groff before CVS: release 1.06
[s-roff.git] / groff / pipeline.c
blob0172a1745a85b6996f3f6e2b5539aa2ce6dee1dc
1 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
2 Written by James Clark (jjc@jclark.com)
4 This file is part of groff.
6 groff is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
11 groff is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
16 You should have received a copy of the GNU General Public License along
17 with groff; see the file COPYING. If not, write to the Free Software
18 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 Compile options are:
23 -DWCOREFLAG=0200 (or whatever)
24 -DHAVE_VFORK_H
25 -Dvfork=fork
26 -DHAVE_SYS_SIGLIST
27 -DHAVE_UNISTD_H
30 #include <stdio.h>
31 #include <signal.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #ifdef HAVE_VFORK_H
38 #include <vfork.h>
39 #endif
41 #ifndef errno
42 extern int errno;
43 #endif
45 extern char *strerror();
47 #ifdef _POSIX_VERSION
49 #include <sys/wait.h>
51 #define PID_T pid_t
53 #else /* not _POSIX_VERSION */
55 /* traditional Unix */
57 #define WIFEXITED(s) (((s) & 0377) == 0)
58 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
59 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
60 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
61 #define WTERMSIG(s) ((s) & 0177)
62 #define WSTOPSIG(s) (((s) >> 8) & 0377)
64 #ifndef WCOREFLAG
65 #define WCOREFLAG 0200
66 #endif
68 #define PID_T int
70 #endif /* not _POSIX_VERSION */
72 /* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */
73 #ifndef WCOREFLAG
74 #ifdef WCOREFLG
75 #define WCOREFLAG WCOREFLG
76 #endif /* WCOREFLG */
77 #endif /* not WCOREFLAG */
79 #ifndef WCOREDUMP
80 #ifdef WCOREFLAG
81 #define WCOREDUMP(s) ((s) & WCOREFLAG)
82 #else /* not WCOREFLAG */
83 #define WCOREDUMP(s) (0)
84 #endif /* WCOREFLAG */
85 #endif /* not WCOREDUMP */
87 #include "pipeline.h"
89 #ifdef __STDC__
90 #define P(parms) parms
91 #else
92 #define P(parms) ()
93 #endif
95 #define error c_error
96 extern void error P((char *, char *, char *, char *));
98 static void sys_fatal P((char *));
99 static char *strsignal P((int));
100 static char *itoa P((int));
102 int run_pipeline(ncommands, commands)
103 int ncommands;
104 char ***commands;
106 int i;
107 int last_input = 0;
108 PID_T pids[MAX_COMMANDS];
109 int ret = 0;
110 int proc_count = ncommands;
112 for (i = 0; i < ncommands; i++) {
113 int pdes[2];
114 PID_T pid;
115 if (i != ncommands - 1) {
116 if (pipe(pdes) < 0)
117 sys_fatal("pipe");
119 pid = vfork();
120 if (pid < 0)
121 sys_fatal("fork");
122 if (pid == 0) {
123 /* child */
124 if (last_input != 0) {
125 if (close(0) < 0)
126 sys_fatal("close");
127 if (dup(last_input) < 0)
128 sys_fatal("dup");
129 if (close(last_input) < 0)
130 sys_fatal("close");
132 if (i != ncommands - 1) {
133 if (close(1) < 0)
134 sys_fatal("close");
135 if (dup(pdes[1]) < 0)
136 sys_fatal("dup");
137 if (close(pdes[1]) < 0)
138 sys_fatal("close");
139 if (close(pdes[0]))
140 sys_fatal("close");
142 execvp(commands[i][0], commands[i]);
143 error("couldn't exec %1: %2", commands[i][0],
144 strerror(errno), (char *)0);
145 fflush(stderr); /* just in case error() doesn't */
146 _exit(EXEC_FAILED_EXIT_STATUS);
148 /* in the parent */
149 if (last_input != 0) {
150 if (close(last_input) < 0)
151 sys_fatal("close");
153 if (i != ncommands - 1) {
154 if (close(pdes[1]) < 0)
155 sys_fatal("close");
156 last_input = pdes[0];
158 pids[i] = pid;
160 while (proc_count > 0) {
161 int status;
162 PID_T pid = wait(&status);
163 if (pid < 0)
164 sys_fatal("wait");
165 for (i = 0; i < ncommands; i++)
166 if (pids[i] == pid) {
167 pids[i] = -1;
168 --proc_count;
169 if (WIFSIGNALED(status)) {
170 int sig = WTERMSIG(status);
171 #ifdef SIGPIPE
172 if (sig == SIGPIPE) {
173 if (i == ncommands - 1) {
175 /* This works around a problem that occurred when using the
176 rerasterize action in gxditview. What seemed to be
177 happening (on SunOS 4.1.1) was that pclose() closed the
178 pipe and waited for groff, gtroff got a SIGPIPE, but
179 gpic blocked writing to gtroff, and so groff blocked
180 waiting for gpic and gxditview blocked waiting for
181 groff. I don't understand why gpic wasn't getting a
182 SIGPIPE. */
183 int j;
184 for (j = 0; j < ncommands; j++)
185 if (pids[j] > 0)
186 (void)kill(pids[j], SIGPIPE);
189 else
190 #endif /* SIGPIPE */
192 error("%1: %2%3",
193 commands[i][0],
194 strsignal(sig),
195 WCOREDUMP(status) ? " (core dumped)" : "");
196 ret |= 2;
199 else if (WIFEXITED(status)) {
200 int exit_status = WEXITSTATUS(status);
201 if (exit_status == EXEC_FAILED_EXIT_STATUS)
202 ret |= 4;
203 else if (exit_status != 0)
204 ret |= 1;
206 else
207 error("unexpected status %1",
208 itoa(status), (char *)0, (char *)0);
209 break;
212 return ret;
215 static void sys_fatal(s)
216 char *s;
218 c_fatal("%1: %2", s, strerror(errno), (char *)0);
221 static char *itoa(n)
222 int n;
224 static char buf[12];
225 sprintf(buf, "%d", n);
226 return buf;
229 static char *strsignal(n)
230 int n;
232 static char buf[sizeof("Signal ") + 1 + sizeof(int)*3];
233 #ifdef HAVE_SYS_SIGLIST
234 extern char *sys_siglist[];
235 if (n >= 0 && n < NSIG && sys_siglist[n] != 0)
236 return sys_siglist[n];
237 #endif /* HAVE_SYS_SIGLIST */
238 sprintf(buf, "Signal %d", n);
239 return buf;