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