15796c8dcSSimon Schubert /* Common code for executing a program in a sub-process.
2*c50c785cSJohn Marino Copyright (C) 2005, 2010 Free Software Foundation, Inc.
35796c8dcSSimon Schubert Written by Ian Lance Taylor <ian@airs.com>.
45796c8dcSSimon Schubert
55796c8dcSSimon Schubert This file is part of the libiberty library.
65796c8dcSSimon Schubert Libiberty is free software; you can redistribute it and/or
75796c8dcSSimon Schubert modify it under the terms of the GNU Library General Public
85796c8dcSSimon Schubert License as published by the Free Software Foundation; either
95796c8dcSSimon Schubert version 2 of the License, or (at your option) any later version.
105796c8dcSSimon Schubert
115796c8dcSSimon Schubert Libiberty is distributed in the hope that it will be useful,
125796c8dcSSimon Schubert but WITHOUT ANY WARRANTY; without even the implied warranty of
135796c8dcSSimon Schubert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
145796c8dcSSimon Schubert Library General Public License for more details.
155796c8dcSSimon Schubert
165796c8dcSSimon Schubert You should have received a copy of the GNU Library General Public
175796c8dcSSimon Schubert License along with libiberty; see the file COPYING.LIB. If not,
185796c8dcSSimon Schubert write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
195796c8dcSSimon Schubert Boston, MA 02110-1301, USA. */
205796c8dcSSimon Schubert
215796c8dcSSimon Schubert #include "config.h"
225796c8dcSSimon Schubert #include "libiberty.h"
235796c8dcSSimon Schubert #include "pex-common.h"
245796c8dcSSimon Schubert
255796c8dcSSimon Schubert #include <stdio.h>
265796c8dcSSimon Schubert #include <errno.h>
275796c8dcSSimon Schubert #ifdef NEED_DECLARATION_ERRNO
285796c8dcSSimon Schubert extern int errno;
295796c8dcSSimon Schubert #endif
305796c8dcSSimon Schubert #ifdef HAVE_STDLIB_H
315796c8dcSSimon Schubert #include <stdlib.h>
325796c8dcSSimon Schubert #endif
335796c8dcSSimon Schubert #ifdef HAVE_STRING_H
345796c8dcSSimon Schubert #include <string.h>
355796c8dcSSimon Schubert #endif
365796c8dcSSimon Schubert #ifdef HAVE_UNISTD_H
375796c8dcSSimon Schubert #include <unistd.h>
385796c8dcSSimon Schubert #endif
395796c8dcSSimon Schubert
405796c8dcSSimon Schubert extern int mkstemps (char *, int);
415796c8dcSSimon Schubert
425796c8dcSSimon Schubert /* This file contains subroutines for the program execution routines
435796c8dcSSimon Schubert (pex_init, pex_run, etc.). This file is compiled on all
445796c8dcSSimon Schubert systems. */
455796c8dcSSimon Schubert
465796c8dcSSimon Schubert static void pex_add_remove (struct pex_obj *, const char *, int);
475796c8dcSSimon Schubert static int pex_get_status_and_time (struct pex_obj *, int, const char **,
485796c8dcSSimon Schubert int *);
495796c8dcSSimon Schubert
505796c8dcSSimon Schubert /* Initialize a pex_obj structure. */
515796c8dcSSimon Schubert
525796c8dcSSimon Schubert struct pex_obj *
pex_init_common(int flags,const char * pname,const char * tempbase,const struct pex_funcs * funcs)535796c8dcSSimon Schubert pex_init_common (int flags, const char *pname, const char *tempbase,
545796c8dcSSimon Schubert const struct pex_funcs *funcs)
555796c8dcSSimon Schubert {
565796c8dcSSimon Schubert struct pex_obj *obj;
575796c8dcSSimon Schubert
585796c8dcSSimon Schubert obj = XNEW (struct pex_obj);
595796c8dcSSimon Schubert obj->flags = flags;
605796c8dcSSimon Schubert obj->pname = pname;
615796c8dcSSimon Schubert obj->tempbase = tempbase;
625796c8dcSSimon Schubert obj->next_input = STDIN_FILE_NO;
635796c8dcSSimon Schubert obj->next_input_name = NULL;
645796c8dcSSimon Schubert obj->next_input_name_allocated = 0;
655796c8dcSSimon Schubert obj->stderr_pipe = -1;
665796c8dcSSimon Schubert obj->count = 0;
675796c8dcSSimon Schubert obj->children = NULL;
685796c8dcSSimon Schubert obj->status = NULL;
695796c8dcSSimon Schubert obj->time = NULL;
705796c8dcSSimon Schubert obj->number_waited = 0;
715796c8dcSSimon Schubert obj->input_file = NULL;
725796c8dcSSimon Schubert obj->read_output = NULL;
735796c8dcSSimon Schubert obj->read_err = NULL;
745796c8dcSSimon Schubert obj->remove_count = 0;
755796c8dcSSimon Schubert obj->remove = NULL;
765796c8dcSSimon Schubert obj->funcs = funcs;
775796c8dcSSimon Schubert obj->sysdep = NULL;
785796c8dcSSimon Schubert return obj;
795796c8dcSSimon Schubert }
805796c8dcSSimon Schubert
815796c8dcSSimon Schubert /* Add a file to be removed when we are done. */
825796c8dcSSimon Schubert
835796c8dcSSimon Schubert static void
pex_add_remove(struct pex_obj * obj,const char * name,int allocated)845796c8dcSSimon Schubert pex_add_remove (struct pex_obj *obj, const char *name, int allocated)
855796c8dcSSimon Schubert {
865796c8dcSSimon Schubert char *add;
875796c8dcSSimon Schubert
885796c8dcSSimon Schubert ++obj->remove_count;
895796c8dcSSimon Schubert obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count);
905796c8dcSSimon Schubert if (allocated)
915796c8dcSSimon Schubert add = (char *) name;
925796c8dcSSimon Schubert else
935796c8dcSSimon Schubert add = xstrdup (name);
945796c8dcSSimon Schubert obj->remove[obj->remove_count - 1] = add;
955796c8dcSSimon Schubert }
965796c8dcSSimon Schubert
975796c8dcSSimon Schubert /* Generate a temporary file name based on OBJ, FLAGS, and NAME.
985796c8dcSSimon Schubert Return NULL if we were unable to reserve a temporary filename.
995796c8dcSSimon Schubert
1005796c8dcSSimon Schubert If non-NULL, the result is either allocated with malloc, or the
1015796c8dcSSimon Schubert same pointer as NAME. */
1025796c8dcSSimon Schubert static char *
temp_file(struct pex_obj * obj,int flags,char * name)1035796c8dcSSimon Schubert temp_file (struct pex_obj *obj, int flags, char *name)
1045796c8dcSSimon Schubert {
1055796c8dcSSimon Schubert if (name == NULL)
1065796c8dcSSimon Schubert {
1075796c8dcSSimon Schubert if (obj->tempbase == NULL)
1085796c8dcSSimon Schubert {
1095796c8dcSSimon Schubert name = make_temp_file (NULL);
1105796c8dcSSimon Schubert }
1115796c8dcSSimon Schubert else
1125796c8dcSSimon Schubert {
1135796c8dcSSimon Schubert int len = strlen (obj->tempbase);
1145796c8dcSSimon Schubert int out;
1155796c8dcSSimon Schubert
1165796c8dcSSimon Schubert if (len >= 6
1175796c8dcSSimon Schubert && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
1185796c8dcSSimon Schubert name = xstrdup (obj->tempbase);
1195796c8dcSSimon Schubert else
1205796c8dcSSimon Schubert name = concat (obj->tempbase, "XXXXXX", NULL);
1215796c8dcSSimon Schubert
1225796c8dcSSimon Schubert out = mkstemps (name, 0);
1235796c8dcSSimon Schubert if (out < 0)
1245796c8dcSSimon Schubert {
1255796c8dcSSimon Schubert free (name);
1265796c8dcSSimon Schubert return NULL;
1275796c8dcSSimon Schubert }
1285796c8dcSSimon Schubert
1295796c8dcSSimon Schubert /* This isn't obj->funcs->close because we got the
1305796c8dcSSimon Schubert descriptor from mkstemps, not from a function in
1315796c8dcSSimon Schubert obj->funcs. Calling close here is just like what
1325796c8dcSSimon Schubert make_temp_file does. */
1335796c8dcSSimon Schubert close (out);
1345796c8dcSSimon Schubert }
1355796c8dcSSimon Schubert }
1365796c8dcSSimon Schubert else if ((flags & PEX_SUFFIX) != 0)
1375796c8dcSSimon Schubert {
1385796c8dcSSimon Schubert if (obj->tempbase == NULL)
1395796c8dcSSimon Schubert name = make_temp_file (name);
1405796c8dcSSimon Schubert else
1415796c8dcSSimon Schubert name = concat (obj->tempbase, name, NULL);
1425796c8dcSSimon Schubert }
1435796c8dcSSimon Schubert
1445796c8dcSSimon Schubert return name;
1455796c8dcSSimon Schubert }
1465796c8dcSSimon Schubert
1475796c8dcSSimon Schubert
1485796c8dcSSimon Schubert /* As for pex_run (), but permits the environment for the child process
1495796c8dcSSimon Schubert to be specified. */
1505796c8dcSSimon Schubert
1515796c8dcSSimon Schubert 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)1525796c8dcSSimon Schubert pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
1535796c8dcSSimon Schubert char * const * argv, char * const * env,
1545796c8dcSSimon Schubert const char *orig_outname, const char *errname,
1555796c8dcSSimon Schubert int *err)
1565796c8dcSSimon Schubert {
1575796c8dcSSimon Schubert const char *errmsg;
1585796c8dcSSimon Schubert int in, out, errdes;
1595796c8dcSSimon Schubert char *outname;
1605796c8dcSSimon Schubert int outname_allocated;
1615796c8dcSSimon Schubert int p[2];
1625796c8dcSSimon Schubert int toclose;
1635796c8dcSSimon Schubert pid_t pid;
1645796c8dcSSimon Schubert
1655796c8dcSSimon Schubert in = -1;
1665796c8dcSSimon Schubert out = -1;
1675796c8dcSSimon Schubert errdes = -1;
1685796c8dcSSimon Schubert outname = (char *) orig_outname;
1695796c8dcSSimon Schubert outname_allocated = 0;
1705796c8dcSSimon Schubert
1715796c8dcSSimon Schubert /* If the user called pex_input_file, close the file now. */
1725796c8dcSSimon Schubert if (obj->input_file)
1735796c8dcSSimon Schubert {
1745796c8dcSSimon Schubert if (fclose (obj->input_file) == EOF)
1755796c8dcSSimon Schubert {
1765796c8dcSSimon Schubert errmsg = "closing pipeline input file";
1775796c8dcSSimon Schubert goto error_exit;
1785796c8dcSSimon Schubert }
1795796c8dcSSimon Schubert obj->input_file = NULL;
1805796c8dcSSimon Schubert }
1815796c8dcSSimon Schubert
1825796c8dcSSimon Schubert /* Set IN. */
1835796c8dcSSimon Schubert
1845796c8dcSSimon Schubert if (obj->next_input_name != NULL)
1855796c8dcSSimon Schubert {
1865796c8dcSSimon Schubert /* We have to make sure that the previous process has completed
1875796c8dcSSimon Schubert before we try to read the file. */
1885796c8dcSSimon Schubert if (!pex_get_status_and_time (obj, 0, &errmsg, err))
1895796c8dcSSimon Schubert goto error_exit;
1905796c8dcSSimon Schubert
1915796c8dcSSimon Schubert in = obj->funcs->open_read (obj, obj->next_input_name,
1925796c8dcSSimon Schubert (flags & PEX_BINARY_INPUT) != 0);
1935796c8dcSSimon Schubert if (in < 0)
1945796c8dcSSimon Schubert {
1955796c8dcSSimon Schubert *err = errno;
1965796c8dcSSimon Schubert errmsg = "open temporary file";
1975796c8dcSSimon Schubert goto error_exit;
1985796c8dcSSimon Schubert }
1995796c8dcSSimon Schubert if (obj->next_input_name_allocated)
2005796c8dcSSimon Schubert {
2015796c8dcSSimon Schubert free (obj->next_input_name);
2025796c8dcSSimon Schubert obj->next_input_name_allocated = 0;
2035796c8dcSSimon Schubert }
2045796c8dcSSimon Schubert obj->next_input_name = NULL;
2055796c8dcSSimon Schubert }
2065796c8dcSSimon Schubert else
2075796c8dcSSimon Schubert {
2085796c8dcSSimon Schubert in = obj->next_input;
2095796c8dcSSimon Schubert if (in < 0)
2105796c8dcSSimon Schubert {
2115796c8dcSSimon Schubert *err = 0;
2125796c8dcSSimon Schubert errmsg = "pipeline already complete";
2135796c8dcSSimon Schubert goto error_exit;
2145796c8dcSSimon Schubert }
2155796c8dcSSimon Schubert }
2165796c8dcSSimon Schubert
2175796c8dcSSimon Schubert /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME. */
2185796c8dcSSimon Schubert
2195796c8dcSSimon Schubert if ((flags & PEX_LAST) != 0)
2205796c8dcSSimon Schubert {
2215796c8dcSSimon Schubert if (outname == NULL)
2225796c8dcSSimon Schubert out = STDOUT_FILE_NO;
2235796c8dcSSimon Schubert else if ((flags & PEX_SUFFIX) != 0)
2245796c8dcSSimon Schubert {
2255796c8dcSSimon Schubert outname = concat (obj->tempbase, outname, NULL);
2265796c8dcSSimon Schubert outname_allocated = 1;
2275796c8dcSSimon Schubert }
2285796c8dcSSimon Schubert obj->next_input = -1;
2295796c8dcSSimon Schubert }
2305796c8dcSSimon Schubert else if ((obj->flags & PEX_USE_PIPES) == 0)
2315796c8dcSSimon Schubert {
2325796c8dcSSimon Schubert outname = temp_file (obj, flags, outname);
2335796c8dcSSimon Schubert if (! outname)
2345796c8dcSSimon Schubert {
2355796c8dcSSimon Schubert *err = 0;
2365796c8dcSSimon Schubert errmsg = "could not create temporary file";
2375796c8dcSSimon Schubert goto error_exit;
2385796c8dcSSimon Schubert }
2395796c8dcSSimon Schubert
2405796c8dcSSimon Schubert if (outname != orig_outname)
2415796c8dcSSimon Schubert outname_allocated = 1;
2425796c8dcSSimon Schubert
2435796c8dcSSimon Schubert if ((obj->flags & PEX_SAVE_TEMPS) == 0)
2445796c8dcSSimon Schubert {
2455796c8dcSSimon Schubert pex_add_remove (obj, outname, outname_allocated);
2465796c8dcSSimon Schubert outname_allocated = 0;
2475796c8dcSSimon Schubert }
2485796c8dcSSimon Schubert
2495796c8dcSSimon Schubert /* Hand off ownership of outname to the next stage. */
2505796c8dcSSimon Schubert obj->next_input_name = outname;
2515796c8dcSSimon Schubert obj->next_input_name_allocated = outname_allocated;
2525796c8dcSSimon Schubert outname_allocated = 0;
2535796c8dcSSimon Schubert }
2545796c8dcSSimon Schubert else
2555796c8dcSSimon Schubert {
2565796c8dcSSimon Schubert if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
2575796c8dcSSimon Schubert {
2585796c8dcSSimon Schubert *err = errno;
2595796c8dcSSimon Schubert errmsg = "pipe";
2605796c8dcSSimon Schubert goto error_exit;
2615796c8dcSSimon Schubert }
2625796c8dcSSimon Schubert
2635796c8dcSSimon Schubert out = p[WRITE_PORT];
2645796c8dcSSimon Schubert obj->next_input = p[READ_PORT];
2655796c8dcSSimon Schubert }
2665796c8dcSSimon Schubert
2675796c8dcSSimon Schubert if (out < 0)
2685796c8dcSSimon Schubert {
2695796c8dcSSimon Schubert out = obj->funcs->open_write (obj, outname,
2705796c8dcSSimon Schubert (flags & PEX_BINARY_OUTPUT) != 0);
2715796c8dcSSimon Schubert if (out < 0)
2725796c8dcSSimon Schubert {
2735796c8dcSSimon Schubert *err = errno;
2745796c8dcSSimon Schubert errmsg = "open temporary output file";
2755796c8dcSSimon Schubert goto error_exit;
2765796c8dcSSimon Schubert }
2775796c8dcSSimon Schubert }
2785796c8dcSSimon Schubert
2795796c8dcSSimon Schubert if (outname_allocated)
2805796c8dcSSimon Schubert {
2815796c8dcSSimon Schubert free (outname);
2825796c8dcSSimon Schubert outname_allocated = 0;
2835796c8dcSSimon Schubert }
2845796c8dcSSimon Schubert
2855796c8dcSSimon Schubert /* Set ERRDES. */
2865796c8dcSSimon Schubert
2875796c8dcSSimon Schubert if (errname != NULL && (flags & PEX_STDERR_TO_PIPE) != 0)
2885796c8dcSSimon Schubert {
2895796c8dcSSimon Schubert *err = 0;
2905796c8dcSSimon Schubert errmsg = "both ERRNAME and PEX_STDERR_TO_PIPE specified.";
2915796c8dcSSimon Schubert goto error_exit;
2925796c8dcSSimon Schubert }
2935796c8dcSSimon Schubert
2945796c8dcSSimon Schubert if (obj->stderr_pipe != -1)
2955796c8dcSSimon Schubert {
2965796c8dcSSimon Schubert *err = 0;
2975796c8dcSSimon Schubert errmsg = "PEX_STDERR_TO_PIPE used in the middle of pipeline";
2985796c8dcSSimon Schubert goto error_exit;
2995796c8dcSSimon Schubert }
3005796c8dcSSimon Schubert
3015796c8dcSSimon Schubert if (errname == NULL)
3025796c8dcSSimon Schubert {
3035796c8dcSSimon Schubert if (flags & PEX_STDERR_TO_PIPE)
3045796c8dcSSimon Schubert {
3055796c8dcSSimon Schubert if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_ERROR) != 0) < 0)
3065796c8dcSSimon Schubert {
3075796c8dcSSimon Schubert *err = errno;
3085796c8dcSSimon Schubert errmsg = "pipe";
3095796c8dcSSimon Schubert goto error_exit;
3105796c8dcSSimon Schubert }
3115796c8dcSSimon Schubert
3125796c8dcSSimon Schubert errdes = p[WRITE_PORT];
3135796c8dcSSimon Schubert obj->stderr_pipe = p[READ_PORT];
3145796c8dcSSimon Schubert }
3155796c8dcSSimon Schubert else
3165796c8dcSSimon Schubert {
3175796c8dcSSimon Schubert errdes = STDERR_FILE_NO;
3185796c8dcSSimon Schubert }
3195796c8dcSSimon Schubert }
3205796c8dcSSimon Schubert else
3215796c8dcSSimon Schubert {
3225796c8dcSSimon Schubert errdes = obj->funcs->open_write (obj, errname,
3235796c8dcSSimon Schubert (flags & PEX_BINARY_ERROR) != 0);
3245796c8dcSSimon Schubert if (errdes < 0)
3255796c8dcSSimon Schubert {
3265796c8dcSSimon Schubert *err = errno;
3275796c8dcSSimon Schubert errmsg = "open error file";
3285796c8dcSSimon Schubert goto error_exit;
3295796c8dcSSimon Schubert }
3305796c8dcSSimon Schubert }
3315796c8dcSSimon Schubert
3325796c8dcSSimon Schubert /* If we are using pipes, the child process has to close the next
3335796c8dcSSimon Schubert input pipe. */
3345796c8dcSSimon Schubert
3355796c8dcSSimon Schubert if ((obj->flags & PEX_USE_PIPES) == 0)
3365796c8dcSSimon Schubert toclose = -1;
3375796c8dcSSimon Schubert else
3385796c8dcSSimon Schubert toclose = obj->next_input;
3395796c8dcSSimon Schubert
3405796c8dcSSimon Schubert /* Run the program. */
3415796c8dcSSimon Schubert
3425796c8dcSSimon Schubert pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
3435796c8dcSSimon Schubert in, out, errdes, toclose, &errmsg, err);
3445796c8dcSSimon Schubert if (pid < 0)
3455796c8dcSSimon Schubert goto error_exit;
3465796c8dcSSimon Schubert
3475796c8dcSSimon Schubert ++obj->count;
3485796c8dcSSimon Schubert obj->children = XRESIZEVEC (pid_t, obj->children, obj->count);
3495796c8dcSSimon Schubert obj->children[obj->count - 1] = pid;
3505796c8dcSSimon Schubert
3515796c8dcSSimon Schubert return NULL;
3525796c8dcSSimon Schubert
3535796c8dcSSimon Schubert error_exit:
3545796c8dcSSimon Schubert if (in >= 0 && in != STDIN_FILE_NO)
3555796c8dcSSimon Schubert obj->funcs->close (obj, in);
3565796c8dcSSimon Schubert if (out >= 0 && out != STDOUT_FILE_NO)
3575796c8dcSSimon Schubert obj->funcs->close (obj, out);
3585796c8dcSSimon Schubert if (errdes >= 0 && errdes != STDERR_FILE_NO)
3595796c8dcSSimon Schubert obj->funcs->close (obj, errdes);
3605796c8dcSSimon Schubert if (outname_allocated)
3615796c8dcSSimon Schubert free (outname);
3625796c8dcSSimon Schubert return errmsg;
3635796c8dcSSimon Schubert }
3645796c8dcSSimon Schubert
3655796c8dcSSimon Schubert /* Run a program. */
3665796c8dcSSimon Schubert
3675796c8dcSSimon Schubert 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)3685796c8dcSSimon Schubert pex_run (struct pex_obj *obj, int flags, const char *executable,
3695796c8dcSSimon Schubert char * const * argv, const char *orig_outname, const char *errname,
3705796c8dcSSimon Schubert int *err)
3715796c8dcSSimon Schubert {
3725796c8dcSSimon Schubert return pex_run_in_environment (obj, flags, executable, argv, NULL,
3735796c8dcSSimon Schubert orig_outname, errname, err);
3745796c8dcSSimon Schubert }
3755796c8dcSSimon Schubert
3765796c8dcSSimon Schubert /* Return a FILE pointer for a temporary file to fill with input for
3775796c8dcSSimon Schubert the pipeline. */
3785796c8dcSSimon Schubert FILE *
pex_input_file(struct pex_obj * obj,int flags,const char * in_name)3795796c8dcSSimon Schubert pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
3805796c8dcSSimon Schubert {
3815796c8dcSSimon Schubert char *name = (char *) in_name;
3825796c8dcSSimon Schubert FILE *f;
3835796c8dcSSimon Schubert
3845796c8dcSSimon Schubert /* This must be called before the first pipeline stage is run, and
3855796c8dcSSimon Schubert there must not have been any other input selected. */
3865796c8dcSSimon Schubert if (obj->count != 0
3875796c8dcSSimon Schubert || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
3885796c8dcSSimon Schubert || obj->next_input_name)
3895796c8dcSSimon Schubert {
3905796c8dcSSimon Schubert errno = EINVAL;
3915796c8dcSSimon Schubert return NULL;
3925796c8dcSSimon Schubert }
3935796c8dcSSimon Schubert
3945796c8dcSSimon Schubert name = temp_file (obj, flags, name);
3955796c8dcSSimon Schubert if (! name)
3965796c8dcSSimon Schubert return NULL;
3975796c8dcSSimon Schubert
3985796c8dcSSimon Schubert f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
3995796c8dcSSimon Schubert if (! f)
4005796c8dcSSimon Schubert {
4015796c8dcSSimon Schubert free (name);
4025796c8dcSSimon Schubert return NULL;
4035796c8dcSSimon Schubert }
4045796c8dcSSimon Schubert
4055796c8dcSSimon Schubert obj->input_file = f;
4065796c8dcSSimon Schubert obj->next_input_name = name;
4075796c8dcSSimon Schubert obj->next_input_name_allocated = (name != in_name);
4085796c8dcSSimon Schubert
4095796c8dcSSimon Schubert return f;
4105796c8dcSSimon Schubert }
4115796c8dcSSimon Schubert
4125796c8dcSSimon Schubert /* Return a stream for a pipe connected to the standard input of the
4135796c8dcSSimon Schubert first stage of the pipeline. */
4145796c8dcSSimon Schubert FILE *
pex_input_pipe(struct pex_obj * obj,int binary)4155796c8dcSSimon Schubert pex_input_pipe (struct pex_obj *obj, int binary)
4165796c8dcSSimon Schubert {
4175796c8dcSSimon Schubert int p[2];
4185796c8dcSSimon Schubert FILE *f;
4195796c8dcSSimon Schubert
4205796c8dcSSimon Schubert /* You must call pex_input_pipe before the first pex_run or pex_one. */
4215796c8dcSSimon Schubert if (obj->count > 0)
4225796c8dcSSimon Schubert goto usage_error;
4235796c8dcSSimon Schubert
4245796c8dcSSimon Schubert /* You must be using pipes. Implementations that don't support
4255796c8dcSSimon Schubert pipes clear this flag before calling pex_init_common. */
4265796c8dcSSimon Schubert if (! (obj->flags & PEX_USE_PIPES))
4275796c8dcSSimon Schubert goto usage_error;
4285796c8dcSSimon Schubert
4295796c8dcSSimon Schubert /* If we have somehow already selected other input, that's a
4305796c8dcSSimon Schubert mistake. */
4315796c8dcSSimon Schubert if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
4325796c8dcSSimon Schubert || obj->next_input_name)
4335796c8dcSSimon Schubert goto usage_error;
4345796c8dcSSimon Schubert
4355796c8dcSSimon Schubert if (obj->funcs->pipe (obj, p, binary != 0) < 0)
4365796c8dcSSimon Schubert return NULL;
4375796c8dcSSimon Schubert
4385796c8dcSSimon Schubert f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
4395796c8dcSSimon Schubert if (! f)
4405796c8dcSSimon Schubert {
4415796c8dcSSimon Schubert int saved_errno = errno;
4425796c8dcSSimon Schubert obj->funcs->close (obj, p[READ_PORT]);
4435796c8dcSSimon Schubert obj->funcs->close (obj, p[WRITE_PORT]);
4445796c8dcSSimon Schubert errno = saved_errno;
4455796c8dcSSimon Schubert return NULL;
4465796c8dcSSimon Schubert }
4475796c8dcSSimon Schubert
4485796c8dcSSimon Schubert obj->next_input = p[READ_PORT];
4495796c8dcSSimon Schubert
4505796c8dcSSimon Schubert return f;
4515796c8dcSSimon Schubert
4525796c8dcSSimon Schubert usage_error:
4535796c8dcSSimon Schubert errno = EINVAL;
4545796c8dcSSimon Schubert return NULL;
4555796c8dcSSimon Schubert }
4565796c8dcSSimon Schubert
4575796c8dcSSimon Schubert /* Return a FILE pointer for the output of the last program
4585796c8dcSSimon Schubert executed. */
4595796c8dcSSimon Schubert
4605796c8dcSSimon Schubert FILE *
pex_read_output(struct pex_obj * obj,int binary)4615796c8dcSSimon Schubert pex_read_output (struct pex_obj *obj, int binary)
4625796c8dcSSimon Schubert {
4635796c8dcSSimon Schubert if (obj->next_input_name != NULL)
4645796c8dcSSimon Schubert {
4655796c8dcSSimon Schubert const char *errmsg;
4665796c8dcSSimon Schubert int err;
4675796c8dcSSimon Schubert
4685796c8dcSSimon Schubert /* We have to make sure that the process has completed before we
4695796c8dcSSimon Schubert try to read the file. */
4705796c8dcSSimon Schubert if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
4715796c8dcSSimon Schubert {
4725796c8dcSSimon Schubert errno = err;
4735796c8dcSSimon Schubert return NULL;
4745796c8dcSSimon Schubert }
4755796c8dcSSimon Schubert
4765796c8dcSSimon Schubert obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
4775796c8dcSSimon Schubert
4785796c8dcSSimon Schubert if (obj->next_input_name_allocated)
4795796c8dcSSimon Schubert {
4805796c8dcSSimon Schubert free (obj->next_input_name);
4815796c8dcSSimon Schubert obj->next_input_name_allocated = 0;
4825796c8dcSSimon Schubert }
4835796c8dcSSimon Schubert obj->next_input_name = NULL;
4845796c8dcSSimon Schubert }
4855796c8dcSSimon Schubert else
4865796c8dcSSimon Schubert {
4875796c8dcSSimon Schubert int o;
4885796c8dcSSimon Schubert
4895796c8dcSSimon Schubert o = obj->next_input;
4905796c8dcSSimon Schubert if (o < 0 || o == STDIN_FILE_NO)
4915796c8dcSSimon Schubert return NULL;
4925796c8dcSSimon Schubert obj->read_output = obj->funcs->fdopenr (obj, o, binary);
4935796c8dcSSimon Schubert obj->next_input = -1;
4945796c8dcSSimon Schubert }
4955796c8dcSSimon Schubert
4965796c8dcSSimon Schubert return obj->read_output;
4975796c8dcSSimon Schubert }
4985796c8dcSSimon Schubert
4995796c8dcSSimon Schubert FILE *
pex_read_err(struct pex_obj * obj,int binary)5005796c8dcSSimon Schubert pex_read_err (struct pex_obj *obj, int binary)
5015796c8dcSSimon Schubert {
5025796c8dcSSimon Schubert int o;
5035796c8dcSSimon Schubert
5045796c8dcSSimon Schubert o = obj->stderr_pipe;
5055796c8dcSSimon Schubert if (o < 0 || o == STDIN_FILE_NO)
5065796c8dcSSimon Schubert return NULL;
5075796c8dcSSimon Schubert obj->read_err = obj->funcs->fdopenr (obj, o, binary);
508*c50c785cSJohn Marino obj->stderr_pipe = -1;
5095796c8dcSSimon Schubert return obj->read_err;
5105796c8dcSSimon Schubert }
5115796c8dcSSimon Schubert
5125796c8dcSSimon Schubert /* Get the exit status and, if requested, the resource time for all
5135796c8dcSSimon Schubert the child processes. Return 0 on failure, 1 on success. */
5145796c8dcSSimon Schubert
5155796c8dcSSimon Schubert static int
pex_get_status_and_time(struct pex_obj * obj,int done,const char ** errmsg,int * err)5165796c8dcSSimon Schubert pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
5175796c8dcSSimon Schubert int *err)
5185796c8dcSSimon Schubert {
5195796c8dcSSimon Schubert int ret;
5205796c8dcSSimon Schubert int i;
5215796c8dcSSimon Schubert
5225796c8dcSSimon Schubert if (obj->number_waited == obj->count)
5235796c8dcSSimon Schubert return 1;
5245796c8dcSSimon Schubert
5255796c8dcSSimon Schubert obj->status = XRESIZEVEC (int, obj->status, obj->count);
5265796c8dcSSimon Schubert if ((obj->flags & PEX_RECORD_TIMES) != 0)
5275796c8dcSSimon Schubert obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
5285796c8dcSSimon Schubert
5295796c8dcSSimon Schubert ret = 1;
5305796c8dcSSimon Schubert for (i = obj->number_waited; i < obj->count; ++i)
5315796c8dcSSimon Schubert {
5325796c8dcSSimon Schubert if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
5335796c8dcSSimon Schubert obj->time == NULL ? NULL : &obj->time[i],
5345796c8dcSSimon Schubert done, errmsg, err) < 0)
5355796c8dcSSimon Schubert ret = 0;
5365796c8dcSSimon Schubert }
5375796c8dcSSimon Schubert obj->number_waited = i;
5385796c8dcSSimon Schubert
5395796c8dcSSimon Schubert return ret;
5405796c8dcSSimon Schubert }
5415796c8dcSSimon Schubert
5425796c8dcSSimon Schubert /* Get exit status of executed programs. */
5435796c8dcSSimon Schubert
5445796c8dcSSimon Schubert int
pex_get_status(struct pex_obj * obj,int count,int * vector)5455796c8dcSSimon Schubert pex_get_status (struct pex_obj *obj, int count, int *vector)
5465796c8dcSSimon Schubert {
5475796c8dcSSimon Schubert if (obj->status == NULL)
5485796c8dcSSimon Schubert {
5495796c8dcSSimon Schubert const char *errmsg;
5505796c8dcSSimon Schubert int err;
5515796c8dcSSimon Schubert
5525796c8dcSSimon Schubert if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
5535796c8dcSSimon Schubert return 0;
5545796c8dcSSimon Schubert }
5555796c8dcSSimon Schubert
5565796c8dcSSimon Schubert if (count > obj->count)
5575796c8dcSSimon Schubert {
5585796c8dcSSimon Schubert memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
5595796c8dcSSimon Schubert count = obj->count;
5605796c8dcSSimon Schubert }
5615796c8dcSSimon Schubert
5625796c8dcSSimon Schubert memcpy (vector, obj->status, count * sizeof (int));
5635796c8dcSSimon Schubert
5645796c8dcSSimon Schubert return 1;
5655796c8dcSSimon Schubert }
5665796c8dcSSimon Schubert
5675796c8dcSSimon Schubert /* Get process times of executed programs. */
5685796c8dcSSimon Schubert
5695796c8dcSSimon Schubert int
pex_get_times(struct pex_obj * obj,int count,struct pex_time * vector)5705796c8dcSSimon Schubert pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
5715796c8dcSSimon Schubert {
5725796c8dcSSimon Schubert if (obj->status == NULL)
5735796c8dcSSimon Schubert {
5745796c8dcSSimon Schubert const char *errmsg;
5755796c8dcSSimon Schubert int err;
5765796c8dcSSimon Schubert
5775796c8dcSSimon Schubert if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
5785796c8dcSSimon Schubert return 0;
5795796c8dcSSimon Schubert }
5805796c8dcSSimon Schubert
5815796c8dcSSimon Schubert if (obj->time == NULL)
5825796c8dcSSimon Schubert return 0;
5835796c8dcSSimon Schubert
5845796c8dcSSimon Schubert if (count > obj->count)
5855796c8dcSSimon Schubert {
5865796c8dcSSimon Schubert memset (vector + obj->count, 0,
5875796c8dcSSimon Schubert (count - obj->count) * sizeof (struct pex_time));
5885796c8dcSSimon Schubert count = obj->count;
5895796c8dcSSimon Schubert }
5905796c8dcSSimon Schubert
5915796c8dcSSimon Schubert memcpy (vector, obj->time, count * sizeof (struct pex_time));
5925796c8dcSSimon Schubert
5935796c8dcSSimon Schubert return 1;
5945796c8dcSSimon Schubert }
5955796c8dcSSimon Schubert
5965796c8dcSSimon Schubert /* Free a pex_obj structure. */
5975796c8dcSSimon Schubert
5985796c8dcSSimon Schubert void
pex_free(struct pex_obj * obj)5995796c8dcSSimon Schubert pex_free (struct pex_obj *obj)
6005796c8dcSSimon Schubert {
601*c50c785cSJohn Marino /* Close pipe file descriptors corresponding to child's stdout and
602*c50c785cSJohn Marino stderr so that the child does not hang trying to output something
603*c50c785cSJohn Marino while we're waiting for it. */
6045796c8dcSSimon Schubert if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
6055796c8dcSSimon Schubert obj->funcs->close (obj, obj->next_input);
606*c50c785cSJohn Marino if (obj->stderr_pipe >= 0 && obj->stderr_pipe != STDIN_FILE_NO)
607*c50c785cSJohn Marino obj->funcs->close (obj, obj->stderr_pipe);
608*c50c785cSJohn Marino if (obj->read_output != NULL)
609*c50c785cSJohn Marino fclose (obj->read_output);
610*c50c785cSJohn Marino if (obj->read_err != NULL)
611*c50c785cSJohn Marino fclose (obj->read_err);
6125796c8dcSSimon Schubert
6135796c8dcSSimon Schubert /* If the caller forgot to wait for the children, we do it here, to
6145796c8dcSSimon Schubert avoid zombies. */
6155796c8dcSSimon Schubert if (obj->status == NULL)
6165796c8dcSSimon Schubert {
6175796c8dcSSimon Schubert const char *errmsg;
6185796c8dcSSimon Schubert int err;
6195796c8dcSSimon Schubert
6205796c8dcSSimon Schubert obj->flags &= ~ PEX_RECORD_TIMES;
6215796c8dcSSimon Schubert pex_get_status_and_time (obj, 1, &errmsg, &err);
6225796c8dcSSimon Schubert }
6235796c8dcSSimon Schubert
6245796c8dcSSimon Schubert if (obj->next_input_name_allocated)
6255796c8dcSSimon Schubert free (obj->next_input_name);
6265796c8dcSSimon Schubert free (obj->children);
6275796c8dcSSimon Schubert free (obj->status);
6285796c8dcSSimon Schubert free (obj->time);
6295796c8dcSSimon Schubert
6305796c8dcSSimon Schubert if (obj->remove_count > 0)
6315796c8dcSSimon Schubert {
6325796c8dcSSimon Schubert int i;
6335796c8dcSSimon Schubert
6345796c8dcSSimon Schubert for (i = 0; i < obj->remove_count; ++i)
6355796c8dcSSimon Schubert {
6365796c8dcSSimon Schubert remove (obj->remove[i]);
6375796c8dcSSimon Schubert free (obj->remove[i]);
6385796c8dcSSimon Schubert }
6395796c8dcSSimon Schubert free (obj->remove);
6405796c8dcSSimon Schubert }
6415796c8dcSSimon Schubert
6425796c8dcSSimon Schubert if (obj->funcs->cleanup != NULL)
6435796c8dcSSimon Schubert obj->funcs->cleanup (obj);
6445796c8dcSSimon Schubert
6455796c8dcSSimon Schubert free (obj);
6465796c8dcSSimon Schubert }
647