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