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