xref: /trueos/contrib/groff/src/roff/groff/pipeline.c (revision 513cdf04e173130783343fe42786eef6b8294c6e)
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 
sbasename(const char * path)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 */
system_shell_name(void)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 
system_shell_dash_c(void)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 
is_system_shell(const char * prog)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 
run_pipeline(int ncommands,char *** commands,int no_pipe)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 
signal_catcher(int signo)354 static RETSIGTYPE signal_catcher(int signo)
355 {
356   child_interrupted++;
357 }
358 
run_pipeline(int ncommands,char *** commands,int no_pipe)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 
run_pipeline(int ncommands,char *** commands,int no_pipe)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 
sys_fatal(const char * s)562 static void sys_fatal(const char *s)
563 {
564   c_fatal("%1: %2", s, strerror(errno), (char *)0);
565 }
566 
xstrsignal(int n)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 }
580