diff options
Diffstat (limited to 'gnu/usr.bin/groff/groff/pipeline.c')
| -rw-r--r-- | gnu/usr.bin/groff/groff/pipeline.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/gnu/usr.bin/groff/groff/pipeline.c b/gnu/usr.bin/groff/groff/pipeline.c new file mode 100644 index 000000000000..1cf5875858e7 --- /dev/null +++ b/gnu/usr.bin/groff/groff/pipeline.c @@ -0,0 +1,239 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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 2, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* +Compile options are: + +-DWCOREFLAG=0200 (or whatever) +-DHAVE_VFORK_H +-Dvfork=fork +-DHAVE_SYS_SIGLIST +-DHAVE_UNISTD_H +*/ + +#include <stdio.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_VFORK_H +#include <vfork.h> +#endif + +#ifndef errno +extern int errno; +#endif + +extern char *strerror(); + +#ifdef _POSIX_VERSION + +#include <sys/wait.h> + +#define PID_T pid_t + +#else /* not _POSIX_VERSION */ + +/* traditional Unix */ + +#define WIFEXITED(s) (((s) & 0377) == 0) +#define WIFSTOPPED(s) (((s) & 0377) == 0177) +#define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177)) +#define WEXITSTATUS(s) (((s) >> 8) & 0377) +#define WTERMSIG(s) ((s) & 0177) +#define WSTOPSIG(s) (((s) >> 8) & 0377) + +#ifndef WCOREFLAG +#define WCOREFLAG 0200 +#endif + +#define PID_T int + +#endif /* not _POSIX_VERSION */ + +/* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */ +#ifndef WCOREFLAG +#ifdef WCOREFLG +#define WCOREFLAG WCOREFLG +#endif /* WCOREFLG */ +#endif /* not WCOREFLAG */ + +#ifndef WCOREDUMP +#ifdef WCOREFLAG +#define WCOREDUMP(s) ((s) & WCOREFLAG) +#else /* not WCOREFLAG */ +#define WCOREDUMP(s) (0) +#endif /* WCOREFLAG */ +#endif /* not WCOREDUMP */ + +#include "pipeline.h" + +#ifdef __STDC__ +#define P(parms) parms +#else +#define P(parms) () +#endif + +#define error c_error +extern void error P((char *, char *, char *, char *)); + +static void sys_fatal P((char *)); +static char *strsignal P((int)); +static char *itoa P((int)); + +int run_pipeline(ncommands, commands) + int ncommands; + char ***commands; +{ + int i; + int last_input = 0; + PID_T pids[MAX_COMMANDS]; + int ret = 0; + int proc_count = ncommands; + + for (i = 0; i < ncommands; i++) { + int pdes[2]; + PID_T pid; + if (i != ncommands - 1) { + if (pipe(pdes) < 0) + sys_fatal("pipe"); + } + pid = vfork(); + if (pid < 0) + sys_fatal("fork"); + if (pid == 0) { + /* child */ + if (last_input != 0) { + if (close(0) < 0) + sys_fatal("close"); + if (dup(last_input) < 0) + sys_fatal("dup"); + if (close(last_input) < 0) + sys_fatal("close"); + } + if (i != ncommands - 1) { + if (close(1) < 0) + sys_fatal("close"); + if (dup(pdes[1]) < 0) + sys_fatal("dup"); + if (close(pdes[1]) < 0) + sys_fatal("close"); + if (close(pdes[0])) + sys_fatal("close"); + } + execvp(commands[i][0], commands[i]); + error("couldn't exec %1: %2", commands[i][0], + strerror(errno), (char *)0); + fflush(stderr); /* just in case error() doesn't */ + _exit(EXEC_FAILED_EXIT_STATUS); + } + /* in the parent */ + if (last_input != 0) { + if (close(last_input) < 0) + sys_fatal("close"); + } + if (i != ncommands - 1) { + if (close(pdes[1]) < 0) + sys_fatal("close"); + last_input = pdes[0]; + } + pids[i] = pid; + } + while (proc_count > 0) { + int status; + PID_T pid = wait(&status); + if (pid < 0) + sys_fatal("wait"); + for (i = 0; i < ncommands; i++) + if (pids[i] == pid) { + pids[i] = -1; + --proc_count; + if (WIFSIGNALED(status)) { + int sig = WTERMSIG(status); +#ifdef SIGPIPE + if (sig == SIGPIPE) { + if (i == ncommands - 1) { + + /* This works around a problem that occurred when using the + rerasterize action in gxditview. What seemed to be + happening (on SunOS 4.1.1) was that pclose() closed the + pipe and waited for groff, gtroff got a SIGPIPE, but + gpic blocked writing to gtroff, and so groff blocked + waiting for gpic and gxditview blocked waiting for + groff. I don't understand why gpic wasn't getting a + SIGPIPE. */ + int j; + for (j = 0; j < ncommands; j++) + if (pids[j] > 0) + (void)kill(pids[j], SIGPIPE); + } + } + else +#endif /* SIGPIPE */ + { + error("%1: %2%3", + commands[i][0], + strsignal(sig), + WCOREDUMP(status) ? " (core dumped)" : ""); + ret |= 2; + } + } + else if (WIFEXITED(status)) { + int exit_status = WEXITSTATUS(status); + if (exit_status == EXEC_FAILED_EXIT_STATUS) + ret |= 4; + else if (exit_status != 0) + ret |= 1; + } + else + error("unexpected status %1", + itoa(status), (char *)0, (char *)0); + break; + } + } + return ret; +} + +static void sys_fatal(s) + char *s; +{ + c_fatal("%1: %2", s, strerror(errno), (char *)0); +} + +static char *itoa(n) + int n; +{ + static char buf[12]; + sprintf(buf, "%d", n); + return buf; +} + +static char *strsignal(n) + int n; +{ + static char buf[sizeof("Signal ") + 1 + sizeof(int)*3]; +#ifdef HAVE_SYS_SIGLIST + if (n >= 0 && n < NSIG && sys_siglist[n] != 0) + return sys_siglist[n]; +#endif /* HAVE_SYS_SIGLIST */ + sprintf(buf, "Signal %d", n); + return buf; +} |
