mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 04:13:03 +00:00
See http://www.gnu.org/prep/maintain/maintain.html#Copyright-Notices * HACKING, Makefile.am, NEWS, PACKAGING, README, README-alpha: * TODO, bootstrap, bootstrap.conf: * build-aux/update-b4-copyright, cfg.mk, configure.ac: * data/README, data/bison.m4, data/c++-skel.m4, data/c++.m4: * data/c-skel.m4, data/c.m4, data/glr.c, data/glr.cc: * data/java-skel.m4, data/java.m4, data/lalr1.cc: * data/lalr1.java, data/local.mk, data/location.cc: * data/stack.hh, data/variant.hh, data/xslt/bison.xsl: * data/xslt/xml2dot.xsl, data/xslt/xml2text.xsl: * data/xslt/xml2xhtml.xsl, data/yacc.c, djgpp/Makefile.maint: * djgpp/README.in, djgpp/config.bat, djgpp/config.sed: * djgpp/config.site, djgpp/config_h.sed, djgpp/djunpack.bat: * djgpp/local.mk, djgpp/subpipe.c, djgpp/subpipe.h: * djgpp/testsuite.sed, doc/bison.texinfo, doc/local.mk: * doc/refcard.tex, etc/README, etc/bench.pl.in, etc/local.mk: * examples/calc++/Makefile.am, examples/extexi: * examples/local.mk, lib/abitset.c, lib/abitset.h: * lib/bbitset.h, lib/bitset.c, lib/bitset.h: * lib/bitset_stats.c, lib/bitset_stats.h, lib/bitsetv-print.c: * lib/bitsetv-print.h, lib/bitsetv.c, lib/bitsetv.h: * lib/ebitset.c, lib/ebitset.h, lib/get-errno.c: * lib/get-errno.h, lib/lbitset.c, lib/lbitset.h: * lib/libiberty.h, lib/local.mk, lib/main.c, lib/timevar.c: * lib/timevar.def, lib/timevar.h, lib/vbitset.c: * lib/vbitset.h, lib/yyerror.c, m4/bison-i18n.m4: * m4/c-working.m4, m4/cxx.m4, m4/subpipe.m4, m4/timevar.m4: * src/AnnotationList.c, src/AnnotationList.h: * src/InadequacyList.c, src/InadequacyList.h, src/LR0.c: * src/LR0.h, src/Sbitset.c, src/Sbitset.h, src/assoc.c: * src/assoc.h, src/closure.c, src/closure.h, src/complain.c: * src/complain.h, src/conflicts.c, src/conflicts.h: * src/derives.c, src/derives.h, src/files.c, src/files.h: * src/flex-scanner.h, src/getargs.c, src/getargs.h: * src/gram.c, src/gram.h, src/graphviz.c, src/ielr.c: * src/ielr.h, src/lalr.c, src/lalr.h, src/local.mk: * src/location.c, src/location.h, src/main.c: * src/muscle-tab.c, src/muscle-tab.h, src/named-ref.c: * src/named-ref.h, src/nullable.c, src/nullable.h: * src/output.c, src/output.h, src/parse-gram.y: * src/print-xml.c, src/print-xml.h, src/print.c, src/print.h: * src/print_graph.c, src/print_graph.h, src/reader.c: * src/reader.h, src/reduce.c, src/reduce.h, src/relation.c: * src/relation.h, src/scan-code.h, src/scan-code.l: * src/scan-gram.h, src/scan-gram.l, src/scan-skel.h: * src/scan-skel.l, src/state.c, src/state.h, src/symlist.c: * src/symlist.h, src/symtab.c, src/symtab.h, src/system.h: * src/tables.c, src/tables.h, src/uniqstr.c, src/uniqstr.h: * tests/actions.at, tests/atlocal.in, tests/c++.at: * tests/calc.at, tests/conflicts.at, tests/cxx-type.at: * tests/existing.at, tests/glr-regression.at: * tests/headers.at, tests/input.at, tests/java.at: * tests/local.at, tests/local.mk, tests/named-refs.at: * tests/output.at, tests/push.at, tests/reduce.at: * tests/regression.at, tests/sets.at, tests/skeletons.at: * tests/synclines.at, tests/testsuite.at, tests/torture.at: Don't use date ranges in copyright notices. Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
295 lines
7.9 KiB
C
295 lines
7.9 KiB
C
/* Subprocesses with pipes.
|
|
|
|
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
|
|
Foundation, Inc.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
/* Written by Juan Manuel Guerrero <juan.guerrero@gmx.de>. */
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include "subpipe.h"
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <process.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "xalloc.h"
|
|
|
|
|
|
#ifndef STDIN_FILENO
|
|
# define STDIN_FILENO 0
|
|
#endif
|
|
#ifndef STDOUT_FILENO
|
|
# define STDOUT_FILENO 1
|
|
#endif
|
|
|
|
|
|
#include "error.h"
|
|
|
|
#include "gettext.h"
|
|
#define _(Msgid) gettext (Msgid)
|
|
|
|
|
|
/* Initialize this module. */
|
|
|
|
|
|
static int old_stdin;
|
|
static int old_stdout;
|
|
static char **arguments;
|
|
static char tmp_file_name[2][L_tmpnam];
|
|
|
|
#define remove_tmp_file(fd, name) \
|
|
do { \
|
|
close ((fd)); \
|
|
if (unlink ((name))) \
|
|
error (EXIT_FAILURE, 0, _("removing of `%s' failed"), (name)); \
|
|
} while (0)
|
|
|
|
|
|
void
|
|
init_subpipe(void)
|
|
{
|
|
char *tmpdir;
|
|
int fd;
|
|
|
|
tmpdir = getenv("TMPDIR");
|
|
if (tmpdir == NULL)
|
|
tmpdir = getenv("TMP");
|
|
if (tmpdir == NULL)
|
|
tmpdir = getenv("TEMP");
|
|
if (access(tmpdir, D_OK))
|
|
tmpdir = ".";
|
|
|
|
strcpy(tmp_file_name[0], tmpdir);
|
|
strcat(tmp_file_name[0], "/bnXXXXXX");
|
|
fd = mkstemp(tmp_file_name[0]);
|
|
if (fd < 0)
|
|
error(EXIT_FAILURE, 0, _("creation of a temporary file failed"));
|
|
close (fd);
|
|
|
|
strcpy(tmp_file_name[1], tmpdir);
|
|
strcat(tmp_file_name[1], "/bnXXXXXX");
|
|
fd = mkstemp(tmp_file_name[1]);
|
|
if (fd < 0)
|
|
error(EXIT_FAILURE, 0, _("creation of a temporary file failed"));
|
|
close (fd);
|
|
}
|
|
|
|
|
|
/* Create a subprocess that is run as a filter. ARGV is the
|
|
NULL-terminated argument vector for the subprocess. Store read and
|
|
write file descriptors for communication with the subprocess into
|
|
FD[0] and FD[1]: input meant for the process can be written into
|
|
FD[0], and output from the process can be read from FD[1]. Return
|
|
the subprocess id.
|
|
|
|
Because DOS has neither fork nor pipe functionality to run the subprocess
|
|
as a filter, the filter is reproduced using temporary files. First bison's
|
|
stdout is redirected to a temporary file. After bison has produced all of
|
|
is output, this file is closed and connected to m4's stdin. All m4's output
|
|
is redirected from m4's stdout to a second temporary file and reopened as
|
|
bison's stdin. */
|
|
|
|
pid_t
|
|
create_subpipe(char const *const *argv, int fd[2])
|
|
{
|
|
int argc;
|
|
int from_in_fd; /* pipe from bison to m4. */
|
|
pid_t pid;
|
|
|
|
|
|
pid = getpid();
|
|
|
|
/*
|
|
* Save original stdin and stdout
|
|
* for later restauration.
|
|
*/
|
|
old_stdin = dup(STDIN_FILENO);
|
|
if (old_stdin < 0)
|
|
error(EXIT_FAILURE, 0, _("saving stdin failed"));
|
|
|
|
old_stdout = dup(STDOUT_FILENO);
|
|
if (old_stdout < 0)
|
|
error(EXIT_FAILURE, 0, _("saving stdout failed"));
|
|
|
|
/*
|
|
* Save argv for later use.
|
|
*/
|
|
for (argc = 0; argv[argc]; argc++)
|
|
;
|
|
argc++;
|
|
arguments = xmalloc(argc * sizeof(arguments[0]));
|
|
for (argc = 0; argv[argc]; argc++)
|
|
{
|
|
arguments[argc] = xmalloc((strlen(argv[argc]) + 1) * sizeof(arguments[0][0]));
|
|
strcpy(arguments[argc], argv[argc]);
|
|
}
|
|
arguments[argc] = NULL;
|
|
|
|
/*
|
|
* All bison's output will be gathered in this temporary file
|
|
* and will be redirected to m4's stdin.
|
|
*/
|
|
from_in_fd = open(tmp_file_name[0], O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR);
|
|
if (from_in_fd < 0)
|
|
error(EXIT_FAILURE, 0, _("opening of tmpfile failed"));
|
|
if (dup2(from_in_fd, STDOUT_FILENO) < 0)
|
|
{
|
|
remove_tmp_file(from_in_fd, tmp_file_name[0]);
|
|
error(EXIT_FAILURE, 0, _("redirecting bison's stdout to the temporary file failed"));
|
|
}
|
|
close(from_in_fd);
|
|
|
|
|
|
fd[0] = STDOUT_FILENO;
|
|
return pid;
|
|
}
|
|
|
|
|
|
/* A signal handler that just records that a signal has happened. */
|
|
static int child_interrupted;
|
|
|
|
static void
|
|
signal_catcher(int signo)
|
|
{
|
|
child_interrupted++;
|
|
}
|
|
|
|
|
|
void
|
|
end_of_output_subpipe(pid_t pid, int fd[2])
|
|
{
|
|
char *program;
|
|
int from_out_fd = open(tmp_file_name[0], O_RDONLY, S_IRUSR); /* pipe from bison to m4. */
|
|
int to_in_fd = open(tmp_file_name[1], O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR); /* pipe from m4 to bison. */
|
|
int status;
|
|
void (*previous_handler)(int);
|
|
|
|
|
|
program = strrchr(arguments[0], '/');
|
|
if (program)
|
|
program++;
|
|
else
|
|
program = arguments[0];
|
|
|
|
/*
|
|
* Redirect bison's output to m4's stdin.
|
|
*/
|
|
if (from_out_fd < 0)
|
|
error(EXIT_FAILURE, 0, _("opening of tmpfile failed"));
|
|
if (dup2(from_out_fd, STDIN_FILENO) < 0)
|
|
{
|
|
remove_tmp_file(from_out_fd, tmp_file_name[0]);
|
|
error(EXIT_FAILURE, 0, _("redirecting m4's stdin from the temporary file failed"));
|
|
}
|
|
close(from_out_fd);
|
|
|
|
/*
|
|
* All m4's output will be gathered in this temporary file
|
|
* and will be redirected to bison's stdin.
|
|
*/
|
|
if (to_in_fd < 0)
|
|
{
|
|
remove_tmp_file(STDIN_FILENO, tmp_file_name[0]);
|
|
error(EXIT_FAILURE, 0, _("opening of a temporary file failed"));
|
|
}
|
|
if (dup2(to_in_fd, STDOUT_FILENO) < 0)
|
|
{
|
|
remove_tmp_file(STDIN_FILENO, tmp_file_name[0]);
|
|
remove_tmp_file(to_in_fd, tmp_file_name[1]);
|
|
error(EXIT_FAILURE, 0, _("redirecting m4's stdout to a temporary file failed"));
|
|
}
|
|
close(to_in_fd);
|
|
|
|
/*
|
|
* Run m4.
|
|
*/
|
|
child_interrupted = 0;
|
|
errno = 0;
|
|
previous_handler = signal(SIGINT, signal_catcher);
|
|
status = spawnvp(P_WAIT, program, arguments);
|
|
signal(SIGINT, previous_handler);
|
|
if (child_interrupted)
|
|
{
|
|
remove_tmp_file(STDIN_FILENO, tmp_file_name[0]);
|
|
remove_tmp_file(STDOUT_FILENO, tmp_file_name[1]);
|
|
error(EXIT_FAILURE, 0, _("subsidiary program `%s' interrupted"), program);
|
|
}
|
|
if (status)
|
|
{
|
|
remove_tmp_file(STDIN_FILENO, tmp_file_name[0]);
|
|
remove_tmp_file(STDOUT_FILENO, tmp_file_name[1]);
|
|
error(EXIT_FAILURE, 0, _(errno == ENOENT
|
|
? "subsidiary program `%s' not found"
|
|
: status < 1
|
|
? "subsidiary program `%s' failed"
|
|
: "subsidiary program `%s' failed (status=%i, errno=%i)"), program, status, errno);
|
|
}
|
|
|
|
|
|
/*
|
|
* Redirect m4's output to bison's stdin.
|
|
*/
|
|
if (dup2(old_stdout, STDOUT_FILENO) < 0)
|
|
error(EXIT_FAILURE, 0, "restore of bison's stdout failed");
|
|
close(old_stdout);
|
|
to_in_fd = open(tmp_file_name[1], O_RDONLY, S_IRUSR); /* pipe from m4 to bison. */
|
|
if (to_in_fd < 0)
|
|
{
|
|
remove_tmp_file(STDIN_FILENO, tmp_file_name[0]);
|
|
error(EXIT_FAILURE, 0, _("opening of tmpfile failed"));
|
|
}
|
|
if (dup2(to_in_fd, STDIN_FILENO) < 0)
|
|
{
|
|
remove_tmp_file(STDIN_FILENO, tmp_file_name[0]);
|
|
remove_tmp_file(to_in_fd, tmp_file_name[1]);
|
|
error(EXIT_FAILURE, -1, "dup2");
|
|
error(EXIT_FAILURE, 0, _("redirecting bison's stdin from the temporary file failed"));
|
|
}
|
|
close(to_in_fd);
|
|
|
|
|
|
fd[1] = STDIN_FILENO;
|
|
}
|
|
|
|
|
|
/* Free resources, unlink temporary files and restore stdin and stdout. */
|
|
|
|
void
|
|
reap_subpipe(pid_t pid, char const *program)
|
|
{
|
|
int argc;
|
|
|
|
for (argc = 0; arguments[argc]; argc++)
|
|
free(arguments[argc]);
|
|
free(arguments);
|
|
|
|
if (unlink(tmp_file_name[0]))
|
|
error(EXIT_FAILURE, 0, _("removing of `%s' failed"), tmp_file_name[0]);
|
|
if (unlink(tmp_file_name[1]))
|
|
error(EXIT_FAILURE, 0, _("removing of `%s' failed"), tmp_file_name[1]);
|
|
|
|
if (dup2(old_stdin, STDIN_FILENO) < 0)
|
|
error(EXIT_FAILURE, 0, "restore of bison's stdin failed");
|
|
close(old_stdin);
|
|
}
|