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