xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/pex-common.c (revision 5173eb0a33e5d83890ba976253e703be4c92557c)
198b9484cSchristos /* Common code for executing a program in a sub-process.
2*5173eb0aSchristos    Copyright (C) 2005-2024 Free Software Foundation, Inc.
398b9484cSchristos    Written by Ian Lance Taylor <ian@airs.com>.
498b9484cSchristos 
598b9484cSchristos This file is part of the libiberty library.
698b9484cSchristos Libiberty is free software; you can redistribute it and/or
798b9484cSchristos modify it under the terms of the GNU Library General Public
898b9484cSchristos License as published by the Free Software Foundation; either
998b9484cSchristos version 2 of the License, or (at your option) any later version.
1098b9484cSchristos 
1198b9484cSchristos Libiberty is distributed in the hope that it will be useful,
1298b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1398b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1498b9484cSchristos Library General Public License for more details.
1598b9484cSchristos 
1698b9484cSchristos You should have received a copy of the GNU Library General Public
1798b9484cSchristos License along with libiberty; see the file COPYING.LIB.  If not,
1898b9484cSchristos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
1998b9484cSchristos Boston, MA 02110-1301, USA.  */
2098b9484cSchristos 
2198b9484cSchristos #include "config.h"
2298b9484cSchristos #include "libiberty.h"
2398b9484cSchristos #include "pex-common.h"
2498b9484cSchristos 
2598b9484cSchristos #include <stdio.h>
2698b9484cSchristos #include <errno.h>
2798b9484cSchristos #ifdef NEED_DECLARATION_ERRNO
2898b9484cSchristos extern int errno;
2998b9484cSchristos #endif
3098b9484cSchristos #ifdef HAVE_STDLIB_H
3198b9484cSchristos #include <stdlib.h>
3298b9484cSchristos #endif
3398b9484cSchristos #ifdef HAVE_STRING_H
3498b9484cSchristos #include <string.h>
3598b9484cSchristos #endif
3698b9484cSchristos #ifdef HAVE_UNISTD_H
3798b9484cSchristos #include <unistd.h>
3898b9484cSchristos #endif
3998b9484cSchristos 
4098b9484cSchristos extern int mkstemps (char *, int);
4198b9484cSchristos 
4298b9484cSchristos /* This file contains subroutines for the program execution routines
4398b9484cSchristos    (pex_init, pex_run, etc.).  This file is compiled on all
4498b9484cSchristos    systems.  */
4598b9484cSchristos 
4698b9484cSchristos static void pex_add_remove (struct pex_obj *, const char *, int);
4798b9484cSchristos static int pex_get_status_and_time (struct pex_obj *, int, const char **,
4898b9484cSchristos 				    int *);
4998b9484cSchristos 
5098b9484cSchristos /* Initialize a pex_obj structure.  */
5198b9484cSchristos 
5298b9484cSchristos struct pex_obj *
5398b9484cSchristos pex_init_common (int flags, const char *pname, const char *tempbase,
5498b9484cSchristos 		 const struct pex_funcs *funcs)
5598b9484cSchristos {
5698b9484cSchristos   struct pex_obj *obj;
5798b9484cSchristos 
5898b9484cSchristos   obj = XNEW (struct pex_obj);
5998b9484cSchristos   obj->flags = flags;
6098b9484cSchristos   obj->pname = pname;
6198b9484cSchristos   obj->tempbase = tempbase;
6298b9484cSchristos   obj->next_input = STDIN_FILE_NO;
6398b9484cSchristos   obj->next_input_name = NULL;
6498b9484cSchristos   obj->next_input_name_allocated = 0;
6598b9484cSchristos   obj->stderr_pipe = -1;
6698b9484cSchristos   obj->count = 0;
6798b9484cSchristos   obj->children = NULL;
6898b9484cSchristos   obj->status = NULL;
6998b9484cSchristos   obj->time = NULL;
7098b9484cSchristos   obj->number_waited = 0;
7198b9484cSchristos   obj->input_file = NULL;
7298b9484cSchristos   obj->read_output = NULL;
7398b9484cSchristos   obj->read_err = NULL;
7498b9484cSchristos   obj->remove_count = 0;
7598b9484cSchristos   obj->remove = NULL;
7698b9484cSchristos   obj->funcs = funcs;
7798b9484cSchristos   obj->sysdep = NULL;
7898b9484cSchristos   return obj;
7998b9484cSchristos }
8098b9484cSchristos 
8198b9484cSchristos /* Add a file to be removed when we are done.  */
8298b9484cSchristos 
8398b9484cSchristos static void
8498b9484cSchristos pex_add_remove (struct pex_obj *obj, const char *name, int allocated)
8598b9484cSchristos {
8698b9484cSchristos   char *add;
8798b9484cSchristos 
8898b9484cSchristos   ++obj->remove_count;
8998b9484cSchristos   obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count);
9098b9484cSchristos   if (allocated)
9198b9484cSchristos     add = (char *) name;
9298b9484cSchristos   else
9398b9484cSchristos     add = xstrdup (name);
9498b9484cSchristos   obj->remove[obj->remove_count - 1] = add;
9598b9484cSchristos }
9698b9484cSchristos 
9798b9484cSchristos /* Generate a temporary file name based on OBJ, FLAGS, and NAME.
9898b9484cSchristos    Return NULL if we were unable to reserve a temporary filename.
9998b9484cSchristos 
10098b9484cSchristos    If non-NULL, the result is either allocated with malloc, or the
10198b9484cSchristos    same pointer as NAME.  */
10298b9484cSchristos static char *
10398b9484cSchristos temp_file (struct pex_obj *obj, int flags, char *name)
10498b9484cSchristos {
10598b9484cSchristos   if (name == NULL)
10698b9484cSchristos     {
10798b9484cSchristos       if (obj->tempbase == NULL)
10898b9484cSchristos         {
10998b9484cSchristos           name = make_temp_file (NULL);
11098b9484cSchristos         }
11198b9484cSchristos       else
11298b9484cSchristos         {
11398b9484cSchristos           int len = strlen (obj->tempbase);
11498b9484cSchristos           int out;
11598b9484cSchristos 
11698b9484cSchristos           if (len >= 6
11798b9484cSchristos               && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
11898b9484cSchristos             name = xstrdup (obj->tempbase);
11998b9484cSchristos           else
12098b9484cSchristos             name = concat (obj->tempbase, "XXXXXX", NULL);
12198b9484cSchristos 
12298b9484cSchristos           out = mkstemps (name, 0);
12398b9484cSchristos           if (out < 0)
12498b9484cSchristos             {
12598b9484cSchristos               free (name);
12698b9484cSchristos               return NULL;
12798b9484cSchristos             }
12898b9484cSchristos 
12998b9484cSchristos           /* This isn't obj->funcs->close because we got the
13098b9484cSchristos              descriptor from mkstemps, not from a function in
13198b9484cSchristos              obj->funcs.  Calling close here is just like what
13298b9484cSchristos              make_temp_file does.  */
13398b9484cSchristos           close (out);
13498b9484cSchristos         }
13598b9484cSchristos     }
13698b9484cSchristos   else if ((flags & PEX_SUFFIX) != 0)
13798b9484cSchristos     {
13898b9484cSchristos       if (obj->tempbase == NULL)
13998b9484cSchristos         name = make_temp_file (name);
14098b9484cSchristos       else
14198b9484cSchristos         name = concat (obj->tempbase, name, NULL);
14298b9484cSchristos     }
14398b9484cSchristos 
14498b9484cSchristos   return name;
14598b9484cSchristos }
14698b9484cSchristos 
14798b9484cSchristos 
14898b9484cSchristos /* As for pex_run (), but permits the environment for the child process
14998b9484cSchristos    to be specified. */
15098b9484cSchristos 
15198b9484cSchristos const char *
15298b9484cSchristos pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
15398b9484cSchristos        	                char * const * argv, char * const * env,
15498b9484cSchristos                         const char *orig_outname, const char *errname,
15598b9484cSchristos                   	int *err)
15698b9484cSchristos {
15798b9484cSchristos   const char *errmsg;
15898b9484cSchristos   int in, out, errdes;
15998b9484cSchristos   char *outname;
16098b9484cSchristos   int outname_allocated;
16198b9484cSchristos   int p[2];
16298b9484cSchristos   int toclose;
16398b9484cSchristos   pid_t pid;
16498b9484cSchristos 
16598b9484cSchristos   in = -1;
16698b9484cSchristos   out = -1;
16798b9484cSchristos   errdes = -1;
16898b9484cSchristos   outname = (char *) orig_outname;
16998b9484cSchristos   outname_allocated = 0;
17098b9484cSchristos 
17198b9484cSchristos   /* If the user called pex_input_file, close the file now.  */
17298b9484cSchristos   if (obj->input_file)
17398b9484cSchristos     {
17498b9484cSchristos       if (fclose (obj->input_file) == EOF)
17598b9484cSchristos         {
17698b9484cSchristos           errmsg = "closing pipeline input file";
17798b9484cSchristos           goto error_exit;
17898b9484cSchristos         }
17998b9484cSchristos       obj->input_file = NULL;
18098b9484cSchristos     }
18198b9484cSchristos 
18298b9484cSchristos   /* Set IN.  */
18398b9484cSchristos 
18498b9484cSchristos   if (obj->next_input_name != NULL)
18598b9484cSchristos     {
18698b9484cSchristos       /* We have to make sure that the previous process has completed
18798b9484cSchristos 	 before we try to read the file.  */
18898b9484cSchristos       if (!pex_get_status_and_time (obj, 0, &errmsg, err))
18998b9484cSchristos 	goto error_exit;
19098b9484cSchristos 
19198b9484cSchristos       in = obj->funcs->open_read (obj, obj->next_input_name,
19298b9484cSchristos 				  (flags & PEX_BINARY_INPUT) != 0);
19398b9484cSchristos       if (in < 0)
19498b9484cSchristos 	{
19598b9484cSchristos 	  *err = errno;
19698b9484cSchristos 	  errmsg = "open temporary file";
19798b9484cSchristos 	  goto error_exit;
19898b9484cSchristos 	}
19998b9484cSchristos       if (obj->next_input_name_allocated)
20098b9484cSchristos 	{
20198b9484cSchristos 	  free (obj->next_input_name);
20298b9484cSchristos 	  obj->next_input_name_allocated = 0;
20398b9484cSchristos 	}
20498b9484cSchristos       obj->next_input_name = NULL;
20598b9484cSchristos     }
20698b9484cSchristos   else
20798b9484cSchristos     {
20898b9484cSchristos       in = obj->next_input;
20998b9484cSchristos       if (in < 0)
21098b9484cSchristos 	{
21198b9484cSchristos 	  *err = 0;
21298b9484cSchristos 	  errmsg = "pipeline already complete";
21398b9484cSchristos 	  goto error_exit;
21498b9484cSchristos 	}
21598b9484cSchristos     }
21698b9484cSchristos 
21798b9484cSchristos   /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME.  */
21898b9484cSchristos 
21998b9484cSchristos   if ((flags & PEX_LAST) != 0)
22098b9484cSchristos     {
22198b9484cSchristos       if (outname == NULL)
22298b9484cSchristos 	out = STDOUT_FILE_NO;
22398b9484cSchristos       else if ((flags & PEX_SUFFIX) != 0)
22498b9484cSchristos 	{
22598b9484cSchristos 	  outname = concat (obj->tempbase, outname, NULL);
22698b9484cSchristos 	  outname_allocated = 1;
22798b9484cSchristos 	}
22898b9484cSchristos       obj->next_input = -1;
22998b9484cSchristos     }
23098b9484cSchristos   else if ((obj->flags & PEX_USE_PIPES) == 0)
23198b9484cSchristos     {
23298b9484cSchristos       outname = temp_file (obj, flags, outname);
23398b9484cSchristos       if (! outname)
23498b9484cSchristos         {
23598b9484cSchristos           *err = 0;
23698b9484cSchristos           errmsg = "could not create temporary file";
23798b9484cSchristos           goto error_exit;
23898b9484cSchristos         }
23998b9484cSchristos 
24098b9484cSchristos       if (outname != orig_outname)
24198b9484cSchristos         outname_allocated = 1;
24298b9484cSchristos 
24398b9484cSchristos       if ((obj->flags & PEX_SAVE_TEMPS) == 0)
24498b9484cSchristos 	{
24598b9484cSchristos 	  pex_add_remove (obj, outname, outname_allocated);
24698b9484cSchristos 	  outname_allocated = 0;
24798b9484cSchristos 	}
24898b9484cSchristos 
24998b9484cSchristos       /* Hand off ownership of outname to the next stage.  */
25098b9484cSchristos       obj->next_input_name = outname;
25198b9484cSchristos       obj->next_input_name_allocated = outname_allocated;
25298b9484cSchristos       outname_allocated = 0;
25398b9484cSchristos     }
25498b9484cSchristos   else
25598b9484cSchristos     {
25698b9484cSchristos       if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
25798b9484cSchristos 	{
25898b9484cSchristos 	  *err = errno;
25998b9484cSchristos 	  errmsg = "pipe";
26098b9484cSchristos 	  goto error_exit;
26198b9484cSchristos 	}
26298b9484cSchristos 
26398b9484cSchristos       out = p[WRITE_PORT];
26498b9484cSchristos       obj->next_input = p[READ_PORT];
26598b9484cSchristos     }
26698b9484cSchristos 
26798b9484cSchristos   if (out < 0)
26898b9484cSchristos     {
26998b9484cSchristos       out = obj->funcs->open_write (obj, outname,
270837edd6bSchristos 				    (flags & PEX_BINARY_OUTPUT) != 0,
271837edd6bSchristos 				    (flags & PEX_STDOUT_APPEND) != 0);
27298b9484cSchristos       if (out < 0)
27398b9484cSchristos 	{
27498b9484cSchristos 	  *err = errno;
27598b9484cSchristos 	  errmsg = "open temporary output file";
27698b9484cSchristos 	  goto error_exit;
27798b9484cSchristos 	}
27898b9484cSchristos     }
27998b9484cSchristos 
28098b9484cSchristos   if (outname_allocated)
28198b9484cSchristos     {
28298b9484cSchristos       free (outname);
28398b9484cSchristos       outname_allocated = 0;
28498b9484cSchristos     }
28598b9484cSchristos 
28698b9484cSchristos   /* Set ERRDES.  */
28798b9484cSchristos 
28898b9484cSchristos   if (errname != NULL && (flags & PEX_STDERR_TO_PIPE) != 0)
28998b9484cSchristos     {
29098b9484cSchristos       *err = 0;
29198b9484cSchristos       errmsg = "both ERRNAME and PEX_STDERR_TO_PIPE specified.";
29298b9484cSchristos       goto error_exit;
29398b9484cSchristos     }
29498b9484cSchristos 
29598b9484cSchristos   if (obj->stderr_pipe != -1)
29698b9484cSchristos     {
29798b9484cSchristos       *err = 0;
29898b9484cSchristos       errmsg = "PEX_STDERR_TO_PIPE used in the middle of pipeline";
29998b9484cSchristos       goto error_exit;
30098b9484cSchristos     }
30198b9484cSchristos 
30298b9484cSchristos   if (errname == NULL)
30398b9484cSchristos     {
30498b9484cSchristos       if (flags & PEX_STDERR_TO_PIPE)
30598b9484cSchristos 	{
30698b9484cSchristos 	  if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_ERROR) != 0) < 0)
30798b9484cSchristos 	    {
30898b9484cSchristos 	      *err = errno;
30998b9484cSchristos 	      errmsg = "pipe";
31098b9484cSchristos 	      goto error_exit;
31198b9484cSchristos 	    }
31298b9484cSchristos 
31398b9484cSchristos 	  errdes = p[WRITE_PORT];
31498b9484cSchristos 	  obj->stderr_pipe = p[READ_PORT];
31598b9484cSchristos 	}
31698b9484cSchristos       else
31798b9484cSchristos 	{
31898b9484cSchristos 	  errdes = STDERR_FILE_NO;
31998b9484cSchristos 	}
32098b9484cSchristos     }
32198b9484cSchristos   else
32298b9484cSchristos     {
32398b9484cSchristos       errdes = obj->funcs->open_write (obj, errname,
324837edd6bSchristos 				       (flags & PEX_BINARY_ERROR) != 0,
325837edd6bSchristos 				       (flags & PEX_STDERR_APPEND) != 0);
32698b9484cSchristos       if (errdes < 0)
32798b9484cSchristos 	{
32898b9484cSchristos 	  *err = errno;
32998b9484cSchristos 	  errmsg = "open error file";
33098b9484cSchristos 	  goto error_exit;
33198b9484cSchristos 	}
33298b9484cSchristos     }
33398b9484cSchristos 
33498b9484cSchristos   /* If we are using pipes, the child process has to close the next
33598b9484cSchristos      input pipe.  */
33698b9484cSchristos 
33798b9484cSchristos   if ((obj->flags & PEX_USE_PIPES) == 0)
33898b9484cSchristos     toclose = -1;
33998b9484cSchristos   else
34098b9484cSchristos     toclose = obj->next_input;
34198b9484cSchristos 
34298b9484cSchristos   /* Run the program.  */
34398b9484cSchristos 
34498b9484cSchristos   pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
34598b9484cSchristos 				in, out, errdes, toclose, &errmsg, err);
34698b9484cSchristos   if (pid < 0)
34798b9484cSchristos     goto error_exit;
34898b9484cSchristos 
34998b9484cSchristos   ++obj->count;
35098b9484cSchristos   obj->children = XRESIZEVEC (pid_t, obj->children, obj->count);
35198b9484cSchristos   obj->children[obj->count - 1] = pid;
35298b9484cSchristos 
35398b9484cSchristos   return NULL;
35498b9484cSchristos 
35598b9484cSchristos  error_exit:
35698b9484cSchristos   if (in >= 0 && in != STDIN_FILE_NO)
35798b9484cSchristos     obj->funcs->close (obj, in);
35898b9484cSchristos   if (out >= 0 && out != STDOUT_FILE_NO)
35998b9484cSchristos     obj->funcs->close (obj, out);
36098b9484cSchristos   if (errdes >= 0 && errdes != STDERR_FILE_NO)
36198b9484cSchristos     obj->funcs->close (obj, errdes);
36298b9484cSchristos   if (outname_allocated)
36398b9484cSchristos     free (outname);
36498b9484cSchristos   return errmsg;
36598b9484cSchristos }
36698b9484cSchristos 
36798b9484cSchristos /* Run a program.  */
36898b9484cSchristos 
36998b9484cSchristos const char *
37098b9484cSchristos pex_run (struct pex_obj *obj, int flags, const char *executable,
37198b9484cSchristos        	 char * const * argv, const char *orig_outname, const char *errname,
37298b9484cSchristos          int *err)
37398b9484cSchristos {
37498b9484cSchristos   return pex_run_in_environment (obj, flags, executable, argv, NULL,
37598b9484cSchristos 				 orig_outname, errname, err);
37698b9484cSchristos }
37798b9484cSchristos 
37898b9484cSchristos /* Return a FILE pointer for a temporary file to fill with input for
37998b9484cSchristos    the pipeline.  */
38098b9484cSchristos FILE *
38198b9484cSchristos pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
38298b9484cSchristos {
38398b9484cSchristos   char *name = (char *) in_name;
38498b9484cSchristos   FILE *f;
38598b9484cSchristos 
38698b9484cSchristos   /* This must be called before the first pipeline stage is run, and
38798b9484cSchristos      there must not have been any other input selected.  */
38898b9484cSchristos   if (obj->count != 0
38998b9484cSchristos       || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
39098b9484cSchristos       || obj->next_input_name)
39198b9484cSchristos     {
39298b9484cSchristos       errno = EINVAL;
39398b9484cSchristos       return NULL;
39498b9484cSchristos     }
39598b9484cSchristos 
39698b9484cSchristos   name = temp_file (obj, flags, name);
39798b9484cSchristos   if (! name)
39898b9484cSchristos     return NULL;
39998b9484cSchristos 
40098b9484cSchristos   f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
40198b9484cSchristos   if (! f)
40298b9484cSchristos     {
40398b9484cSchristos       free (name);
40498b9484cSchristos       return NULL;
40598b9484cSchristos     }
40698b9484cSchristos 
40798b9484cSchristos   obj->input_file = f;
40898b9484cSchristos   obj->next_input_name = name;
40998b9484cSchristos   obj->next_input_name_allocated = (name != in_name);
41098b9484cSchristos 
41198b9484cSchristos   return f;
41298b9484cSchristos }
41398b9484cSchristos 
41498b9484cSchristos /* Return a stream for a pipe connected to the standard input of the
41598b9484cSchristos    first stage of the pipeline.  */
41698b9484cSchristos FILE *
41798b9484cSchristos pex_input_pipe (struct pex_obj *obj, int binary)
41898b9484cSchristos {
41998b9484cSchristos   int p[2];
42098b9484cSchristos   FILE *f;
42198b9484cSchristos 
42298b9484cSchristos   /* You must call pex_input_pipe before the first pex_run or pex_one.  */
42398b9484cSchristos   if (obj->count > 0)
42498b9484cSchristos     goto usage_error;
42598b9484cSchristos 
42698b9484cSchristos   /* You must be using pipes.  Implementations that don't support
42798b9484cSchristos      pipes clear this flag before calling pex_init_common.  */
42898b9484cSchristos   if (! (obj->flags & PEX_USE_PIPES))
42998b9484cSchristos     goto usage_error;
43098b9484cSchristos 
43198b9484cSchristos   /* If we have somehow already selected other input, that's a
43298b9484cSchristos      mistake.  */
43398b9484cSchristos   if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
43498b9484cSchristos       || obj->next_input_name)
43598b9484cSchristos     goto usage_error;
43698b9484cSchristos 
43798b9484cSchristos   if (obj->funcs->pipe (obj, p, binary != 0) < 0)
43898b9484cSchristos     return NULL;
43998b9484cSchristos 
44098b9484cSchristos   f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
44198b9484cSchristos   if (! f)
44298b9484cSchristos     {
44398b9484cSchristos       int saved_errno = errno;
44498b9484cSchristos       obj->funcs->close (obj, p[READ_PORT]);
44598b9484cSchristos       obj->funcs->close (obj, p[WRITE_PORT]);
44698b9484cSchristos       errno = saved_errno;
44798b9484cSchristos       return NULL;
44898b9484cSchristos     }
44998b9484cSchristos 
45098b9484cSchristos   obj->next_input = p[READ_PORT];
45198b9484cSchristos 
45298b9484cSchristos   return f;
45398b9484cSchristos 
45498b9484cSchristos  usage_error:
45598b9484cSchristos   errno = EINVAL;
45698b9484cSchristos   return NULL;
45798b9484cSchristos }
45898b9484cSchristos 
45998b9484cSchristos /* Return a FILE pointer for the output of the last program
46098b9484cSchristos    executed.  */
46198b9484cSchristos 
46298b9484cSchristos FILE *
46398b9484cSchristos pex_read_output (struct pex_obj *obj, int binary)
46498b9484cSchristos {
46598b9484cSchristos   if (obj->next_input_name != NULL)
46698b9484cSchristos     {
46798b9484cSchristos       const char *errmsg;
46898b9484cSchristos       int err;
46998b9484cSchristos 
47098b9484cSchristos       /* We have to make sure that the process has completed before we
47198b9484cSchristos 	 try to read the file.  */
47298b9484cSchristos       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
47398b9484cSchristos 	{
47498b9484cSchristos 	  errno = err;
47598b9484cSchristos 	  return NULL;
47698b9484cSchristos 	}
47798b9484cSchristos 
47898b9484cSchristos       obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
47998b9484cSchristos 
48098b9484cSchristos       if (obj->next_input_name_allocated)
48198b9484cSchristos 	{
48298b9484cSchristos 	  free (obj->next_input_name);
48398b9484cSchristos 	  obj->next_input_name_allocated = 0;
48498b9484cSchristos 	}
48598b9484cSchristos       obj->next_input_name = NULL;
48698b9484cSchristos     }
48798b9484cSchristos   else
48898b9484cSchristos     {
48998b9484cSchristos       int o;
49098b9484cSchristos 
49198b9484cSchristos       o = obj->next_input;
49298b9484cSchristos       if (o < 0 || o == STDIN_FILE_NO)
49398b9484cSchristos 	return NULL;
49498b9484cSchristos       obj->read_output = obj->funcs->fdopenr (obj, o, binary);
49598b9484cSchristos       obj->next_input = -1;
49698b9484cSchristos     }
49798b9484cSchristos 
49898b9484cSchristos   return obj->read_output;
49998b9484cSchristos }
50098b9484cSchristos 
50198b9484cSchristos FILE *
50298b9484cSchristos pex_read_err (struct pex_obj *obj, int binary)
50398b9484cSchristos {
50498b9484cSchristos   int o;
50598b9484cSchristos 
50698b9484cSchristos   o = obj->stderr_pipe;
50798b9484cSchristos   if (o < 0 || o == STDIN_FILE_NO)
50898b9484cSchristos     return NULL;
50998b9484cSchristos   obj->read_err = obj->funcs->fdopenr (obj, o, binary);
51098b9484cSchristos   obj->stderr_pipe = -1;
51198b9484cSchristos   return obj->read_err;
51298b9484cSchristos }
51398b9484cSchristos 
51498b9484cSchristos /* Get the exit status and, if requested, the resource time for all
51598b9484cSchristos    the child processes.  Return 0 on failure, 1 on success.  */
51698b9484cSchristos 
51798b9484cSchristos static int
51898b9484cSchristos pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
51998b9484cSchristos 			 int *err)
52098b9484cSchristos {
52198b9484cSchristos   int ret;
52298b9484cSchristos   int i;
52398b9484cSchristos 
52498b9484cSchristos   if (obj->number_waited == obj->count)
52598b9484cSchristos     return 1;
52698b9484cSchristos 
52798b9484cSchristos   obj->status = XRESIZEVEC (int, obj->status, obj->count);
52898b9484cSchristos   if ((obj->flags & PEX_RECORD_TIMES) != 0)
52998b9484cSchristos     obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
53098b9484cSchristos 
53198b9484cSchristos   ret = 1;
53298b9484cSchristos   for (i = obj->number_waited; i < obj->count; ++i)
53398b9484cSchristos     {
53498b9484cSchristos       if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
53598b9484cSchristos 			    obj->time == NULL ? NULL : &obj->time[i],
53698b9484cSchristos 			    done, errmsg, err) < 0)
53798b9484cSchristos 	ret = 0;
53898b9484cSchristos     }
53998b9484cSchristos   obj->number_waited = i;
54098b9484cSchristos 
54198b9484cSchristos   return ret;
54298b9484cSchristos }
54398b9484cSchristos 
54498b9484cSchristos /* Get exit status of executed programs.  */
54598b9484cSchristos 
54698b9484cSchristos int
54798b9484cSchristos pex_get_status (struct pex_obj *obj, int count, int *vector)
54898b9484cSchristos {
54998b9484cSchristos   if (obj->status == NULL)
55098b9484cSchristos     {
55198b9484cSchristos       const char *errmsg;
55298b9484cSchristos       int err;
55398b9484cSchristos 
55498b9484cSchristos       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
55598b9484cSchristos 	return 0;
55698b9484cSchristos     }
55798b9484cSchristos 
55898b9484cSchristos   if (count > obj->count)
55998b9484cSchristos     {
56098b9484cSchristos       memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
56198b9484cSchristos       count = obj->count;
56298b9484cSchristos     }
56398b9484cSchristos 
56498b9484cSchristos   memcpy (vector, obj->status, count * sizeof (int));
56598b9484cSchristos 
56698b9484cSchristos   return 1;
56798b9484cSchristos }
56898b9484cSchristos 
56998b9484cSchristos /* Get process times of executed programs.  */
57098b9484cSchristos 
57198b9484cSchristos int
57298b9484cSchristos pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
57398b9484cSchristos {
57498b9484cSchristos   if (obj->status == NULL)
57598b9484cSchristos     {
57698b9484cSchristos       const char *errmsg;
57798b9484cSchristos       int err;
57898b9484cSchristos 
57998b9484cSchristos       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
58098b9484cSchristos 	return 0;
58198b9484cSchristos     }
58298b9484cSchristos 
58398b9484cSchristos   if (obj->time == NULL)
58498b9484cSchristos     return 0;
58598b9484cSchristos 
58698b9484cSchristos   if (count > obj->count)
58798b9484cSchristos     {
58898b9484cSchristos       memset (vector + obj->count, 0,
58998b9484cSchristos 	      (count - obj->count) * sizeof (struct pex_time));
59098b9484cSchristos       count = obj->count;
59198b9484cSchristos     }
59298b9484cSchristos 
59398b9484cSchristos   memcpy (vector, obj->time, count * sizeof (struct pex_time));
59498b9484cSchristos 
59598b9484cSchristos   return 1;
59698b9484cSchristos }
59798b9484cSchristos 
59898b9484cSchristos /* Free a pex_obj structure.  */
59998b9484cSchristos 
60098b9484cSchristos void
60198b9484cSchristos pex_free (struct pex_obj *obj)
60298b9484cSchristos {
60398b9484cSchristos   /* Close pipe file descriptors corresponding to child's stdout and
60498b9484cSchristos      stderr so that the child does not hang trying to output something
60598b9484cSchristos      while we're waiting for it.  */
60698b9484cSchristos   if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
60798b9484cSchristos     obj->funcs->close (obj, obj->next_input);
60898b9484cSchristos   if (obj->stderr_pipe >= 0 && obj->stderr_pipe != STDIN_FILE_NO)
60998b9484cSchristos     obj->funcs->close (obj, obj->stderr_pipe);
61098b9484cSchristos   if (obj->read_output != NULL)
61198b9484cSchristos     fclose (obj->read_output);
61298b9484cSchristos   if (obj->read_err != NULL)
61398b9484cSchristos     fclose (obj->read_err);
61498b9484cSchristos 
61598b9484cSchristos   /* If the caller forgot to wait for the children, we do it here, to
61698b9484cSchristos      avoid zombies.  */
61798b9484cSchristos   if (obj->status == NULL)
61898b9484cSchristos     {
61998b9484cSchristos       const char *errmsg;
62098b9484cSchristos       int err;
62198b9484cSchristos 
62298b9484cSchristos       obj->flags &= ~ PEX_RECORD_TIMES;
62398b9484cSchristos       pex_get_status_and_time (obj, 1, &errmsg, &err);
62498b9484cSchristos     }
62598b9484cSchristos 
62698b9484cSchristos   if (obj->next_input_name_allocated)
62798b9484cSchristos     free (obj->next_input_name);
62898b9484cSchristos   free (obj->children);
62998b9484cSchristos   free (obj->status);
63098b9484cSchristos   free (obj->time);
63198b9484cSchristos 
63298b9484cSchristos   if (obj->remove_count > 0)
63398b9484cSchristos     {
63498b9484cSchristos       int i;
63598b9484cSchristos 
63698b9484cSchristos       for (i = 0; i < obj->remove_count; ++i)
63798b9484cSchristos 	{
63898b9484cSchristos 	  remove (obj->remove[i]);
63998b9484cSchristos 	  free (obj->remove[i]);
64098b9484cSchristos 	}
64198b9484cSchristos       free (obj->remove);
64298b9484cSchristos     }
64398b9484cSchristos 
64498b9484cSchristos   if (obj->funcs->cleanup != NULL)
64598b9484cSchristos     obj->funcs->cleanup (obj);
64698b9484cSchristos 
64798b9484cSchristos   free (obj);
64898b9484cSchristos }
649