Home | History | Annotate | Line # | Download | only in libiberty
pex-common.c revision 1.1.1.4
      1      1.1  christos /* Common code for executing a program in a sub-process.
      2  1.1.1.4  christos    Copyright (C) 2005-2020 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.1.2  christos 				    (flags & PEX_BINARY_OUTPUT) != 0,
    271  1.1.1.2  christos 				    (flags & PEX_STDOUT_APPEND) != 0);
    272      1.1  christos       if (out < 0)
    273      1.1  christos 	{
    274      1.1  christos 	  *err = errno;
    275      1.1  christos 	  errmsg = "open temporary output file";
    276      1.1  christos 	  goto error_exit;
    277      1.1  christos 	}
    278      1.1  christos     }
    279      1.1  christos 
    280      1.1  christos   if (outname_allocated)
    281      1.1  christos     {
    282      1.1  christos       free (outname);
    283      1.1  christos       outname_allocated = 0;
    284      1.1  christos     }
    285      1.1  christos 
    286      1.1  christos   /* Set ERRDES.  */
    287      1.1  christos 
    288      1.1  christos   if (errname != NULL && (flags & PEX_STDERR_TO_PIPE) != 0)
    289      1.1  christos     {
    290      1.1  christos       *err = 0;
    291      1.1  christos       errmsg = "both ERRNAME and PEX_STDERR_TO_PIPE specified.";
    292      1.1  christos       goto error_exit;
    293      1.1  christos     }
    294      1.1  christos 
    295      1.1  christos   if (obj->stderr_pipe != -1)
    296      1.1  christos     {
    297      1.1  christos       *err = 0;
    298      1.1  christos       errmsg = "PEX_STDERR_TO_PIPE used in the middle of pipeline";
    299      1.1  christos       goto error_exit;
    300      1.1  christos     }
    301      1.1  christos 
    302      1.1  christos   if (errname == NULL)
    303      1.1  christos     {
    304      1.1  christos       if (flags & PEX_STDERR_TO_PIPE)
    305      1.1  christos 	{
    306      1.1  christos 	  if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_ERROR) != 0) < 0)
    307      1.1  christos 	    {
    308      1.1  christos 	      *err = errno;
    309      1.1  christos 	      errmsg = "pipe";
    310      1.1  christos 	      goto error_exit;
    311      1.1  christos 	    }
    312      1.1  christos 
    313      1.1  christos 	  errdes = p[WRITE_PORT];
    314      1.1  christos 	  obj->stderr_pipe = p[READ_PORT];
    315      1.1  christos 	}
    316      1.1  christos       else
    317      1.1  christos 	{
    318      1.1  christos 	  errdes = STDERR_FILE_NO;
    319      1.1  christos 	}
    320      1.1  christos     }
    321      1.1  christos   else
    322      1.1  christos     {
    323  1.1.1.2  christos       errdes = obj->funcs->open_write (obj, errname,
    324  1.1.1.2  christos 				       (flags & PEX_BINARY_ERROR) != 0,
    325  1.1.1.2  christos 				       (flags & PEX_STDERR_APPEND) != 0);
    326      1.1  christos       if (errdes < 0)
    327      1.1  christos 	{
    328      1.1  christos 	  *err = errno;
    329      1.1  christos 	  errmsg = "open error file";
    330      1.1  christos 	  goto error_exit;
    331      1.1  christos 	}
    332      1.1  christos     }
    333      1.1  christos 
    334      1.1  christos   /* If we are using pipes, the child process has to close the next
    335      1.1  christos      input pipe.  */
    336      1.1  christos 
    337      1.1  christos   if ((obj->flags & PEX_USE_PIPES) == 0)
    338      1.1  christos     toclose = -1;
    339      1.1  christos   else
    340      1.1  christos     toclose = obj->next_input;
    341      1.1  christos 
    342      1.1  christos   /* Run the program.  */
    343      1.1  christos 
    344      1.1  christos   pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
    345      1.1  christos 				in, out, errdes, toclose, &errmsg, err);
    346      1.1  christos   if (pid < 0)
    347      1.1  christos     goto error_exit;
    348      1.1  christos 
    349      1.1  christos   ++obj->count;
    350      1.1  christos   obj->children = XRESIZEVEC (pid_t, obj->children, obj->count);
    351      1.1  christos   obj->children[obj->count - 1] = pid;
    352      1.1  christos 
    353      1.1  christos   return NULL;
    354      1.1  christos 
    355      1.1  christos  error_exit:
    356      1.1  christos   if (in >= 0 && in != STDIN_FILE_NO)
    357      1.1  christos     obj->funcs->close (obj, in);
    358      1.1  christos   if (out >= 0 && out != STDOUT_FILE_NO)
    359      1.1  christos     obj->funcs->close (obj, out);
    360      1.1  christos   if (errdes >= 0 && errdes != STDERR_FILE_NO)
    361      1.1  christos     obj->funcs->close (obj, errdes);
    362      1.1  christos   if (outname_allocated)
    363      1.1  christos     free (outname);
    364      1.1  christos   return errmsg;
    365      1.1  christos }
    366      1.1  christos 
    367      1.1  christos /* Run a program.  */
    368      1.1  christos 
    369      1.1  christos const char *
    370      1.1  christos pex_run (struct pex_obj *obj, int flags, const char *executable,
    371      1.1  christos        	 char * const * argv, const char *orig_outname, const char *errname,
    372      1.1  christos          int *err)
    373      1.1  christos {
    374      1.1  christos   return pex_run_in_environment (obj, flags, executable, argv, NULL,
    375      1.1  christos 				 orig_outname, errname, err);
    376      1.1  christos }
    377      1.1  christos 
    378      1.1  christos /* Return a FILE pointer for a temporary file to fill with input for
    379      1.1  christos    the pipeline.  */
    380      1.1  christos FILE *
    381      1.1  christos pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
    382      1.1  christos {
    383      1.1  christos   char *name = (char *) in_name;
    384      1.1  christos   FILE *f;
    385      1.1  christos 
    386      1.1  christos   /* This must be called before the first pipeline stage is run, and
    387      1.1  christos      there must not have been any other input selected.  */
    388      1.1  christos   if (obj->count != 0
    389      1.1  christos       || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
    390      1.1  christos       || obj->next_input_name)
    391      1.1  christos     {
    392      1.1  christos       errno = EINVAL;
    393      1.1  christos       return NULL;
    394      1.1  christos     }
    395      1.1  christos 
    396      1.1  christos   name = temp_file (obj, flags, name);
    397      1.1  christos   if (! name)
    398      1.1  christos     return NULL;
    399      1.1  christos 
    400      1.1  christos   f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
    401      1.1  christos   if (! f)
    402      1.1  christos     {
    403      1.1  christos       free (name);
    404      1.1  christos       return NULL;
    405      1.1  christos     }
    406      1.1  christos 
    407      1.1  christos   obj->input_file = f;
    408      1.1  christos   obj->next_input_name = name;
    409      1.1  christos   obj->next_input_name_allocated = (name != in_name);
    410      1.1  christos 
    411      1.1  christos   return f;
    412      1.1  christos }
    413      1.1  christos 
    414      1.1  christos /* Return a stream for a pipe connected to the standard input of the
    415      1.1  christos    first stage of the pipeline.  */
    416      1.1  christos FILE *
    417      1.1  christos pex_input_pipe (struct pex_obj *obj, int binary)
    418      1.1  christos {
    419      1.1  christos   int p[2];
    420      1.1  christos   FILE *f;
    421      1.1  christos 
    422      1.1  christos   /* You must call pex_input_pipe before the first pex_run or pex_one.  */
    423      1.1  christos   if (obj->count > 0)
    424      1.1  christos     goto usage_error;
    425      1.1  christos 
    426      1.1  christos   /* You must be using pipes.  Implementations that don't support
    427      1.1  christos      pipes clear this flag before calling pex_init_common.  */
    428      1.1  christos   if (! (obj->flags & PEX_USE_PIPES))
    429      1.1  christos     goto usage_error;
    430      1.1  christos 
    431      1.1  christos   /* If we have somehow already selected other input, that's a
    432      1.1  christos      mistake.  */
    433      1.1  christos   if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
    434      1.1  christos       || obj->next_input_name)
    435      1.1  christos     goto usage_error;
    436      1.1  christos 
    437      1.1  christos   if (obj->funcs->pipe (obj, p, binary != 0) < 0)
    438      1.1  christos     return NULL;
    439      1.1  christos 
    440      1.1  christos   f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
    441      1.1  christos   if (! f)
    442      1.1  christos     {
    443      1.1  christos       int saved_errno = errno;
    444      1.1  christos       obj->funcs->close (obj, p[READ_PORT]);
    445      1.1  christos       obj->funcs->close (obj, p[WRITE_PORT]);
    446      1.1  christos       errno = saved_errno;
    447      1.1  christos       return NULL;
    448      1.1  christos     }
    449      1.1  christos 
    450      1.1  christos   obj->next_input = p[READ_PORT];
    451      1.1  christos 
    452      1.1  christos   return f;
    453      1.1  christos 
    454      1.1  christos  usage_error:
    455      1.1  christos   errno = EINVAL;
    456      1.1  christos   return NULL;
    457      1.1  christos }
    458      1.1  christos 
    459      1.1  christos /* Return a FILE pointer for the output of the last program
    460      1.1  christos    executed.  */
    461      1.1  christos 
    462      1.1  christos FILE *
    463      1.1  christos pex_read_output (struct pex_obj *obj, int binary)
    464      1.1  christos {
    465      1.1  christos   if (obj->next_input_name != NULL)
    466      1.1  christos     {
    467      1.1  christos       const char *errmsg;
    468      1.1  christos       int err;
    469      1.1  christos 
    470      1.1  christos       /* We have to make sure that the process has completed before we
    471      1.1  christos 	 try to read the file.  */
    472      1.1  christos       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
    473      1.1  christos 	{
    474      1.1  christos 	  errno = err;
    475      1.1  christos 	  return NULL;
    476      1.1  christos 	}
    477      1.1  christos 
    478      1.1  christos       obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
    479      1.1  christos 
    480      1.1  christos       if (obj->next_input_name_allocated)
    481      1.1  christos 	{
    482      1.1  christos 	  free (obj->next_input_name);
    483      1.1  christos 	  obj->next_input_name_allocated = 0;
    484      1.1  christos 	}
    485      1.1  christos       obj->next_input_name = NULL;
    486      1.1  christos     }
    487      1.1  christos   else
    488      1.1  christos     {
    489      1.1  christos       int o;
    490      1.1  christos 
    491      1.1  christos       o = obj->next_input;
    492      1.1  christos       if (o < 0 || o == STDIN_FILE_NO)
    493      1.1  christos 	return NULL;
    494      1.1  christos       obj->read_output = obj->funcs->fdopenr (obj, o, binary);
    495      1.1  christos       obj->next_input = -1;
    496      1.1  christos     }
    497      1.1  christos 
    498      1.1  christos   return obj->read_output;
    499      1.1  christos }
    500      1.1  christos 
    501      1.1  christos FILE *
    502      1.1  christos pex_read_err (struct pex_obj *obj, int binary)
    503      1.1  christos {
    504      1.1  christos   int o;
    505      1.1  christos 
    506      1.1  christos   o = obj->stderr_pipe;
    507      1.1  christos   if (o < 0 || o == STDIN_FILE_NO)
    508      1.1  christos     return NULL;
    509      1.1  christos   obj->read_err = obj->funcs->fdopenr (obj, o, binary);
    510      1.1  christos   obj->stderr_pipe = -1;
    511      1.1  christos   return obj->read_err;
    512      1.1  christos }
    513      1.1  christos 
    514      1.1  christos /* Get the exit status and, if requested, the resource time for all
    515      1.1  christos    the child processes.  Return 0 on failure, 1 on success.  */
    516      1.1  christos 
    517      1.1  christos static int
    518      1.1  christos pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
    519      1.1  christos 			 int *err)
    520      1.1  christos {
    521      1.1  christos   int ret;
    522      1.1  christos   int i;
    523      1.1  christos 
    524      1.1  christos   if (obj->number_waited == obj->count)
    525      1.1  christos     return 1;
    526      1.1  christos 
    527      1.1  christos   obj->status = XRESIZEVEC (int, obj->status, obj->count);
    528      1.1  christos   if ((obj->flags & PEX_RECORD_TIMES) != 0)
    529      1.1  christos     obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
    530      1.1  christos 
    531      1.1  christos   ret = 1;
    532      1.1  christos   for (i = obj->number_waited; i < obj->count; ++i)
    533      1.1  christos     {
    534      1.1  christos       if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
    535      1.1  christos 			    obj->time == NULL ? NULL : &obj->time[i],
    536      1.1  christos 			    done, errmsg, err) < 0)
    537      1.1  christos 	ret = 0;
    538      1.1  christos     }
    539      1.1  christos   obj->number_waited = i;
    540      1.1  christos 
    541      1.1  christos   return ret;
    542      1.1  christos }
    543      1.1  christos 
    544      1.1  christos /* Get exit status of executed programs.  */
    545      1.1  christos 
    546      1.1  christos int
    547      1.1  christos pex_get_status (struct pex_obj *obj, int count, int *vector)
    548      1.1  christos {
    549      1.1  christos   if (obj->status == NULL)
    550      1.1  christos     {
    551      1.1  christos       const char *errmsg;
    552      1.1  christos       int err;
    553      1.1  christos 
    554      1.1  christos       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
    555      1.1  christos 	return 0;
    556      1.1  christos     }
    557      1.1  christos 
    558      1.1  christos   if (count > obj->count)
    559      1.1  christos     {
    560      1.1  christos       memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
    561      1.1  christos       count = obj->count;
    562      1.1  christos     }
    563      1.1  christos 
    564      1.1  christos   memcpy (vector, obj->status, count * sizeof (int));
    565      1.1  christos 
    566      1.1  christos   return 1;
    567      1.1  christos }
    568      1.1  christos 
    569      1.1  christos /* Get process times of executed programs.  */
    570      1.1  christos 
    571      1.1  christos int
    572      1.1  christos pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
    573      1.1  christos {
    574      1.1  christos   if (obj->status == NULL)
    575      1.1  christos     {
    576      1.1  christos       const char *errmsg;
    577      1.1  christos       int err;
    578      1.1  christos 
    579      1.1  christos       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
    580      1.1  christos 	return 0;
    581      1.1  christos     }
    582      1.1  christos 
    583      1.1  christos   if (obj->time == NULL)
    584      1.1  christos     return 0;
    585      1.1  christos 
    586      1.1  christos   if (count > obj->count)
    587      1.1  christos     {
    588      1.1  christos       memset (vector + obj->count, 0,
    589      1.1  christos 	      (count - obj->count) * sizeof (struct pex_time));
    590      1.1  christos       count = obj->count;
    591      1.1  christos     }
    592      1.1  christos 
    593      1.1  christos   memcpy (vector, obj->time, count * sizeof (struct pex_time));
    594      1.1  christos 
    595      1.1  christos   return 1;
    596      1.1  christos }
    597      1.1  christos 
    598      1.1  christos /* Free a pex_obj structure.  */
    599      1.1  christos 
    600      1.1  christos void
    601      1.1  christos pex_free (struct pex_obj *obj)
    602      1.1  christos {
    603      1.1  christos   /* Close pipe file descriptors corresponding to child's stdout and
    604      1.1  christos      stderr so that the child does not hang trying to output something
    605      1.1  christos      while we're waiting for it.  */
    606      1.1  christos   if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
    607      1.1  christos     obj->funcs->close (obj, obj->next_input);
    608      1.1  christos   if (obj->stderr_pipe >= 0 && obj->stderr_pipe != STDIN_FILE_NO)
    609      1.1  christos     obj->funcs->close (obj, obj->stderr_pipe);
    610      1.1  christos   if (obj->read_output != NULL)
    611      1.1  christos     fclose (obj->read_output);
    612      1.1  christos   if (obj->read_err != NULL)
    613      1.1  christos     fclose (obj->read_err);
    614      1.1  christos 
    615      1.1  christos   /* If the caller forgot to wait for the children, we do it here, to
    616      1.1  christos      avoid zombies.  */
    617      1.1  christos   if (obj->status == NULL)
    618      1.1  christos     {
    619      1.1  christos       const char *errmsg;
    620      1.1  christos       int err;
    621      1.1  christos 
    622      1.1  christos       obj->flags &= ~ PEX_RECORD_TIMES;
    623      1.1  christos       pex_get_status_and_time (obj, 1, &errmsg, &err);
    624      1.1  christos     }
    625      1.1  christos 
    626      1.1  christos   if (obj->next_input_name_allocated)
    627      1.1  christos     free (obj->next_input_name);
    628      1.1  christos   free (obj->children);
    629      1.1  christos   free (obj->status);
    630      1.1  christos   free (obj->time);
    631      1.1  christos 
    632      1.1  christos   if (obj->remove_count > 0)
    633      1.1  christos     {
    634      1.1  christos       int i;
    635      1.1  christos 
    636      1.1  christos       for (i = 0; i < obj->remove_count; ++i)
    637      1.1  christos 	{
    638      1.1  christos 	  remove (obj->remove[i]);
    639      1.1  christos 	  free (obj->remove[i]);
    640      1.1  christos 	}
    641      1.1  christos       free (obj->remove);
    642      1.1  christos     }
    643      1.1  christos 
    644      1.1  christos   if (obj->funcs->cleanup != NULL)
    645      1.1  christos     obj->funcs->cleanup (obj);
    646      1.1  christos 
    647      1.1  christos   free (obj);
    648      1.1  christos }
    649