xref: /dflybsd-src/contrib/gdb-7/libiberty/pex-common.c (revision ec70266467411565ead9166ad4c1dbb79ff7cd77)
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