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