Home | History | Annotate | Line # | Download | only in libiberty
pex-common.c revision 1.1
      1  1.1  christos /* Common code for executing a program in a sub-process.
      2  1.1  christos    Copyright (C) 2005, 2010 Free Software Foundation, Inc.
      3  1.1  christos    Written by Ian Lance Taylor <ian (at) airs.com>.
      4  1.1  christos 
      5  1.1  christos This file is part of the libiberty library.
      6  1.1  christos Libiberty is free software; you can redistribute it and/or
      7  1.1  christos modify it under the terms of the GNU Library General Public
      8  1.1  christos License as published by the Free Software Foundation; either
      9  1.1  christos version 2 of the License, or (at your option) any later version.
     10  1.1  christos 
     11  1.1  christos Libiberty is distributed in the hope that it will be useful,
     12  1.1  christos but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  1.1  christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  1.1  christos Library General Public License for more details.
     15  1.1  christos 
     16  1.1  christos You should have received a copy of the GNU Library General Public
     17  1.1  christos License along with libiberty; see the file COPYING.LIB.  If not,
     18  1.1  christos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
     19  1.1  christos Boston, MA 02110-1301, USA.  */
     20  1.1  christos 
     21  1.1  christos #include "config.h"
     22  1.1  christos #include "libiberty.h"
     23  1.1  christos #include "pex-common.h"
     24  1.1  christos 
     25  1.1  christos #include <stdio.h>
     26  1.1  christos #include <errno.h>
     27  1.1  christos #ifdef NEED_DECLARATION_ERRNO
     28  1.1  christos extern int errno;
     29  1.1  christos #endif
     30  1.1  christos #ifdef HAVE_STDLIB_H
     31  1.1  christos #include <stdlib.h>
     32  1.1  christos #endif
     33  1.1  christos #ifdef HAVE_STRING_H
     34  1.1  christos #include <string.h>
     35  1.1  christos #endif
     36  1.1  christos #ifdef HAVE_UNISTD_H
     37  1.1  christos #include <unistd.h>
     38  1.1  christos #endif
     39  1.1  christos 
     40  1.1  christos extern int mkstemps (char *, int);
     41  1.1  christos 
     42  1.1  christos /* This file contains subroutines for the program execution routines
     43  1.1  christos    (pex_init, pex_run, etc.).  This file is compiled on all
     44  1.1  christos    systems.  */
     45  1.1  christos 
     46  1.1  christos static void pex_add_remove (struct pex_obj *, const char *, int);
     47  1.1  christos static int pex_get_status_and_time (struct pex_obj *, int, const char **,
     48  1.1  christos 				    int *);
     49  1.1  christos 
     50  1.1  christos /* Initialize a pex_obj structure.  */
     51  1.1  christos 
     52  1.1  christos struct pex_obj *
     53  1.1  christos pex_init_common (int flags, const char *pname, const char *tempbase,
     54  1.1  christos 		 const struct pex_funcs *funcs)
     55  1.1  christos {
     56  1.1  christos   struct pex_obj *obj;
     57  1.1  christos 
     58  1.1  christos   obj = XNEW (struct pex_obj);
     59  1.1  christos   obj->flags = flags;
     60  1.1  christos   obj->pname = pname;
     61  1.1  christos   obj->tempbase = tempbase;
     62  1.1  christos   obj->next_input = STDIN_FILE_NO;
     63  1.1  christos   obj->next_input_name = NULL;
     64  1.1  christos   obj->next_input_name_allocated = 0;
     65  1.1  christos   obj->stderr_pipe = -1;
     66  1.1  christos   obj->count = 0;
     67  1.1  christos   obj->children = NULL;
     68  1.1  christos   obj->status = NULL;
     69  1.1  christos   obj->time = NULL;
     70  1.1  christos   obj->number_waited = 0;
     71  1.1  christos   obj->input_file = NULL;
     72  1.1  christos   obj->read_output = NULL;
     73  1.1  christos   obj->read_err = NULL;
     74  1.1  christos   obj->remove_count = 0;
     75  1.1  christos   obj->remove = NULL;
     76  1.1  christos   obj->funcs = funcs;
     77  1.1  christos   obj->sysdep = NULL;
     78  1.1  christos   return obj;
     79  1.1  christos }
     80  1.1  christos 
     81  1.1  christos /* Add a file to be removed when we are done.  */
     82  1.1  christos 
     83  1.1  christos static void
     84  1.1  christos pex_add_remove (struct pex_obj *obj, const char *name, int allocated)
     85  1.1  christos {
     86  1.1  christos   char *add;
     87  1.1  christos 
     88  1.1  christos   ++obj->remove_count;
     89  1.1  christos   obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count);
     90  1.1  christos   if (allocated)
     91  1.1  christos     add = (char *) name;
     92  1.1  christos   else
     93  1.1  christos     add = xstrdup (name);
     94  1.1  christos   obj->remove[obj->remove_count - 1] = add;
     95  1.1  christos }
     96  1.1  christos 
     97  1.1  christos /* Generate a temporary file name based on OBJ, FLAGS, and NAME.
     98  1.1  christos    Return NULL if we were unable to reserve a temporary filename.
     99  1.1  christos 
    100  1.1  christos    If non-NULL, the result is either allocated with malloc, or the
    101  1.1  christos    same pointer as NAME.  */
    102  1.1  christos static char *
    103  1.1  christos temp_file (struct pex_obj *obj, int flags, char *name)
    104  1.1  christos {
    105  1.1  christos   if (name == NULL)
    106  1.1  christos     {
    107  1.1  christos       if (obj->tempbase == NULL)
    108  1.1  christos         {
    109  1.1  christos           name = make_temp_file (NULL);
    110  1.1  christos         }
    111  1.1  christos       else
    112  1.1  christos         {
    113  1.1  christos           int len = strlen (obj->tempbase);
    114  1.1  christos           int out;
    115  1.1  christos 
    116  1.1  christos           if (len >= 6
    117  1.1  christos               && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
    118  1.1  christos             name = xstrdup (obj->tempbase);
    119  1.1  christos           else
    120  1.1  christos             name = concat (obj->tempbase, "XXXXXX", NULL);
    121  1.1  christos 
    122  1.1  christos           out = mkstemps (name, 0);
    123  1.1  christos           if (out < 0)
    124  1.1  christos             {
    125  1.1  christos               free (name);
    126  1.1  christos               return NULL;
    127  1.1  christos             }
    128  1.1  christos 
    129  1.1  christos           /* This isn't obj->funcs->close because we got the
    130  1.1  christos              descriptor from mkstemps, not from a function in
    131  1.1  christos              obj->funcs.  Calling close here is just like what
    132  1.1  christos              make_temp_file does.  */
    133  1.1  christos           close (out);
    134  1.1  christos         }
    135  1.1  christos     }
    136  1.1  christos   else if ((flags & PEX_SUFFIX) != 0)
    137  1.1  christos     {
    138  1.1  christos       if (obj->tempbase == NULL)
    139  1.1  christos         name = make_temp_file (name);
    140  1.1  christos       else
    141  1.1  christos         name = concat (obj->tempbase, name, NULL);
    142  1.1  christos     }
    143  1.1  christos 
    144  1.1  christos   return name;
    145  1.1  christos }
    146  1.1  christos 
    147  1.1  christos 
    148  1.1  christos /* As for pex_run (), but permits the environment for the child process
    149  1.1  christos    to be specified. */
    150  1.1  christos 
    151  1.1  christos const char *
    152  1.1  christos pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
    153  1.1  christos        	                char * const * argv, char * const * env,
    154  1.1  christos                         const char *orig_outname, const char *errname,
    155  1.1  christos                   	int *err)
    156  1.1  christos {
    157  1.1  christos   const char *errmsg;
    158  1.1  christos   int in, out, errdes;
    159  1.1  christos   char *outname;
    160  1.1  christos   int outname_allocated;
    161  1.1  christos   int p[2];
    162  1.1  christos   int toclose;
    163  1.1  christos   pid_t pid;
    164  1.1  christos 
    165  1.1  christos   in = -1;
    166  1.1  christos   out = -1;
    167  1.1  christos   errdes = -1;
    168  1.1  christos   outname = (char *) orig_outname;
    169  1.1  christos   outname_allocated = 0;
    170  1.1  christos 
    171  1.1  christos   /* If the user called pex_input_file, close the file now.  */
    172  1.1  christos   if (obj->input_file)
    173  1.1  christos     {
    174  1.1  christos       if (fclose (obj->input_file) == EOF)
    175  1.1  christos         {
    176  1.1  christos           errmsg = "closing pipeline input file";
    177  1.1  christos           goto error_exit;
    178  1.1  christos         }
    179  1.1  christos       obj->input_file = NULL;
    180  1.1  christos     }
    181  1.1  christos 
    182  1.1  christos   /* Set IN.  */
    183  1.1  christos 
    184  1.1  christos   if (obj->next_input_name != NULL)
    185  1.1  christos     {
    186  1.1  christos       /* We have to make sure that the previous process has completed
    187  1.1  christos 	 before we try to read the file.  */
    188  1.1  christos       if (!pex_get_status_and_time (obj, 0, &errmsg, err))
    189  1.1  christos 	goto error_exit;
    190  1.1  christos 
    191  1.1  christos       in = obj->funcs->open_read (obj, obj->next_input_name,
    192  1.1  christos 				  (flags & PEX_BINARY_INPUT) != 0);
    193  1.1  christos       if (in < 0)
    194  1.1  christos 	{
    195  1.1  christos 	  *err = errno;
    196  1.1  christos 	  errmsg = "open temporary file";
    197  1.1  christos 	  goto error_exit;
    198  1.1  christos 	}
    199  1.1  christos       if (obj->next_input_name_allocated)
    200  1.1  christos 	{
    201  1.1  christos 	  free (obj->next_input_name);
    202  1.1  christos 	  obj->next_input_name_allocated = 0;
    203  1.1  christos 	}
    204  1.1  christos       obj->next_input_name = NULL;
    205  1.1  christos     }
    206  1.1  christos   else
    207  1.1  christos     {
    208  1.1  christos       in = obj->next_input;
    209  1.1  christos       if (in < 0)
    210  1.1  christos 	{
    211  1.1  christos 	  *err = 0;
    212  1.1  christos 	  errmsg = "pipeline already complete";
    213  1.1  christos 	  goto error_exit;
    214  1.1  christos 	}
    215  1.1  christos     }
    216  1.1  christos 
    217  1.1  christos   /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME.  */
    218  1.1  christos 
    219  1.1  christos   if ((flags & PEX_LAST) != 0)
    220  1.1  christos     {
    221  1.1  christos       if (outname == NULL)
    222  1.1  christos 	out = STDOUT_FILE_NO;
    223  1.1  christos       else if ((flags & PEX_SUFFIX) != 0)
    224  1.1  christos 	{
    225  1.1  christos 	  outname = concat (obj->tempbase, outname, NULL);
    226  1.1  christos 	  outname_allocated = 1;
    227  1.1  christos 	}
    228  1.1  christos       obj->next_input = -1;
    229  1.1  christos     }
    230  1.1  christos   else if ((obj->flags & PEX_USE_PIPES) == 0)
    231  1.1  christos     {
    232  1.1  christos       outname = temp_file (obj, flags, outname);
    233  1.1  christos       if (! outname)
    234  1.1  christos         {
    235  1.1  christos           *err = 0;
    236  1.1  christos           errmsg = "could not create temporary file";
    237  1.1  christos           goto error_exit;
    238  1.1  christos         }
    239  1.1  christos 
    240  1.1  christos       if (outname != orig_outname)
    241  1.1  christos         outname_allocated = 1;
    242  1.1  christos 
    243  1.1  christos       if ((obj->flags & PEX_SAVE_TEMPS) == 0)
    244  1.1  christos 	{
    245  1.1  christos 	  pex_add_remove (obj, outname, outname_allocated);
    246  1.1  christos 	  outname_allocated = 0;
    247  1.1  christos 	}
    248  1.1  christos 
    249  1.1  christos       /* Hand off ownership of outname to the next stage.  */
    250  1.1  christos       obj->next_input_name = outname;
    251  1.1  christos       obj->next_input_name_allocated = outname_allocated;
    252  1.1  christos       outname_allocated = 0;
    253  1.1  christos     }
    254  1.1  christos   else
    255  1.1  christos     {
    256  1.1  christos       if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
    257  1.1  christos 	{
    258  1.1  christos 	  *err = errno;
    259  1.1  christos 	  errmsg = "pipe";
    260  1.1  christos 	  goto error_exit;
    261  1.1  christos 	}
    262  1.1  christos 
    263  1.1  christos       out = p[WRITE_PORT];
    264  1.1  christos       obj->next_input = p[READ_PORT];
    265  1.1  christos     }
    266  1.1  christos 
    267  1.1  christos   if (out < 0)
    268  1.1  christos     {
    269  1.1  christos       out = obj->funcs->open_write (obj, outname,
    270  1.1  christos 				    (flags & PEX_BINARY_OUTPUT) != 0);
    271  1.1  christos       if (out < 0)
    272  1.1  christos 	{
    273  1.1  christos 	  *err = errno;
    274  1.1  christos 	  errmsg = "open temporary output file";
    275  1.1  christos 	  goto error_exit;
    276  1.1  christos 	}
    277  1.1  christos     }
    278  1.1  christos 
    279  1.1  christos   if (outname_allocated)
    280  1.1  christos     {
    281  1.1  christos       free (outname);
    282  1.1  christos       outname_allocated = 0;
    283  1.1  christos     }
    284  1.1  christos 
    285  1.1  christos   /* Set ERRDES.  */
    286  1.1  christos 
    287  1.1  christos   if (errname != NULL && (flags & PEX_STDERR_TO_PIPE) != 0)
    288  1.1  christos     {
    289  1.1  christos       *err = 0;
    290  1.1  christos       errmsg = "both ERRNAME and PEX_STDERR_TO_PIPE specified.";
    291  1.1  christos       goto error_exit;
    292  1.1  christos     }
    293  1.1  christos 
    294  1.1  christos   if (obj->stderr_pipe != -1)
    295  1.1  christos     {
    296  1.1  christos       *err = 0;
    297  1.1  christos       errmsg = "PEX_STDERR_TO_PIPE used in the middle of pipeline";
    298  1.1  christos       goto error_exit;
    299  1.1  christos     }
    300  1.1  christos 
    301  1.1  christos   if (errname == NULL)
    302  1.1  christos     {
    303  1.1  christos       if (flags & PEX_STDERR_TO_PIPE)
    304  1.1  christos 	{
    305  1.1  christos 	  if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_ERROR) != 0) < 0)
    306  1.1  christos 	    {
    307  1.1  christos 	      *err = errno;
    308  1.1  christos 	      errmsg = "pipe";
    309  1.1  christos 	      goto error_exit;
    310  1.1  christos 	    }
    311  1.1  christos 
    312  1.1  christos 	  errdes = p[WRITE_PORT];
    313  1.1  christos 	  obj->stderr_pipe = p[READ_PORT];
    314  1.1  christos 	}
    315  1.1  christos       else
    316  1.1  christos 	{
    317  1.1  christos 	  errdes = STDERR_FILE_NO;
    318  1.1  christos 	}
    319  1.1  christos     }
    320  1.1  christos   else
    321  1.1  christos     {
    322  1.1  christos       errdes = obj->funcs->open_write (obj, errname,
    323  1.1  christos 				       (flags & PEX_BINARY_ERROR) != 0);
    324  1.1  christos       if (errdes < 0)
    325  1.1  christos 	{
    326  1.1  christos 	  *err = errno;
    327  1.1  christos 	  errmsg = "open error file";
    328  1.1  christos 	  goto error_exit;
    329  1.1  christos 	}
    330  1.1  christos     }
    331  1.1  christos 
    332  1.1  christos   /* If we are using pipes, the child process has to close the next
    333  1.1  christos      input pipe.  */
    334  1.1  christos 
    335  1.1  christos   if ((obj->flags & PEX_USE_PIPES) == 0)
    336  1.1  christos     toclose = -1;
    337  1.1  christos   else
    338  1.1  christos     toclose = obj->next_input;
    339  1.1  christos 
    340  1.1  christos   /* Run the program.  */
    341  1.1  christos 
    342  1.1  christos   pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
    343  1.1  christos 				in, out, errdes, toclose, &errmsg, err);
    344  1.1  christos   if (pid < 0)
    345  1.1  christos     goto error_exit;
    346  1.1  christos 
    347  1.1  christos   ++obj->count;
    348  1.1  christos   obj->children = XRESIZEVEC (pid_t, obj->children, obj->count);
    349  1.1  christos   obj->children[obj->count - 1] = pid;
    350  1.1  christos 
    351  1.1  christos   return NULL;
    352  1.1  christos 
    353  1.1  christos  error_exit:
    354  1.1  christos   if (in >= 0 && in != STDIN_FILE_NO)
    355  1.1  christos     obj->funcs->close (obj, in);
    356  1.1  christos   if (out >= 0 && out != STDOUT_FILE_NO)
    357  1.1  christos     obj->funcs->close (obj, out);
    358  1.1  christos   if (errdes >= 0 && errdes != STDERR_FILE_NO)
    359  1.1  christos     obj->funcs->close (obj, errdes);
    360  1.1  christos   if (outname_allocated)
    361  1.1  christos     free (outname);
    362  1.1  christos   return errmsg;
    363  1.1  christos }
    364  1.1  christos 
    365  1.1  christos /* Run a program.  */
    366  1.1  christos 
    367  1.1  christos const char *
    368  1.1  christos pex_run (struct pex_obj *obj, int flags, const char *executable,
    369  1.1  christos        	 char * const * argv, const char *orig_outname, const char *errname,
    370  1.1  christos          int *err)
    371  1.1  christos {
    372  1.1  christos   return pex_run_in_environment (obj, flags, executable, argv, NULL,
    373  1.1  christos 				 orig_outname, errname, err);
    374  1.1  christos }
    375  1.1  christos 
    376  1.1  christos /* Return a FILE pointer for a temporary file to fill with input for
    377  1.1  christos    the pipeline.  */
    378  1.1  christos FILE *
    379  1.1  christos pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
    380  1.1  christos {
    381  1.1  christos   char *name = (char *) in_name;
    382  1.1  christos   FILE *f;
    383  1.1  christos 
    384  1.1  christos   /* This must be called before the first pipeline stage is run, and
    385  1.1  christos      there must not have been any other input selected.  */
    386  1.1  christos   if (obj->count != 0
    387  1.1  christos       || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
    388  1.1  christos       || obj->next_input_name)
    389  1.1  christos     {
    390  1.1  christos       errno = EINVAL;
    391  1.1  christos       return NULL;
    392  1.1  christos     }
    393  1.1  christos 
    394  1.1  christos   name = temp_file (obj, flags, name);
    395  1.1  christos   if (! name)
    396  1.1  christos     return NULL;
    397  1.1  christos 
    398  1.1  christos   f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
    399  1.1  christos   if (! f)
    400  1.1  christos     {
    401  1.1  christos       free (name);
    402  1.1  christos       return NULL;
    403  1.1  christos     }
    404  1.1  christos 
    405  1.1  christos   obj->input_file = f;
    406  1.1  christos   obj->next_input_name = name;
    407  1.1  christos   obj->next_input_name_allocated = (name != in_name);
    408  1.1  christos 
    409  1.1  christos   return f;
    410  1.1  christos }
    411  1.1  christos 
    412  1.1  christos /* Return a stream for a pipe connected to the standard input of the
    413  1.1  christos    first stage of the pipeline.  */
    414  1.1  christos FILE *
    415  1.1  christos pex_input_pipe (struct pex_obj *obj, int binary)
    416  1.1  christos {
    417  1.1  christos   int p[2];
    418  1.1  christos   FILE *f;
    419  1.1  christos 
    420  1.1  christos   /* You must call pex_input_pipe before the first pex_run or pex_one.  */
    421  1.1  christos   if (obj->count > 0)
    422  1.1  christos     goto usage_error;
    423  1.1  christos 
    424  1.1  christos   /* You must be using pipes.  Implementations that don't support
    425  1.1  christos      pipes clear this flag before calling pex_init_common.  */
    426  1.1  christos   if (! (obj->flags & PEX_USE_PIPES))
    427  1.1  christos     goto usage_error;
    428  1.1  christos 
    429  1.1  christos   /* If we have somehow already selected other input, that's a
    430  1.1  christos      mistake.  */
    431  1.1  christos   if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
    432  1.1  christos       || obj->next_input_name)
    433  1.1  christos     goto usage_error;
    434  1.1  christos 
    435  1.1  christos   if (obj->funcs->pipe (obj, p, binary != 0) < 0)
    436  1.1  christos     return NULL;
    437  1.1  christos 
    438  1.1  christos   f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
    439  1.1  christos   if (! f)
    440  1.1  christos     {
    441  1.1  christos       int saved_errno = errno;
    442  1.1  christos       obj->funcs->close (obj, p[READ_PORT]);
    443  1.1  christos       obj->funcs->close (obj, p[WRITE_PORT]);
    444  1.1  christos       errno = saved_errno;
    445  1.1  christos       return NULL;
    446  1.1  christos     }
    447  1.1  christos 
    448  1.1  christos   obj->next_input = p[READ_PORT];
    449  1.1  christos 
    450  1.1  christos   return f;
    451  1.1  christos 
    452  1.1  christos  usage_error:
    453  1.1  christos   errno = EINVAL;
    454  1.1  christos   return NULL;
    455  1.1  christos }
    456  1.1  christos 
    457  1.1  christos /* Return a FILE pointer for the output of the last program
    458  1.1  christos    executed.  */
    459  1.1  christos 
    460  1.1  christos FILE *
    461  1.1  christos pex_read_output (struct pex_obj *obj, int binary)
    462  1.1  christos {
    463  1.1  christos   if (obj->next_input_name != NULL)
    464  1.1  christos     {
    465  1.1  christos       const char *errmsg;
    466  1.1  christos       int err;
    467  1.1  christos 
    468  1.1  christos       /* We have to make sure that the process has completed before we
    469  1.1  christos 	 try to read the file.  */
    470  1.1  christos       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
    471  1.1  christos 	{
    472  1.1  christos 	  errno = err;
    473  1.1  christos 	  return NULL;
    474  1.1  christos 	}
    475  1.1  christos 
    476  1.1  christos       obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
    477  1.1  christos 
    478  1.1  christos       if (obj->next_input_name_allocated)
    479  1.1  christos 	{
    480  1.1  christos 	  free (obj->next_input_name);
    481  1.1  christos 	  obj->next_input_name_allocated = 0;
    482  1.1  christos 	}
    483  1.1  christos       obj->next_input_name = NULL;
    484  1.1  christos     }
    485  1.1  christos   else
    486  1.1  christos     {
    487  1.1  christos       int o;
    488  1.1  christos 
    489  1.1  christos       o = obj->next_input;
    490  1.1  christos       if (o < 0 || o == STDIN_FILE_NO)
    491  1.1  christos 	return NULL;
    492  1.1  christos       obj->read_output = obj->funcs->fdopenr (obj, o, binary);
    493  1.1  christos       obj->next_input = -1;
    494  1.1  christos     }
    495  1.1  christos 
    496  1.1  christos   return obj->read_output;
    497  1.1  christos }
    498  1.1  christos 
    499  1.1  christos FILE *
    500  1.1  christos pex_read_err (struct pex_obj *obj, int binary)
    501  1.1  christos {
    502  1.1  christos   int o;
    503  1.1  christos 
    504  1.1  christos   o = obj->stderr_pipe;
    505  1.1  christos   if (o < 0 || o == STDIN_FILE_NO)
    506  1.1  christos     return NULL;
    507  1.1  christos   obj->read_err = obj->funcs->fdopenr (obj, o, binary);
    508  1.1  christos   obj->stderr_pipe = -1;
    509  1.1  christos   return obj->read_err;
    510  1.1  christos }
    511  1.1  christos 
    512  1.1  christos /* Get the exit status and, if requested, the resource time for all
    513  1.1  christos    the child processes.  Return 0 on failure, 1 on success.  */
    514  1.1  christos 
    515  1.1  christos static int
    516  1.1  christos pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
    517  1.1  christos 			 int *err)
    518  1.1  christos {
    519  1.1  christos   int ret;
    520  1.1  christos   int i;
    521  1.1  christos 
    522  1.1  christos   if (obj->number_waited == obj->count)
    523  1.1  christos     return 1;
    524  1.1  christos 
    525  1.1  christos   obj->status = XRESIZEVEC (int, obj->status, obj->count);
    526  1.1  christos   if ((obj->flags & PEX_RECORD_TIMES) != 0)
    527  1.1  christos     obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
    528  1.1  christos 
    529  1.1  christos   ret = 1;
    530  1.1  christos   for (i = obj->number_waited; i < obj->count; ++i)
    531  1.1  christos     {
    532  1.1  christos       if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
    533  1.1  christos 			    obj->time == NULL ? NULL : &obj->time[i],
    534  1.1  christos 			    done, errmsg, err) < 0)
    535  1.1  christos 	ret = 0;
    536  1.1  christos     }
    537  1.1  christos   obj->number_waited = i;
    538  1.1  christos 
    539  1.1  christos   return ret;
    540  1.1  christos }
    541  1.1  christos 
    542  1.1  christos /* Get exit status of executed programs.  */
    543  1.1  christos 
    544  1.1  christos int
    545  1.1  christos pex_get_status (struct pex_obj *obj, int count, int *vector)
    546  1.1  christos {
    547  1.1  christos   if (obj->status == NULL)
    548  1.1  christos     {
    549  1.1  christos       const char *errmsg;
    550  1.1  christos       int err;
    551  1.1  christos 
    552  1.1  christos       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
    553  1.1  christos 	return 0;
    554  1.1  christos     }
    555  1.1  christos 
    556  1.1  christos   if (count > obj->count)
    557  1.1  christos     {
    558  1.1  christos       memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
    559  1.1  christos       count = obj->count;
    560  1.1  christos     }
    561  1.1  christos 
    562  1.1  christos   memcpy (vector, obj->status, count * sizeof (int));
    563  1.1  christos 
    564  1.1  christos   return 1;
    565  1.1  christos }
    566  1.1  christos 
    567  1.1  christos /* Get process times of executed programs.  */
    568  1.1  christos 
    569  1.1  christos int
    570  1.1  christos pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
    571  1.1  christos {
    572  1.1  christos   if (obj->status == NULL)
    573  1.1  christos     {
    574  1.1  christos       const char *errmsg;
    575  1.1  christos       int err;
    576  1.1  christos 
    577  1.1  christos       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
    578  1.1  christos 	return 0;
    579  1.1  christos     }
    580  1.1  christos 
    581  1.1  christos   if (obj->time == NULL)
    582  1.1  christos     return 0;
    583  1.1  christos 
    584  1.1  christos   if (count > obj->count)
    585  1.1  christos     {
    586  1.1  christos       memset (vector + obj->count, 0,
    587  1.1  christos 	      (count - obj->count) * sizeof (struct pex_time));
    588  1.1  christos       count = obj->count;
    589  1.1  christos     }
    590  1.1  christos 
    591  1.1  christos   memcpy (vector, obj->time, count * sizeof (struct pex_time));
    592  1.1  christos 
    593  1.1  christos   return 1;
    594  1.1  christos }
    595  1.1  christos 
    596  1.1  christos /* Free a pex_obj structure.  */
    597  1.1  christos 
    598  1.1  christos void
    599  1.1  christos pex_free (struct pex_obj *obj)
    600  1.1  christos {
    601  1.1  christos   /* Close pipe file descriptors corresponding to child's stdout and
    602  1.1  christos      stderr so that the child does not hang trying to output something
    603  1.1  christos      while we're waiting for it.  */
    604  1.1  christos   if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
    605  1.1  christos     obj->funcs->close (obj, obj->next_input);
    606  1.1  christos   if (obj->stderr_pipe >= 0 && obj->stderr_pipe != STDIN_FILE_NO)
    607  1.1  christos     obj->funcs->close (obj, obj->stderr_pipe);
    608  1.1  christos   if (obj->read_output != NULL)
    609  1.1  christos     fclose (obj->read_output);
    610  1.1  christos   if (obj->read_err != NULL)
    611  1.1  christos     fclose (obj->read_err);
    612  1.1  christos 
    613  1.1  christos   /* If the caller forgot to wait for the children, we do it here, to
    614  1.1  christos      avoid zombies.  */
    615  1.1  christos   if (obj->status == NULL)
    616  1.1  christos     {
    617  1.1  christos       const char *errmsg;
    618  1.1  christos       int err;
    619  1.1  christos 
    620  1.1  christos       obj->flags &= ~ PEX_RECORD_TIMES;
    621  1.1  christos       pex_get_status_and_time (obj, 1, &errmsg, &err);
    622  1.1  christos     }
    623  1.1  christos 
    624  1.1  christos   if (obj->next_input_name_allocated)
    625  1.1  christos     free (obj->next_input_name);
    626  1.1  christos   free (obj->children);
    627  1.1  christos   free (obj->status);
    628  1.1  christos   free (obj->time);
    629  1.1  christos 
    630  1.1  christos   if (obj->remove_count > 0)
    631  1.1  christos     {
    632  1.1  christos       int i;
    633  1.1  christos 
    634  1.1  christos       for (i = 0; i < obj->remove_count; ++i)
    635  1.1  christos 	{
    636  1.1  christos 	  remove (obj->remove[i]);
    637  1.1  christos 	  free (obj->remove[i]);
    638  1.1  christos 	}
    639  1.1  christos       free (obj->remove);
    640  1.1  christos     }
    641  1.1  christos 
    642  1.1  christos   if (obj->funcs->cleanup != NULL)
    643  1.1  christos     obj->funcs->cleanup (obj);
    644  1.1  christos 
    645  1.1  christos   free (obj);
    646  1.1  christos }
    647