home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / groff / pipeline.c < prev    next >
C/C++ Source or Header  |  1995-06-22  |  6KB  |  240 lines

  1. /* Copyright (C) 1989, 1990, 1991, 1992 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 2, or (at your option) any later
  9. 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 along
  17. with groff; see the file COPYING.  If not, write to the Free Software
  18. Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  19.  
  20. /*
  21. Compile options are:
  22.  
  23. -DWCOREFLAG=0200 (or whatever)
  24. -DHAVE_SYS_SIGLIST
  25. -DSYS_SIGLIST_DECLARED
  26. -DHAVE_UNISTD_H
  27. */
  28.  
  29. #include <stdio.h>
  30. #include <signal.h>
  31. #include <errno.h>
  32. #include <sys/types.h>
  33. #ifdef HAVE_UNISTD_H
  34. #include <unistd.h>
  35. #endif
  36.  
  37. #ifndef errno
  38. extern int errno;
  39. #endif
  40.  
  41. extern char *strerror();
  42.  
  43. #ifdef _POSIX_VERSION
  44.  
  45. #include <sys/wait.h>
  46.  
  47. #define PID_T pid_t
  48.  
  49. #else /* not _POSIX_VERSION */
  50.  
  51. /* traditional Unix */
  52.  
  53. #define WIFEXITED(s) (((s) & 0377) == 0)
  54. #define WIFSTOPPED(s) (((s) & 0377) == 0177)
  55. #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
  56. #define WEXITSTATUS(s) (((s) >> 8) & 0377)
  57. #define WTERMSIG(s) ((s) & 0177)
  58. #define WSTOPSIG(s) (((s) >> 8) & 0377)
  59.  
  60. #ifndef WCOREFLAG
  61. #define WCOREFLAG 0200
  62. #endif
  63.  
  64. #define PID_T int
  65.  
  66. #endif /* not _POSIX_VERSION */
  67.  
  68. /* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */
  69. #ifndef WCOREFLAG
  70. #ifdef WCOREFLG
  71. #define WCOREFLAG WCOREFLG
  72. #endif /* WCOREFLG */
  73. #endif /* not WCOREFLAG */
  74.  
  75. #ifndef WCOREDUMP
  76. #ifdef WCOREFLAG
  77. #define WCOREDUMP(s) ((s) & WCOREFLAG)
  78. #else /* not WCOREFLAG */
  79. #define WCOREDUMP(s) (0)
  80. #endif /* WCOREFLAG */
  81. #endif /* not WCOREDUMP */
  82.  
  83. #include "pipeline.h"
  84.  
  85. #ifdef __STDC__
  86. #define P(parms) parms
  87. #else
  88. #define P(parms) ()
  89. #define const /* as nothing */
  90. #endif
  91.  
  92. #define error c_error
  93. extern void error P((const char *, const char *, const char *, const char *));
  94. extern void c_fatal P((const char *, const char *, const char *, const char *));
  95.  
  96. static void sys_fatal P((const char *));
  97. static const char *xstrsignal P((int));
  98. static char *itoa P((int));
  99.  
  100. int run_pipeline(ncommands, commands)
  101.      int ncommands;
  102.      char ***commands;
  103. {
  104.   int i;
  105.   int last_input = 0;
  106.   PID_T pids[MAX_COMMANDS];
  107.   int ret = 0;
  108.   int proc_count = ncommands;
  109.  
  110.   for (i = 0; i < ncommands; i++) {
  111.       int pdes[2];
  112.       PID_T pid;
  113.       if (i != ncommands - 1) {
  114.     if (pipe(pdes) < 0)
  115.       sys_fatal("pipe");
  116.       }
  117.       pid = fork();
  118.       if (pid < 0)
  119.     sys_fatal("fork");
  120.       if (pid == 0) {
  121.     /* child */
  122.     if (last_input != 0) {
  123.       if (close(0) < 0)
  124.         sys_fatal("close");
  125.       if (dup(last_input) < 0)
  126.         sys_fatal("dup");
  127.       if (close(last_input) < 0)
  128.         sys_fatal("close");
  129.     }
  130.     if (i != ncommands - 1) {
  131.       if (close(1) < 0)
  132.         sys_fatal("close");
  133.       if (dup(pdes[1]) < 0)
  134.         sys_fatal("dup");
  135.       if (close(pdes[1]) < 0)
  136.         sys_fatal("close");
  137.       if (close(pdes[0]))
  138.         sys_fatal("close");
  139.     }
  140.     execvp(commands[i][0], commands[i]);
  141.     error("couldn't exec %1: %2", commands[i][0],
  142.           strerror(errno), (char *)0);
  143.     fflush(stderr);        /* just in case error() doesn't */
  144.     _exit(EXEC_FAILED_EXIT_STATUS);
  145.       }
  146.       /* in the parent */
  147.       if (last_input != 0) {
  148.     if (close(last_input) < 0)
  149.       sys_fatal("close");
  150.       }
  151.       if (i != ncommands - 1) {
  152.     if (close(pdes[1]) < 0)
  153.       sys_fatal("close");
  154.     last_input = pdes[0];
  155.       }
  156.       pids[i] = pid;
  157.     }
  158.   while (proc_count > 0) {
  159.     int status;
  160.     PID_T pid = wait(&status);
  161.     if (pid < 0)
  162.       sys_fatal("wait");
  163.     for (i = 0; i < ncommands; i++)
  164.       if (pids[i] == pid) {
  165.     pids[i] = -1;
  166.     --proc_count;
  167.     if (WIFSIGNALED(status)) {
  168.       int sig = WTERMSIG(status);
  169. #ifdef SIGPIPE
  170.       if (sig == SIGPIPE) {
  171.         if (i == ncommands - 1) {
  172.  
  173.           /* This works around a problem that occurred when using the
  174.          rerasterize action in gxditview.  What seemed to be
  175.          happening (on SunOS 4.1.1) was that pclose() closed the
  176.          pipe and waited for groff, gtroff got a SIGPIPE, but
  177.          gpic blocked writing to gtroff, and so groff blocked
  178.          waiting for gpic and gxditview blocked waiting for
  179.          groff.  I don't understand why gpic wasn't getting a
  180.          SIGPIPE. */
  181.           int j;
  182.           for (j = 0; j < ncommands; j++)
  183.         if (pids[j] > 0)
  184.           (void)kill(pids[j], SIGPIPE);
  185.         }
  186.       }
  187.       else
  188. #endif /* SIGPIPE */
  189.       {
  190.         error("%1: %2%3",
  191.           commands[i][0],
  192.           xstrsignal(sig),
  193.           WCOREDUMP(status) ? " (core dumped)" : "");
  194.         ret |= 2;
  195.       }
  196.     }
  197.     else if (WIFEXITED(status)) {
  198.       int exit_status = WEXITSTATUS(status);
  199.       if (exit_status == EXEC_FAILED_EXIT_STATUS)
  200.         ret |= 4;
  201.       else if (exit_status != 0)
  202.         ret |= 1;
  203.     }
  204.     else
  205.       error("unexpected status %1",
  206.         itoa(status), (char *)0, (char *)0);
  207.     break;
  208.       }
  209.   }
  210.   return ret;
  211. }
  212.  
  213. static void sys_fatal(s)
  214.      const char *s;
  215. {
  216.   c_fatal("%1: %2", s, strerror(errno), (char *)0);
  217. }
  218.  
  219. static char *itoa(n)
  220.      int n;
  221. {
  222.   static char buf[12];
  223.   sprintf(buf, "%d", n);
  224.   return buf;
  225. }
  226.  
  227. static const char *xstrsignal(n)
  228.      int n;
  229. {
  230.   static char buf[sizeof("Signal ") + 1 + sizeof(int)*3];
  231. #ifdef NSIG
  232. #ifdef SYS_SIGLIST_DECLARED
  233.   if (n >= 0 && n < NSIG && sys_siglist[n] != 0)
  234.     return sys_siglist[n];
  235. #endif /* SYS_SIGLIST_DECLARED */
  236. #endif /* NSIG */
  237.   sprintf(buf, "Signal %d", n);
  238.   return buf;
  239. }
  240.