Update to groff 1.19.2.
[dragonfly.git] / contrib / groff-1.19 / src / roff / groff / pipeline.c
1 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
2    Free Software Foundation, Inc.
3      Written by James Clark (jjc@jclark.com)
4
5 This file is part of groff.
6
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING.  If not, write to the Free Software
19 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <signal.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
33 #ifdef HAVE_STRERROR
34 #include <string.h>
35 #else
36 extern char *strerror();
37 #endif
38
39 #ifdef _POSIX_VERSION
40
41 #include <sys/wait.h>
42 #define PID_T pid_t
43
44 #else /* not _POSIX_VERSION */
45
46 /* traditional Unix */
47
48 #define WIFEXITED(s) (((s) & 0377) == 0)
49 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
50 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
51 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
52 #define WTERMSIG(s) ((s) & 0177)
53 #define WSTOPSIG(s) (((s) >> 8) & 0377)
54
55 #ifndef WCOREFLAG
56 #define WCOREFLAG 0200
57 #endif
58
59 #define PID_T int
60
61 #endif /* not _POSIX_VERSION */
62
63 /* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */
64 #ifndef WCOREFLAG
65 #ifdef WCOREFLG
66 #define WCOREFLAG WCOREFLG
67 #endif /* WCOREFLG */
68 #endif /* not WCOREFLAG */
69
70 #ifndef WCOREDUMP
71 #ifdef WCOREFLAG
72 #define WCOREDUMP(s) ((s) & WCOREFLAG)
73 #else /* not WCOREFLAG */
74 #define WCOREDUMP(s) (0)
75 #endif /* WCOREFLAG */
76 #endif /* not WCOREDUMP */
77
78 #include "pipeline.h"
79
80 #define error c_error
81
82 #ifdef __cplusplus
83 extern "C" {
84 #endif
85
86 extern void error(const char *, const char *, const char *, const char *);
87 extern void c_fatal(const char *, const char *, const char *, const char *);
88 extern const char *i_to_a(int);         /* from libgroff */
89
90 #ifdef __cplusplus
91 }
92 #endif
93
94 static void sys_fatal(const char *);
95 static const char *xstrsignal(int);
96
97
98 #if defined(__MSDOS__) \
99     || (defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__)) \
100     || defined(__EMX__)
101
102 #include <process.h>
103 #include <fcntl.h>
104 #include <string.h>
105 #include <stdlib.h>
106
107 #include "nonposix.h"
108
109 static const char *sh = "sh";
110 static const char *cmd = "cmd";
111 static const char *command = "command";
112
113 extern int strcasecmp(const char *, const char *);
114
115 char *sbasename(const char *path)
116 {
117   char *base;
118   const char *p1, *p2;
119
120   p1 = path;
121   if ((p2 = strrchr(p1, '\\'))
122       || (p2 = strrchr(p1, '/'))
123       || (p2 = strrchr(p1, ':')))
124     p1 = p2 + 1;
125   if ((p2 = strrchr(p1, '.'))
126       && ((strcasecmp(p2, ".exe") == 0)
127           || (strcasecmp(p2, ".com") == 0)))
128     ;
129   else
130     p2 = p1 + strlen(p1);
131
132   base = malloc((size_t)(p2 - p1));
133   strncpy(base, p1, p2 - p1);
134   *(base + (p2 - p1)) = '\0';
135
136   return(base);
137 }
138
139 /* Get the name of the system shell */
140 char *system_shell_name(void)
141 {
142   const char *shell_name;
143
144   /*
145      Use a Unixy shell if it's installed.  Use SHELL if set; otherwise,
146      let spawnlp try to find sh; if that fails, use COMSPEC if set; if
147      not, try cmd.exe; if that fails, default to command.com.
148    */
149
150   if ((shell_name = getenv("SHELL")) != NULL)
151     ;
152   else if (spawnlp(_P_WAIT, sh, sh, "-c", ":", NULL) == 0)
153     shell_name = sh;
154   else if ((shell_name = getenv("COMSPEC")) != NULL)
155     ;
156   else if (spawnlp(_P_WAIT, cmd, cmd, "/c", ";", NULL) == 0)
157     shell_name = cmd;
158   else
159     shell_name = command;
160
161   return sbasename(shell_name);
162 }
163
164 const char *system_shell_dash_c(void)
165 {
166   char *shell_name;
167   const char *dash_c;
168
169   shell_name = system_shell_name();
170
171   /* Assume that if the shell name ends in "sh", it's Unixy */
172   if (strcasecmp(shell_name + strlen(shell_name) - strlen("sh"), "sh") == 0)
173     dash_c = "-c";
174   else
175     dash_c = "/c";
176
177   free(shell_name);
178   return dash_c;
179 }
180
181 int is_system_shell(const char *prog)
182 {
183   int result;
184   char *this_prog, *system_shell;
185
186   if (!prog)    /* paranoia */
187     return 0;
188
189   this_prog = sbasename(prog);
190   system_shell = system_shell_name();
191
192   result = strcasecmp(this_prog, system_shell) == 0;
193
194   free(this_prog);
195   free(system_shell);
196
197   return result;
198 }
199
200 #ifdef _WIN32
201
202 /*
203   Windows 32 doesn't have fork(), so we need to start asynchronous child
204   processes with spawn() rather than exec().  If there is more than one
205   command, i.e., a pipeline, the parent must set up each child's I/O
206   redirection prior to the spawn.  The original stdout must be restored
207   before spawning the last process in the pipeline, and the original
208   stdin must be restored in the parent after spawning the last process
209   and before waiting for any of the children.
210 */
211
212 int run_pipeline(int ncommands, char ***commands, int no_pipe)
213 {
214   int i;
215   int last_input = 0;   /* pacify some compilers */
216   int save_stdin = 0;
217   int save_stdout = 0;
218   int ret = 0;
219   char err_str[BUFSIZ];
220   PID_T pids[MAX_COMMANDS];
221
222   for (i = 0; i < ncommands; i++) {
223     int pdes[2];
224     PID_T pid;
225
226     /* If no_pipe is set, just run the commands in sequence
227        to show the version numbers */
228     if (ncommands > 1 && !no_pipe) {
229       /* last command doesn't need a new pipe */
230       if (i < ncommands - 1) {
231         if (pipe(pdes) < 0) {
232           sprintf(err_str, "%s: pipe", commands[i][0]);
233           sys_fatal(err_str);
234         }
235       }
236       /* 1st command; writer */
237       if (i == 0) {
238         /* save stdin */
239         if ((save_stdin = dup(STDIN_FILENO)) < 0)
240           sys_fatal("dup stdin");
241         /* save stdout */
242         if ((save_stdout = dup(STDOUT_FILENO)) < 0)
243           sys_fatal("dup stdout");
244
245         /* connect stdout to write end of pipe */
246         if (dup2(pdes[1], STDOUT_FILENO) < 0) {
247           sprintf(err_str, "%s: dup2(stdout)", commands[i][0]);
248           sys_fatal(err_str);
249         }
250         if (close(pdes[1]) < 0) {
251           sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
252           sys_fatal(err_str);
253         }
254         /*
255            Save the read end of the pipe so that it can be connected to
256            stdin of the next program in the pipeline during the next
257            pass through the loop.
258         */
259         last_input = pdes[0];
260       }
261       /* reader and writer */
262       else if (i < ncommands - 1) {
263         /* connect stdin to read end of last pipe */
264         if (dup2(last_input, STDIN_FILENO) < 0) {
265           sprintf(err_str, " %s: dup2(stdin)", commands[i][0]);
266           sys_fatal(err_str);
267         }
268         if (close(last_input) < 0) {
269           sprintf(err_str, "%s: close(last_input)", commands[i][0]);
270           sys_fatal(err_str);
271         }
272         /* connect stdout to write end of new pipe */
273         if (dup2(pdes[1], STDOUT_FILENO) < 0) {
274           sprintf(err_str, "%s: dup2(stdout)", commands[i][0]);
275           sys_fatal(err_str);
276         }
277         if (close(pdes[1]) < 0) {
278           sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
279           sys_fatal(err_str);
280         }
281         last_input = pdes[0];
282       }
283       /* last command; reader */
284       else {
285         /* connect stdin to read end of last pipe */
286         if (dup2(last_input, STDIN_FILENO) < 0) {
287           sprintf(err_str, "%s: dup2(stdin)", commands[i][0]);
288           sys_fatal(err_str);
289         }
290         if (close(last_input) < 0) {
291           sprintf(err_str, "%s: close(last_input)", commands[i][0]);
292           sys_fatal(err_str);
293         }
294         /* restore original stdout */
295         if (dup2(save_stdout, STDOUT_FILENO) < 0) {
296           sprintf(err_str, "%s: dup2(save_stdout))", commands[i][0]);
297           sys_fatal(err_str);
298         }
299         /* close stdout copy */
300         if (close(save_stdout) < 0) {
301           sprintf(err_str, "%s: close(save_stdout)", commands[i][0]);
302           sys_fatal(err_str);
303         }
304       }
305     }
306     if ((pid = spawnvp(_P_NOWAIT, commands[i][0], commands[i])) < 0) {
307       error("couldn't exec %1: %2",
308             commands[i][0], strerror(errno), (char *)0);
309       fflush(stderr);                   /* just in case error() doesn't */
310       _exit(EXEC_FAILED_EXIT_STATUS);
311     }
312     pids[i] = pid;
313   }
314
315   if (ncommands > 1 && !no_pipe) {
316     /* restore original stdin if it was redirected */
317     if (dup2(save_stdin, STDIN_FILENO) < 0) {
318       sprintf(err_str, "dup2(save_stdin))");
319       sys_fatal(err_str);
320     }
321     /* close stdin copy */
322     if (close(save_stdin) < 0) {
323       sprintf(err_str, "close(save_stdin)");
324       sys_fatal(err_str);
325     }
326   }
327
328   for (i = 0; i < ncommands; i++) {
329     int status;
330     PID_T pid;
331
332     pid = pids[i];
333     if ((pid = WAIT(&status, pid, _WAIT_CHILD)) < 0) {
334       sprintf(err_str, "%s: wait", commands[i][0]);
335       sys_fatal(err_str);
336     }
337     else if (status != 0)
338       ret |= 1;
339   }
340   return ret;
341 }
342
343 #else  /* not _WIN32 */
344
345 /* MSDOS doesn't have `fork', so we need to simulate the pipe by running
346    the programs in sequence with standard streams redirected to and
347    from temporary files.
348 */
349
350
351 /* A signal handler that just records that a signal has happened.  */
352 static int child_interrupted;
353
354 static RETSIGTYPE signal_catcher(int signo)
355 {
356   child_interrupted++;
357 }
358
359 int run_pipeline(int ncommands, char ***commands, int no_pipe)
360 {
361   int save_stdin = dup(0);
362   int save_stdout = dup(1);
363   char *tmpfiles[2];
364   int infile  = 0;
365   int outfile = 1;
366   int i, f, ret = 0;
367
368   /* Choose names for a pair of temporary files to implement the pipeline.
369      Microsoft's `tempnam' uses the directory specified by `getenv("TMP")'
370      if it exists; in case it doesn't, try the GROFF alternatives, or
371      `getenv("TEMP")' as last resort -- at least one of these had better
372      be set, since Microsoft's default has a high probability of failure. */
373   char *tmpdir;
374   if ((tmpdir = getenv("GROFF_TMPDIR")) == NULL
375       && (tmpdir = getenv("TMPDIR")) == NULL)
376     tmpdir = getenv("TEMP");
377
378   /* Don't use `tmpnam' here: Microsoft's implementation yields unusable
379      file names if current directory is on network share with read-only
380      root. */
381   tmpfiles[0] = tempnam(tmpdir, NULL);
382   tmpfiles[1] = tempnam(tmpdir, NULL);
383
384   for (i = 0; i < ncommands; i++) {
385     int exit_status;
386     RETSIGTYPE (*prev_handler)(int);
387
388     if (i && !no_pipe) {
389       /* redirect stdin from temp file */
390       f = open(tmpfiles[infile], O_RDONLY|O_BINARY, 0666);
391       if (f < 0)
392         sys_fatal("open stdin");
393       if (dup2(f, 0) < 0)
394         sys_fatal("dup2 stdin"); 
395       if (close(f) < 0)
396         sys_fatal("close stdin");
397     }
398     if ((i < ncommands - 1) && !no_pipe) {
399       /* redirect stdout to temp file */
400       f = open(tmpfiles[outfile], O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
401       if (f < 0)
402         sys_fatal("open stdout");
403       if (dup2(f, 1) < 0)
404         sys_fatal("dup2 stdout");
405       if (close(f) < 0)
406         sys_fatal("close stdout");
407     }
408     else if (dup2(save_stdout, 1) < 0)
409       sys_fatal("restore stdout");
410
411     /* run the program */
412     child_interrupted = 0;
413     prev_handler = signal(SIGINT, signal_catcher);
414     exit_status = spawnvp(P_WAIT, commands[i][0], commands[i]);
415     signal(SIGINT, prev_handler);
416     if (child_interrupted) {
417       error("%1: Interrupted", commands[i][0], (char *)0, (char *)0);
418       ret |= 2;
419     }
420     else if (exit_status < 0) {
421       error("couldn't exec %1: %2",
422             commands[i][0], strerror(errno), (char *)0);
423       fflush(stderr);                   /* just in case error() doesn't */
424       ret |= 4;
425     }
426     if (exit_status != 0)
427       ret |= 1;
428     /* There's no sense to continue with the pipe if one of the
429        programs has ended abnormally, is there? */
430     if (ret != 0)
431       break;
432     /* swap temp files: make output of this program be input for the next */
433     infile = 1 - infile;
434     outfile = 1 - outfile;
435   }
436   if (dup2(save_stdin, 0) < 0)
437     sys_fatal("restore stdin");
438   unlink(tmpfiles[0]);
439   unlink(tmpfiles[1]);
440   return ret;
441 }
442
443 #endif /* not _WIN32 */
444
445 #else /* not __MSDOS__, not _WIN32 */
446
447 int run_pipeline(int ncommands, char ***commands, int no_pipe)
448 {
449   int i;
450   int last_input = 0;
451   PID_T pids[MAX_COMMANDS];
452   int ret = 0;
453   int proc_count = ncommands;
454
455   for (i = 0; i < ncommands; i++) {
456     int pdes[2];
457     PID_T pid;
458
459     if ((i != ncommands - 1) && !no_pipe) {
460       if (pipe(pdes) < 0)
461         sys_fatal("pipe");
462     }
463     pid = fork();
464     if (pid < 0)
465       sys_fatal("fork");
466     if (pid == 0) {
467       /* child */
468       if (last_input != 0) {
469         if (close(0) < 0)
470           sys_fatal("close");
471         if (dup(last_input) < 0)
472           sys_fatal("dup");
473         if (close(last_input) < 0)
474           sys_fatal("close");
475       }
476       if ((i != ncommands - 1) && !no_pipe) {
477         if (close(1) < 0)
478           sys_fatal("close");
479         if (dup(pdes[1]) < 0)
480           sys_fatal("dup");
481         if (close(pdes[1]) < 0)
482           sys_fatal("close");
483         if (close(pdes[0]))
484           sys_fatal("close");
485       }
486       execvp(commands[i][0], commands[i]);
487       error("couldn't exec %1: %2",
488             commands[i][0], strerror(errno), (char *)0);
489       fflush(stderr);                   /* just in case error() doesn't */
490       _exit(EXEC_FAILED_EXIT_STATUS);
491     }
492     /* in the parent */
493     if (last_input != 0) {
494       if (close(last_input) < 0)
495         sys_fatal("close");
496     }
497     if ((i != ncommands - 1) && !no_pipe) {
498       if (close(pdes[1]) < 0)
499         sys_fatal("close");
500       last_input = pdes[0];
501     }
502     pids[i] = pid;
503   }
504   while (proc_count > 0) {
505     int status;
506     PID_T pid = wait(&status);
507
508     if (pid < 0)
509       sys_fatal("wait");
510     for (i = 0; i < ncommands; i++)
511       if (pids[i] == pid) {
512         pids[i] = -1;
513         --proc_count;
514         if (WIFSIGNALED(status)) {
515           int sig = WTERMSIG(status);
516 #ifdef SIGPIPE
517           if (sig == SIGPIPE) {
518             if (i == ncommands - 1) {
519               /* This works around a problem that occurred when using the
520                  rerasterize action in gxditview.  What seemed to be
521                  happening (on SunOS 4.1.1) was that pclose() closed the
522                  pipe and waited for groff, gtroff got a SIGPIPE, but
523                  gpic blocked writing to gtroff, and so groff blocked
524                  waiting for gpic and gxditview blocked waiting for
525                  groff.  I don't understand why gpic wasn't getting a
526                  SIGPIPE. */
527               int j;
528
529               for (j = 0; j < ncommands; j++)
530                 if (pids[j] > 0)
531                   (void)kill(pids[j], SIGPIPE);
532             }
533           }
534           else
535 #endif /* SIGPIPE */
536           {
537             error("%1: %2%3",
538                   commands[i][0],
539                   xstrsignal(sig),
540                   WCOREDUMP(status) ? " (core dumped)" : "");
541             ret |= 2;
542           }
543         }
544         else if (WIFEXITED(status)) {
545           int exit_status = WEXITSTATUS(status);
546
547           if (exit_status == EXEC_FAILED_EXIT_STATUS)
548             ret |= 4;
549           else if (exit_status != 0)
550             ret |= 1;
551         }
552         else
553           error("unexpected status %1", i_to_a(status), (char *)0, (char *)0);
554         break;
555       }
556   }
557   return ret;
558 }
559
560 #endif /* not __MSDOS__, not _WIN32 */
561
562 static void sys_fatal(const char *s)
563 {
564   c_fatal("%1: %2", s, strerror(errno), (char *)0);
565 }
566
567 static const char *xstrsignal(int n)
568 {
569   static char buf[sizeof("Signal ") + 1 + sizeof(int) * 3];
570
571 #ifdef NSIG
572 #if HAVE_DECL_SYS_SIGLIST
573   if (n >= 0 && n < NSIG && sys_siglist[n] != 0)
574     return sys_siglist[n];
575 #endif /* HAVE_DECL_SYS_SIGLIST */
576 #endif /* NSIG */
577   sprintf(buf, "Signal %d", n);
578   return buf;
579 }