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 
sbasename(const char * path)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 */
system_shell_name(void)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 
system_shell_dash_c(void)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 
is_system_shell(const char * prog)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 
run_pipeline(int ncommands,char *** commands,int no_pipe)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 
signal_catcher(int signo)355 static RETSIGTYPE signal_catcher(int signo)
356 {
357   child_interrupted++;
358 }
359 
run_pipeline(int ncommands,char *** commands,int no_pipe)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 
run_pipeline(int ncommands,char *** commands,int no_pipe)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 
sys_fatal(const char * s)563 static void sys_fatal(const char *s)
564 {
565   c_fatal("%1: %2", s, strerror(errno), (char *)0);
566 }
567 
xstrsignal(int n)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 }
581