Home | History | Annotate | Download | only in lib
      1 /* Subprocesses with pipes.
      2 
      3    Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
      4 
      5    This program is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by
      7    the Free Software Foundation; either version 2, or (at your option)
      8    any later version.
      9 
     10    This program is distributed in the hope that it will be useful,
     11    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU General Public License for more details.
     14 
     15    You should have received a copy of the GNU General Public License
     16    along with this program; if not, write to the Free Software Foundation,
     17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
     18 
     19 /* Written by Paul Eggert <eggert (at) twinsun.com>
     20    and Florian Krohm <florian (at) edamail.fishkill.ibm.com>.  */
     21 
     22 #ifdef HAVE_CONFIG_H
     23 # include <config.h>
     24 #endif
     25 
     26 #include "subpipe.h"
     27 
     28 #include <errno.h>
     29 
     30 #include <signal.h>
     31 #if ! defined SIGCHLD && defined SIGCLD
     32 # define SIGCHLD SIGCLD
     33 #endif
     34 
     35 #include <stdlib.h>
     36 
     37 #if HAVE_UNISTD_H
     38 # include <unistd.h>
     39 #endif
     40 #ifndef STDIN_FILENO
     41 # define STDIN_FILENO 0
     42 #endif
     43 #ifndef STDOUT_FILENO
     44 # define STDOUT_FILENO 1
     45 #endif
     46 #if ! HAVE_DUP2 && ! defined dup2
     47 # include <fcntl.h>
     48 # define dup2(f, t) (close (t), fcntl (f, F_DUPFD, t))
     49 #endif
     50 
     51 #if HAVE_SYS_WAIT_H
     52 # include <sys/wait.h>
     53 #endif
     54 #ifndef WEXITSTATUS
     55 # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
     56 #endif
     57 #ifndef WIFEXITED
     58 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
     59 #endif
     60 
     61 #if HAVE_VFORK_H
     62 # include <vfork.h>
     63 #endif
     64 #if ! HAVE_WORKING_VFORK
     65 # define vfork fork
     66 #endif
     67 
     68 #include "error.h"
     69 #include "unistd-safer.h"
     70 
     71 #include "gettext.h"
     72 #define _(Msgid)  gettext (Msgid)
     73 
     74 #ifndef __attribute__
     75 /* This feature is available in gcc versions 2.5 and later.  */
     76 # if ! defined __GNUC__ || __GNUC__ < 2 || \
     77 (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
     78 #  define __attribute__(Spec) /* empty */
     79 # endif
     80 #endif
     81 
     82 #ifndef ATTRIBUTE_UNUSED
     83 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
     84 #endif
     85 
     86 
     87 /* Initialize this module.  */
     88 
     89 void
     90 init_subpipe (void)
     91 {
     92 #ifdef SIGCHLD
     93   /* System V fork+wait does not work if SIGCHLD is ignored.  */
     94   signal (SIGCHLD, SIG_DFL);
     95 #endif
     96 }
     97 
     98 
     99 /* Create a subprocess that is run as a filter.  ARGV is the
    100    NULL-terminated argument vector for the subprocess.  Store read and
    101    write file descriptors for communication with the subprocess into
    102    FD[0] and FD[1]: input meant for the process can be written into
    103    FD[0], and output from the process can be read from FD[1].  Return
    104    the subprocess id.
    105 
    106    To avoid deadlock, the invoker must not let incoming data pile up
    107    in FD[1] while writing data to FD[0].  */
    108 
    109 pid_t
    110 create_subpipe (char const * const *argv, int fd[2])
    111 {
    112   int pipe_fd[2];
    113   int child_fd[2];
    114   pid_t pid;
    115 
    116   if (pipe (child_fd) != 0
    117       || (child_fd[0] = fd_safer (child_fd[0])) < 0
    118       || (fd[0] = fd_safer (child_fd[1])) < 0
    119       || pipe (pipe_fd) != 0
    120       || (fd[1] = fd_safer (pipe_fd[0])) < 0
    121       || (child_fd[1] = fd_safer (pipe_fd[1])) < 0)
    122     error (EXIT_FAILURE, errno,
    123 	   "pipe");
    124 
    125   pid = vfork ();
    126   if (pid < 0)
    127     error (EXIT_FAILURE, errno,
    128 	   "fork");
    129 
    130   if (! pid)
    131     {
    132       /* Child.  */
    133       close (fd[0]);
    134       close (fd[1]);
    135       dup2 (child_fd[0], STDIN_FILENO);
    136       close (child_fd[0]);
    137       dup2 (child_fd[1], STDOUT_FILENO);
    138       close (child_fd[1]);
    139 
    140       /* The cast to (char **) rather than (char * const *) is needed
    141 	 for portability to older hosts with a nonstandard prototype
    142 	 for execvp.  */
    143       execvp (argv[0], (char **) argv);
    144 
    145       _exit (errno == ENOENT ? 127 : 126);
    146     }
    147 
    148   /* Parent.  */
    149   close (child_fd[0]);
    150   close (child_fd[1]);
    151   return pid;
    152 }
    153 
    154 
    155 /* Wait for the subprocess to exit.  */
    156 
    157 void
    158 reap_subpipe (pid_t pid, char const *program)
    159 {
    160 #if HAVE_WAITPID || defined waitpid
    161   int wstatus;
    162   if (waitpid (pid, &wstatus, 0) < 0)
    163     error (EXIT_FAILURE, errno,
    164 	   "waitpid");
    165   else
    166     {
    167       int status = WIFEXITED (wstatus) ? WEXITSTATUS (wstatus) : -1;
    168       if (status)
    169 	error (EXIT_FAILURE, 0,
    170 	       _(status == 126
    171 		 ? "subsidiary program `%s' could not be invoked"
    172 		 : status == 127
    173 		 ? "subsidiary program `%s' not found"
    174 		 : status < 0
    175 		 ? "subsidiary program `%s' failed"
    176 		 : "subsidiary program `%s' failed (exit status %d)"),
    177 	       program, status);
    178     }
    179 #endif
    180 }
    181 
    182 void
    183 end_of_output_subpipe (pid_t pid ATTRIBUTE_UNUSED,
    184 		       int fd[2] ATTRIBUTE_UNUSED)
    185 {
    186 }
    187