198b9484cSchristos /* Utilities to execute a program in a subprocess (possibly linked by pipes 298b9484cSchristos with other subprocesses), and wait for it. Generic Unix version 398b9484cSchristos (also used for UWIN and VMS). 4*7e120ff0Schristos Copyright (C) 1996-2024 Free Software Foundation, Inc. 598b9484cSchristos 698b9484cSchristos This file is part of the libiberty library. 798b9484cSchristos Libiberty is free software; you can redistribute it and/or 898b9484cSchristos modify it under the terms of the GNU Library General Public 998b9484cSchristos License as published by the Free Software Foundation; either 1098b9484cSchristos version 2 of the License, or (at your option) any later version. 1198b9484cSchristos 1298b9484cSchristos Libiberty is distributed in the hope that it will be useful, 1398b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1498b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1598b9484cSchristos Library General Public License for more details. 1698b9484cSchristos 1798b9484cSchristos You should have received a copy of the GNU Library General Public 1898b9484cSchristos License along with libiberty; see the file COPYING.LIB. If not, 1998b9484cSchristos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 2098b9484cSchristos Boston, MA 02110-1301, USA. */ 2198b9484cSchristos 2298b9484cSchristos #include "config.h" 2398b9484cSchristos #include "libiberty.h" 2498b9484cSchristos #include "pex-common.h" 25ba340e45Schristos #include "environ.h" 2698b9484cSchristos 2798b9484cSchristos #include <stdio.h> 2898b9484cSchristos #include <signal.h> 2998b9484cSchristos #include <errno.h> 3098b9484cSchristos #ifdef NEED_DECLARATION_ERRNO 3198b9484cSchristos extern int errno; 3298b9484cSchristos #endif 3398b9484cSchristos #ifdef HAVE_STDLIB_H 3498b9484cSchristos #include <stdlib.h> 3598b9484cSchristos #endif 3698b9484cSchristos #ifdef HAVE_STRING_H 3798b9484cSchristos #include <string.h> 3898b9484cSchristos #endif 3998b9484cSchristos #ifdef HAVE_UNISTD_H 4098b9484cSchristos #include <unistd.h> 4198b9484cSchristos #endif 4298b9484cSchristos 4398b9484cSchristos #include <sys/types.h> 4498b9484cSchristos 4598b9484cSchristos #ifdef HAVE_FCNTL_H 4698b9484cSchristos #include <fcntl.h> 4798b9484cSchristos #endif 4898b9484cSchristos #ifdef HAVE_SYS_WAIT_H 4998b9484cSchristos #include <sys/wait.h> 5098b9484cSchristos #endif 5198b9484cSchristos #ifdef HAVE_GETRUSAGE 5298b9484cSchristos #include <sys/time.h> 5398b9484cSchristos #include <sys/resource.h> 5498b9484cSchristos #endif 5598b9484cSchristos #ifdef HAVE_SYS_STAT_H 5698b9484cSchristos #include <sys/stat.h> 5798b9484cSchristos #endif 5898b9484cSchristos #ifdef HAVE_PROCESS_H 5998b9484cSchristos #include <process.h> 6098b9484cSchristos #endif 61*7e120ff0Schristos #ifdef HAVE_SPAWN_H 62*7e120ff0Schristos #include <spawn.h> 63*7e120ff0Schristos #endif 6498b9484cSchristos 6598b9484cSchristos #ifdef vfork /* Autoconf may define this to fork for us. */ 6698b9484cSchristos # define VFORK_STRING "fork" 6798b9484cSchristos #else 6898b9484cSchristos # define VFORK_STRING "vfork" 6998b9484cSchristos #endif 7098b9484cSchristos #ifdef HAVE_VFORK_H 7198b9484cSchristos #include <vfork.h> 7298b9484cSchristos #endif 7398b9484cSchristos #if defined(VMS) && defined (__LONG_POINTERS) 7498b9484cSchristos #ifndef __CHAR_PTR32 7598b9484cSchristos typedef char * __char_ptr32 7698b9484cSchristos __attribute__ ((mode (SI))); 7798b9484cSchristos #endif 7898b9484cSchristos 7998b9484cSchristos typedef __char_ptr32 *__char_ptr_char_ptr32 8098b9484cSchristos __attribute__ ((mode (SI))); 8198b9484cSchristos 8298b9484cSchristos /* Return a 32 bit pointer to an array of 32 bit pointers 8398b9484cSchristos given a 64 bit pointer to an array of 64 bit pointers. */ 8498b9484cSchristos 8598b9484cSchristos static __char_ptr_char_ptr32 8698b9484cSchristos to_ptr32 (char **ptr64) 8798b9484cSchristos { 8898b9484cSchristos int argc; 8998b9484cSchristos __char_ptr_char_ptr32 short_argv; 9098b9484cSchristos 91a2e2270fSchristos /* Count number of arguments. */ 92a2e2270fSchristos for (argc = 0; ptr64[argc] != NULL; argc++) 93a2e2270fSchristos ; 9498b9484cSchristos 9598b9484cSchristos /* Reallocate argv with 32 bit pointers. */ 9698b9484cSchristos short_argv = (__char_ptr_char_ptr32) decc$malloc 9798b9484cSchristos (sizeof (__char_ptr32) * (argc + 1)); 9898b9484cSchristos 99a2e2270fSchristos for (argc = 0; ptr64[argc] != NULL; argc++) 10098b9484cSchristos short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]); 10198b9484cSchristos 10298b9484cSchristos short_argv[argc] = (__char_ptr32) 0; 10398b9484cSchristos return short_argv; 10498b9484cSchristos 10598b9484cSchristos } 10698b9484cSchristos #else 10798b9484cSchristos #define to_ptr32(argv) argv 10898b9484cSchristos #endif 10998b9484cSchristos 11098b9484cSchristos /* File mode to use for private and world-readable files. */ 11198b9484cSchristos 11298b9484cSchristos #if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH) 11398b9484cSchristos #define PUBLIC_MODE \ 11498b9484cSchristos (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) 11598b9484cSchristos #else 11698b9484cSchristos #define PUBLIC_MODE 0666 11798b9484cSchristos #endif 11898b9484cSchristos 11998b9484cSchristos /* Get the exit status of a particular process, and optionally get the 12098b9484cSchristos time that it took. This is simple if we have wait4, slightly 12198b9484cSchristos harder if we have waitpid, and is a pain if we only have wait. */ 12298b9484cSchristos 12398b9484cSchristos static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *); 12498b9484cSchristos 12598b9484cSchristos #ifdef HAVE_WAIT4 12698b9484cSchristos 12798b9484cSchristos static pid_t 12898b9484cSchristos pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, 12998b9484cSchristos struct pex_time *time) 13098b9484cSchristos { 13198b9484cSchristos pid_t ret; 13298b9484cSchristos struct rusage r; 13398b9484cSchristos 13498b9484cSchristos #ifdef HAVE_WAITPID 13598b9484cSchristos if (time == NULL) 13698b9484cSchristos return waitpid (pid, status, 0); 13798b9484cSchristos #endif 13898b9484cSchristos 13998b9484cSchristos ret = wait4 (pid, status, 0, &r); 14098b9484cSchristos 14198b9484cSchristos if (time != NULL) 14298b9484cSchristos { 14398b9484cSchristos time->user_seconds = r.ru_utime.tv_sec; 14498b9484cSchristos time->user_microseconds= r.ru_utime.tv_usec; 14598b9484cSchristos time->system_seconds = r.ru_stime.tv_sec; 14698b9484cSchristos time->system_microseconds= r.ru_stime.tv_usec; 14798b9484cSchristos } 14898b9484cSchristos 14998b9484cSchristos return ret; 15098b9484cSchristos } 15198b9484cSchristos 15298b9484cSchristos #else /* ! defined (HAVE_WAIT4) */ 15398b9484cSchristos 15498b9484cSchristos #ifdef HAVE_WAITPID 15598b9484cSchristos 15698b9484cSchristos #ifndef HAVE_GETRUSAGE 15798b9484cSchristos 15898b9484cSchristos static pid_t 15998b9484cSchristos pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, 16098b9484cSchristos struct pex_time *time) 16198b9484cSchristos { 16298b9484cSchristos if (time != NULL) 16398b9484cSchristos memset (time, 0, sizeof (struct pex_time)); 16498b9484cSchristos return waitpid (pid, status, 0); 16598b9484cSchristos } 16698b9484cSchristos 16798b9484cSchristos #else /* defined (HAVE_GETRUSAGE) */ 16898b9484cSchristos 16998b9484cSchristos static pid_t 17098b9484cSchristos pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, 17198b9484cSchristos struct pex_time *time) 17298b9484cSchristos { 17398b9484cSchristos struct rusage r1, r2; 17498b9484cSchristos pid_t ret; 17598b9484cSchristos 17698b9484cSchristos if (time == NULL) 17798b9484cSchristos return waitpid (pid, status, 0); 17898b9484cSchristos 17998b9484cSchristos getrusage (RUSAGE_CHILDREN, &r1); 18098b9484cSchristos 18198b9484cSchristos ret = waitpid (pid, status, 0); 18298b9484cSchristos if (ret < 0) 18398b9484cSchristos return ret; 18498b9484cSchristos 18598b9484cSchristos getrusage (RUSAGE_CHILDREN, &r2); 18698b9484cSchristos 18798b9484cSchristos time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; 18898b9484cSchristos time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; 18998b9484cSchristos if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec) 19098b9484cSchristos { 19198b9484cSchristos --time->user_seconds; 19298b9484cSchristos time->user_microseconds += 1000000; 19398b9484cSchristos } 19498b9484cSchristos 19598b9484cSchristos time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; 19698b9484cSchristos time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; 19798b9484cSchristos if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec) 19898b9484cSchristos { 19998b9484cSchristos --time->system_seconds; 20098b9484cSchristos time->system_microseconds += 1000000; 20198b9484cSchristos } 20298b9484cSchristos 20398b9484cSchristos return ret; 20498b9484cSchristos } 20598b9484cSchristos 20698b9484cSchristos #endif /* defined (HAVE_GETRUSAGE) */ 20798b9484cSchristos 20898b9484cSchristos #else /* ! defined (HAVE_WAITPID) */ 20998b9484cSchristos 21098b9484cSchristos struct status_list 21198b9484cSchristos { 21298b9484cSchristos struct status_list *next; 21398b9484cSchristos pid_t pid; 21498b9484cSchristos int status; 21598b9484cSchristos struct pex_time time; 21698b9484cSchristos }; 21798b9484cSchristos 21898b9484cSchristos static pid_t 21998b9484cSchristos pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time) 22098b9484cSchristos { 22198b9484cSchristos struct status_list **pp; 22298b9484cSchristos 22398b9484cSchristos for (pp = (struct status_list **) &obj->sysdep; 22498b9484cSchristos *pp != NULL; 22598b9484cSchristos pp = &(*pp)->next) 22698b9484cSchristos { 22798b9484cSchristos if ((*pp)->pid == pid) 22898b9484cSchristos { 22998b9484cSchristos struct status_list *p; 23098b9484cSchristos 23198b9484cSchristos p = *pp; 23298b9484cSchristos *status = p->status; 23398b9484cSchristos if (time != NULL) 23498b9484cSchristos *time = p->time; 23598b9484cSchristos *pp = p->next; 23698b9484cSchristos free (p); 23798b9484cSchristos return pid; 23898b9484cSchristos } 23998b9484cSchristos } 24098b9484cSchristos 24198b9484cSchristos while (1) 24298b9484cSchristos { 24398b9484cSchristos pid_t cpid; 24498b9484cSchristos struct status_list *psl; 24598b9484cSchristos struct pex_time pt; 24698b9484cSchristos #ifdef HAVE_GETRUSAGE 24798b9484cSchristos struct rusage r1, r2; 24898b9484cSchristos #endif 24998b9484cSchristos 25098b9484cSchristos if (time != NULL) 25198b9484cSchristos { 25298b9484cSchristos #ifdef HAVE_GETRUSAGE 25398b9484cSchristos getrusage (RUSAGE_CHILDREN, &r1); 25498b9484cSchristos #else 25598b9484cSchristos memset (&pt, 0, sizeof (struct pex_time)); 25698b9484cSchristos #endif 25798b9484cSchristos } 25898b9484cSchristos 25998b9484cSchristos cpid = wait (status); 26098b9484cSchristos 26198b9484cSchristos #ifdef HAVE_GETRUSAGE 26298b9484cSchristos if (time != NULL && cpid >= 0) 26398b9484cSchristos { 26498b9484cSchristos getrusage (RUSAGE_CHILDREN, &r2); 26598b9484cSchristos 26698b9484cSchristos pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; 26798b9484cSchristos pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; 26898b9484cSchristos if (pt.user_microseconds < 0) 26998b9484cSchristos { 27098b9484cSchristos --pt.user_seconds; 27198b9484cSchristos pt.user_microseconds += 1000000; 27298b9484cSchristos } 27398b9484cSchristos 27498b9484cSchristos pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; 27598b9484cSchristos pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; 27698b9484cSchristos if (pt.system_microseconds < 0) 27798b9484cSchristos { 27898b9484cSchristos --pt.system_seconds; 27998b9484cSchristos pt.system_microseconds += 1000000; 28098b9484cSchristos } 28198b9484cSchristos } 28298b9484cSchristos #endif 28398b9484cSchristos 28498b9484cSchristos if (cpid < 0 || cpid == pid) 28598b9484cSchristos { 28698b9484cSchristos if (time != NULL) 28798b9484cSchristos *time = pt; 28898b9484cSchristos return cpid; 28998b9484cSchristos } 29098b9484cSchristos 29198b9484cSchristos psl = XNEW (struct status_list); 29298b9484cSchristos psl->pid = cpid; 29398b9484cSchristos psl->status = *status; 29498b9484cSchristos if (time != NULL) 29598b9484cSchristos psl->time = pt; 29698b9484cSchristos psl->next = (struct status_list *) obj->sysdep; 29798b9484cSchristos obj->sysdep = (void *) psl; 29898b9484cSchristos } 29998b9484cSchristos } 30098b9484cSchristos 30198b9484cSchristos #endif /* ! defined (HAVE_WAITPID) */ 30298b9484cSchristos #endif /* ! defined (HAVE_WAIT4) */ 30398b9484cSchristos 30498b9484cSchristos static int pex_unix_open_read (struct pex_obj *, const char *, int); 305837edd6bSchristos static int pex_unix_open_write (struct pex_obj *, const char *, int, int); 30698b9484cSchristos static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *, 30798b9484cSchristos char * const *, char * const *, 30898b9484cSchristos int, int, int, int, 30998b9484cSchristos const char **, int *); 31098b9484cSchristos static int pex_unix_close (struct pex_obj *, int); 311*7e120ff0Schristos static pid_t pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *, 31298b9484cSchristos int, const char **, int *); 31398b9484cSchristos static int pex_unix_pipe (struct pex_obj *, int *, int); 31498b9484cSchristos static FILE *pex_unix_fdopenr (struct pex_obj *, int, int); 31598b9484cSchristos static FILE *pex_unix_fdopenw (struct pex_obj *, int, int); 31698b9484cSchristos static void pex_unix_cleanup (struct pex_obj *); 31798b9484cSchristos 31898b9484cSchristos /* The list of functions we pass to the common routines. */ 31998b9484cSchristos 32098b9484cSchristos const struct pex_funcs funcs = 32198b9484cSchristos { 32298b9484cSchristos pex_unix_open_read, 32398b9484cSchristos pex_unix_open_write, 32498b9484cSchristos pex_unix_exec_child, 32598b9484cSchristos pex_unix_close, 32698b9484cSchristos pex_unix_wait, 32798b9484cSchristos pex_unix_pipe, 32898b9484cSchristos pex_unix_fdopenr, 32998b9484cSchristos pex_unix_fdopenw, 33098b9484cSchristos pex_unix_cleanup 33198b9484cSchristos }; 33298b9484cSchristos 33398b9484cSchristos /* Return a newly initialized pex_obj structure. */ 33498b9484cSchristos 33598b9484cSchristos struct pex_obj * 33698b9484cSchristos pex_init (int flags, const char *pname, const char *tempbase) 33798b9484cSchristos { 33898b9484cSchristos return pex_init_common (flags, pname, tempbase, &funcs); 33998b9484cSchristos } 34098b9484cSchristos 34198b9484cSchristos /* Open a file for reading. */ 34298b9484cSchristos 34398b9484cSchristos static int 34498b9484cSchristos pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, 34598b9484cSchristos int binary ATTRIBUTE_UNUSED) 34698b9484cSchristos { 34798b9484cSchristos return open (name, O_RDONLY); 34898b9484cSchristos } 34998b9484cSchristos 35098b9484cSchristos /* Open a file for writing. */ 35198b9484cSchristos 35298b9484cSchristos static int 35398b9484cSchristos pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, 354837edd6bSchristos int binary ATTRIBUTE_UNUSED, int append) 35598b9484cSchristos { 35698b9484cSchristos /* Note that we can't use O_EXCL here because gcc may have already 35798b9484cSchristos created the temporary file via make_temp_file. */ 358837edd6bSchristos return open (name, O_WRONLY | O_CREAT 359837edd6bSchristos | (append ? O_APPEND : O_TRUNC), PUBLIC_MODE); 36098b9484cSchristos } 36198b9484cSchristos 36298b9484cSchristos /* Close a file. */ 36398b9484cSchristos 36498b9484cSchristos static int 36598b9484cSchristos pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) 36698b9484cSchristos { 36798b9484cSchristos return close (fd); 36898b9484cSchristos } 36998b9484cSchristos 37098b9484cSchristos /* Execute a child. */ 37198b9484cSchristos 37298b9484cSchristos #if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE) 37398b9484cSchristos /* Implementation of pex->exec_child using the Cygwin spawn operation. */ 37498b9484cSchristos 37598b9484cSchristos /* Subroutine of pex_unix_exec_child. Move OLD_FD to a new file descriptor 37698b9484cSchristos to be stored in *PNEW_FD, save the flags in *PFLAGS, and arrange for the 37798b9484cSchristos saved copy to be close-on-exec. Move CHILD_FD into OLD_FD. If CHILD_FD 37898b9484cSchristos is -1, OLD_FD is to be closed. Return -1 on error. */ 37998b9484cSchristos 38098b9484cSchristos static int 38198b9484cSchristos save_and_install_fd(int *pnew_fd, int *pflags, int old_fd, int child_fd) 38298b9484cSchristos { 38398b9484cSchristos int new_fd, flags; 38498b9484cSchristos 38598b9484cSchristos flags = fcntl (old_fd, F_GETFD); 38698b9484cSchristos 38798b9484cSchristos /* If we could not retrieve the flags, then OLD_FD was not open. */ 38898b9484cSchristos if (flags < 0) 38998b9484cSchristos { 39098b9484cSchristos new_fd = -1, flags = 0; 39198b9484cSchristos if (child_fd >= 0 && dup2 (child_fd, old_fd) < 0) 39298b9484cSchristos return -1; 39398b9484cSchristos } 39498b9484cSchristos /* If we wish to close OLD_FD, just mark it CLOEXEC. */ 39598b9484cSchristos else if (child_fd == -1) 39698b9484cSchristos { 39798b9484cSchristos new_fd = old_fd; 39898b9484cSchristos if ((flags & FD_CLOEXEC) == 0 && fcntl (old_fd, F_SETFD, FD_CLOEXEC) < 0) 39998b9484cSchristos return -1; 40098b9484cSchristos } 40198b9484cSchristos /* Otherwise we need to save a copy of OLD_FD before installing CHILD_FD. */ 40298b9484cSchristos else 40398b9484cSchristos { 40498b9484cSchristos #ifdef F_DUPFD_CLOEXEC 40598b9484cSchristos new_fd = fcntl (old_fd, F_DUPFD_CLOEXEC, 3); 40698b9484cSchristos if (new_fd < 0) 40798b9484cSchristos return -1; 40898b9484cSchristos #else 40998b9484cSchristos /* Prefer F_DUPFD over dup in order to avoid getting a new fd 41098b9484cSchristos in the range 0-2, right where a new stderr fd might get put. */ 41198b9484cSchristos new_fd = fcntl (old_fd, F_DUPFD, 3); 41298b9484cSchristos if (new_fd < 0) 41398b9484cSchristos return -1; 41498b9484cSchristos if (fcntl (new_fd, F_SETFD, FD_CLOEXEC) < 0) 41598b9484cSchristos return -1; 41698b9484cSchristos #endif 41798b9484cSchristos if (dup2 (child_fd, old_fd) < 0) 41898b9484cSchristos return -1; 41998b9484cSchristos } 42098b9484cSchristos 42198b9484cSchristos *pflags = flags; 42298b9484cSchristos if (pnew_fd) 42398b9484cSchristos *pnew_fd = new_fd; 42498b9484cSchristos else if (new_fd != old_fd) 42598b9484cSchristos abort (); 42698b9484cSchristos 42798b9484cSchristos return 0; 42898b9484cSchristos } 42998b9484cSchristos 43098b9484cSchristos /* Subroutine of pex_unix_exec_child. Move SAVE_FD back to OLD_FD 43198b9484cSchristos restoring FLAGS. If SAVE_FD < 0, OLD_FD is to be closed. */ 43298b9484cSchristos 43398b9484cSchristos static int 43498b9484cSchristos restore_fd(int old_fd, int save_fd, int flags) 43598b9484cSchristos { 43698b9484cSchristos /* For SAVE_FD < 0, all we have to do is restore the 43798b9484cSchristos "closed-ness" of the original. */ 43898b9484cSchristos if (save_fd < 0) 43998b9484cSchristos return close (old_fd); 44098b9484cSchristos 44198b9484cSchristos /* For SAVE_FD == OLD_FD, all we have to do is restore the 44298b9484cSchristos original setting of the CLOEXEC flag. */ 44398b9484cSchristos if (save_fd == old_fd) 44498b9484cSchristos { 44598b9484cSchristos if (flags & FD_CLOEXEC) 44698b9484cSchristos return 0; 44798b9484cSchristos return fcntl (old_fd, F_SETFD, flags); 44898b9484cSchristos } 44998b9484cSchristos 45098b9484cSchristos /* Otherwise we have to move the descriptor back, restore the flags, 45198b9484cSchristos and close the saved copy. */ 45298b9484cSchristos #ifdef HAVE_DUP3 45398b9484cSchristos if (flags == FD_CLOEXEC) 45498b9484cSchristos { 45598b9484cSchristos if (dup3 (save_fd, old_fd, O_CLOEXEC) < 0) 45698b9484cSchristos return -1; 45798b9484cSchristos } 45898b9484cSchristos else 45998b9484cSchristos #endif 46098b9484cSchristos { 46198b9484cSchristos if (dup2 (save_fd, old_fd) < 0) 46298b9484cSchristos return -1; 46398b9484cSchristos if (flags != 0 && fcntl (old_fd, F_SETFD, flags) < 0) 46498b9484cSchristos return -1; 46598b9484cSchristos } 46698b9484cSchristos return close (save_fd); 46798b9484cSchristos } 46898b9484cSchristos 46998b9484cSchristos static pid_t 47098b9484cSchristos pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, 47198b9484cSchristos int flags, const char *executable, 47298b9484cSchristos char * const * argv, char * const * env, 47398b9484cSchristos int in, int out, int errdes, int toclose, 47498b9484cSchristos const char **errmsg, int *err) 47598b9484cSchristos { 47698b9484cSchristos int fl_in = 0, fl_out = 0, fl_err = 0, fl_tc = 0; 47798b9484cSchristos int save_in = -1, save_out = -1, save_err = -1; 47898b9484cSchristos int max, retries; 47998b9484cSchristos pid_t pid; 48098b9484cSchristos 48198b9484cSchristos if (flags & PEX_STDERR_TO_STDOUT) 48298b9484cSchristos errdes = out; 48398b9484cSchristos 48498b9484cSchristos /* We need the three standard file descriptors to be set up as for 48598b9484cSchristos the child before we perform the spawn. The file descriptors for 48698b9484cSchristos the parent need to be moved and marked for close-on-exec. */ 48798b9484cSchristos if (in != STDIN_FILE_NO 48898b9484cSchristos && save_and_install_fd (&save_in, &fl_in, STDIN_FILE_NO, in) < 0) 48998b9484cSchristos goto error_dup2; 49098b9484cSchristos if (out != STDOUT_FILE_NO 49198b9484cSchristos && save_and_install_fd (&save_out, &fl_out, STDOUT_FILE_NO, out) < 0) 49298b9484cSchristos goto error_dup2; 49398b9484cSchristos if (errdes != STDERR_FILE_NO 49498b9484cSchristos && save_and_install_fd (&save_err, &fl_err, STDERR_FILE_NO, errdes) < 0) 49598b9484cSchristos goto error_dup2; 49698b9484cSchristos if (toclose >= 0 49798b9484cSchristos && save_and_install_fd (NULL, &fl_tc, toclose, -1) < 0) 49898b9484cSchristos goto error_dup2; 49998b9484cSchristos 50098b9484cSchristos /* Now that we've moved the file descriptors for the child into place, 50198b9484cSchristos close the originals. Be careful not to close any of the standard 50298b9484cSchristos file descriptors that we just set up. */ 50398b9484cSchristos max = -1; 50498b9484cSchristos if (errdes >= 0) 50598b9484cSchristos max = STDERR_FILE_NO; 50698b9484cSchristos else if (out >= 0) 50798b9484cSchristos max = STDOUT_FILE_NO; 50898b9484cSchristos else if (in >= 0) 50998b9484cSchristos max = STDIN_FILE_NO; 51098b9484cSchristos if (in > max) 51198b9484cSchristos close (in); 51298b9484cSchristos if (out > max) 51398b9484cSchristos close (out); 51498b9484cSchristos if (errdes > max && errdes != out) 51598b9484cSchristos close (errdes); 51698b9484cSchristos 51798b9484cSchristos /* If we were not given an environment, use the global environment. */ 51898b9484cSchristos if (env == NULL) 51998b9484cSchristos env = environ; 52098b9484cSchristos 52198b9484cSchristos /* Launch the program. If we get EAGAIN (normally out of pid's), try 52298b9484cSchristos again a few times with increasing backoff times. */ 52398b9484cSchristos retries = 0; 52498b9484cSchristos while (1) 52598b9484cSchristos { 52698b9484cSchristos typedef const char * const *cc_cp; 52798b9484cSchristos 52898b9484cSchristos if (flags & PEX_SEARCH) 52998b9484cSchristos pid = spawnvpe (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env); 53098b9484cSchristos else 53198b9484cSchristos pid = spawnve (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env); 53298b9484cSchristos 53398b9484cSchristos if (pid > 0) 53498b9484cSchristos break; 53598b9484cSchristos 53698b9484cSchristos *err = errno; 53798b9484cSchristos *errmsg = "spawn"; 53898b9484cSchristos if (errno != EAGAIN || ++retries == 4) 53998b9484cSchristos return (pid_t) -1; 54098b9484cSchristos sleep (1 << retries); 54198b9484cSchristos } 54298b9484cSchristos 54398b9484cSchristos /* Success. Restore the parent's file descriptors that we saved above. */ 54498b9484cSchristos if (toclose >= 0 54598b9484cSchristos && restore_fd (toclose, toclose, fl_tc) < 0) 54698b9484cSchristos goto error_dup2; 54798b9484cSchristos if (in != STDIN_FILE_NO 54898b9484cSchristos && restore_fd (STDIN_FILE_NO, save_in, fl_in) < 0) 54998b9484cSchristos goto error_dup2; 55098b9484cSchristos if (out != STDOUT_FILE_NO 55198b9484cSchristos && restore_fd (STDOUT_FILE_NO, save_out, fl_out) < 0) 55298b9484cSchristos goto error_dup2; 55398b9484cSchristos if (errdes != STDERR_FILE_NO 55498b9484cSchristos && restore_fd (STDERR_FILE_NO, save_err, fl_err) < 0) 55598b9484cSchristos goto error_dup2; 55698b9484cSchristos 55798b9484cSchristos return pid; 55898b9484cSchristos 55998b9484cSchristos error_dup2: 56098b9484cSchristos *err = errno; 56198b9484cSchristos *errmsg = "dup2"; 56298b9484cSchristos return (pid_t) -1; 56398b9484cSchristos } 56498b9484cSchristos 565*7e120ff0Schristos #elif defined(HAVE_POSIX_SPAWN) && defined(HAVE_POSIX_SPAWNP) 566*7e120ff0Schristos /* Implementation of pex->exec_child using posix_spawn. */ 567*7e120ff0Schristos 568*7e120ff0Schristos static pid_t 569*7e120ff0Schristos pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, 570*7e120ff0Schristos int flags, const char *executable, 571*7e120ff0Schristos char * const * argv, char * const * env, 572*7e120ff0Schristos int in, int out, int errdes, 573*7e120ff0Schristos int toclose, const char **errmsg, int *err) 574*7e120ff0Schristos { 575*7e120ff0Schristos int ret; 576*7e120ff0Schristos pid_t pid = -1; 577*7e120ff0Schristos posix_spawnattr_t attr; 578*7e120ff0Schristos posix_spawn_file_actions_t actions; 579*7e120ff0Schristos int attr_initialized = 0, actions_initialized = 0; 580*7e120ff0Schristos 581*7e120ff0Schristos *err = 0; 582*7e120ff0Schristos 583*7e120ff0Schristos ret = posix_spawnattr_init (&attr); 584*7e120ff0Schristos if (ret) 585*7e120ff0Schristos { 586*7e120ff0Schristos *err = ret; 587*7e120ff0Schristos *errmsg = "posix_spawnattr_init"; 588*7e120ff0Schristos goto exit; 589*7e120ff0Schristos } 590*7e120ff0Schristos attr_initialized = 1; 591*7e120ff0Schristos 592*7e120ff0Schristos /* Use vfork() on glibc <=2.24. */ 593*7e120ff0Schristos #ifdef POSIX_SPAWN_USEVFORK 594*7e120ff0Schristos ret = posix_spawnattr_setflags (&attr, POSIX_SPAWN_USEVFORK); 595*7e120ff0Schristos if (ret) 596*7e120ff0Schristos { 597*7e120ff0Schristos *err = ret; 598*7e120ff0Schristos *errmsg = "posix_spawnattr_setflags"; 599*7e120ff0Schristos goto exit; 600*7e120ff0Schristos } 601*7e120ff0Schristos #endif 602*7e120ff0Schristos 603*7e120ff0Schristos ret = posix_spawn_file_actions_init (&actions); 604*7e120ff0Schristos if (ret) 605*7e120ff0Schristos { 606*7e120ff0Schristos *err = ret; 607*7e120ff0Schristos *errmsg = "posix_spawn_file_actions_init"; 608*7e120ff0Schristos goto exit; 609*7e120ff0Schristos } 610*7e120ff0Schristos actions_initialized = 1; 611*7e120ff0Schristos 612*7e120ff0Schristos if (in != STDIN_FILE_NO) 613*7e120ff0Schristos { 614*7e120ff0Schristos ret = posix_spawn_file_actions_adddup2 (&actions, in, STDIN_FILE_NO); 615*7e120ff0Schristos if (ret) 616*7e120ff0Schristos { 617*7e120ff0Schristos *err = ret; 618*7e120ff0Schristos *errmsg = "posix_spawn_file_actions_adddup2"; 619*7e120ff0Schristos goto exit; 620*7e120ff0Schristos } 621*7e120ff0Schristos 622*7e120ff0Schristos ret = posix_spawn_file_actions_addclose (&actions, in); 623*7e120ff0Schristos if (ret) 624*7e120ff0Schristos { 625*7e120ff0Schristos *err = ret; 626*7e120ff0Schristos *errmsg = "posix_spawn_file_actions_addclose"; 627*7e120ff0Schristos goto exit; 628*7e120ff0Schristos } 629*7e120ff0Schristos } 630*7e120ff0Schristos 631*7e120ff0Schristos if (out != STDOUT_FILE_NO) 632*7e120ff0Schristos { 633*7e120ff0Schristos ret = posix_spawn_file_actions_adddup2 (&actions, out, STDOUT_FILE_NO); 634*7e120ff0Schristos if (ret) 635*7e120ff0Schristos { 636*7e120ff0Schristos *err = ret; 637*7e120ff0Schristos *errmsg = "posix_spawn_file_actions_adddup2"; 638*7e120ff0Schristos goto exit; 639*7e120ff0Schristos } 640*7e120ff0Schristos 641*7e120ff0Schristos ret = posix_spawn_file_actions_addclose (&actions, out); 642*7e120ff0Schristos if (ret) 643*7e120ff0Schristos { 644*7e120ff0Schristos *err = ret; 645*7e120ff0Schristos *errmsg = "posix_spawn_file_actions_addclose"; 646*7e120ff0Schristos goto exit; 647*7e120ff0Schristos } 648*7e120ff0Schristos } 649*7e120ff0Schristos 650*7e120ff0Schristos if (errdes != STDERR_FILE_NO) 651*7e120ff0Schristos { 652*7e120ff0Schristos ret = posix_spawn_file_actions_adddup2 (&actions, errdes, STDERR_FILE_NO); 653*7e120ff0Schristos if (ret) 654*7e120ff0Schristos { 655*7e120ff0Schristos *err = ret; 656*7e120ff0Schristos *errmsg = "posix_spawn_file_actions_adddup2"; 657*7e120ff0Schristos goto exit; 658*7e120ff0Schristos } 659*7e120ff0Schristos 660*7e120ff0Schristos ret = posix_spawn_file_actions_addclose (&actions, errdes); 661*7e120ff0Schristos if (ret) 662*7e120ff0Schristos { 663*7e120ff0Schristos *err = ret; 664*7e120ff0Schristos *errmsg = "posix_spawn_file_actions_addclose"; 665*7e120ff0Schristos goto exit; 666*7e120ff0Schristos } 667*7e120ff0Schristos } 668*7e120ff0Schristos 669*7e120ff0Schristos if (toclose >= 0) 670*7e120ff0Schristos { 671*7e120ff0Schristos ret = posix_spawn_file_actions_addclose (&actions, toclose); 672*7e120ff0Schristos if (ret) 673*7e120ff0Schristos { 674*7e120ff0Schristos *err = ret; 675*7e120ff0Schristos *errmsg = "posix_spawn_file_actions_addclose"; 676*7e120ff0Schristos goto exit; 677*7e120ff0Schristos } 678*7e120ff0Schristos } 679*7e120ff0Schristos 680*7e120ff0Schristos if ((flags & PEX_STDERR_TO_STDOUT) != 0) 681*7e120ff0Schristos { 682*7e120ff0Schristos ret = posix_spawn_file_actions_adddup2 (&actions, STDOUT_FILE_NO, STDERR_FILE_NO); 683*7e120ff0Schristos if (ret) 684*7e120ff0Schristos { 685*7e120ff0Schristos *err = ret; 686*7e120ff0Schristos *errmsg = "posix_spawn_file_actions_adddup2"; 687*7e120ff0Schristos goto exit; 688*7e120ff0Schristos } 689*7e120ff0Schristos } 690*7e120ff0Schristos 691*7e120ff0Schristos if ((flags & PEX_SEARCH) != 0) 692*7e120ff0Schristos { 693*7e120ff0Schristos ret = posix_spawnp (&pid, executable, &actions, &attr, argv, env ? env : environ); 694*7e120ff0Schristos if (ret) 695*7e120ff0Schristos { 696*7e120ff0Schristos *err = ret; 697*7e120ff0Schristos *errmsg = "posix_spawnp"; 698*7e120ff0Schristos goto exit; 699*7e120ff0Schristos } 700*7e120ff0Schristos } 701*7e120ff0Schristos else 702*7e120ff0Schristos { 703*7e120ff0Schristos ret = posix_spawn (&pid, executable, &actions, &attr, argv, env ? env : environ); 704*7e120ff0Schristos if (ret) 705*7e120ff0Schristos { 706*7e120ff0Schristos *err = ret; 707*7e120ff0Schristos *errmsg = "posix_spawn"; 708*7e120ff0Schristos goto exit; 709*7e120ff0Schristos } 710*7e120ff0Schristos } 711*7e120ff0Schristos 712*7e120ff0Schristos exit: 713*7e120ff0Schristos if (actions_initialized) 714*7e120ff0Schristos posix_spawn_file_actions_destroy (&actions); 715*7e120ff0Schristos if (attr_initialized) 716*7e120ff0Schristos posix_spawnattr_destroy (&attr); 717*7e120ff0Schristos 718*7e120ff0Schristos if (!*err && in != STDIN_FILE_NO) 719*7e120ff0Schristos if (close (in)) 720*7e120ff0Schristos *errmsg = "close", *err = errno, pid = -1; 721*7e120ff0Schristos if (!*err && out != STDOUT_FILE_NO) 722*7e120ff0Schristos if (close (out)) 723*7e120ff0Schristos *errmsg = "close", *err = errno, pid = -1; 724*7e120ff0Schristos if (!*err && errdes != STDERR_FILE_NO) 725*7e120ff0Schristos if (close (errdes)) 726*7e120ff0Schristos *errmsg = "close", *err = errno, pid = -1; 727*7e120ff0Schristos 728*7e120ff0Schristos return pid; 729*7e120ff0Schristos } 73098b9484cSchristos #else 73198b9484cSchristos /* Implementation of pex->exec_child using standard vfork + exec. */ 73298b9484cSchristos 73398b9484cSchristos static pid_t 73498b9484cSchristos pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, 73598b9484cSchristos char * const * argv, char * const * env, 73698b9484cSchristos int in, int out, int errdes, 73798b9484cSchristos int toclose, const char **errmsg, int *err) 73898b9484cSchristos { 7394559860eSchristos pid_t pid = -1; 7404559860eSchristos /* Tuple to communicate error from child to parent. We can safely 7414559860eSchristos transfer string literal pointers as both run with identical 7424559860eSchristos address mappings. */ 7434559860eSchristos struct fn_err 7444559860eSchristos { 7454559860eSchristos const char *fn; 7464559860eSchristos int err; 7474559860eSchristos }; 7484559860eSchristos volatile int do_pipe = 0; 7494559860eSchristos volatile int pipes[2]; /* [0]:reader,[1]:writer. */ 7504559860eSchristos #ifdef O_CLOEXEC 7514559860eSchristos do_pipe = 1; 7524559860eSchristos #endif 7534559860eSchristos if (do_pipe) 7544559860eSchristos { 7554559860eSchristos #ifdef HAVE_PIPE2 7564559860eSchristos if (pipe2 ((int *)pipes, O_CLOEXEC)) 7574559860eSchristos do_pipe = 0; 7584559860eSchristos #else 7594559860eSchristos if (pipe ((int *)pipes)) 7604559860eSchristos do_pipe = 0; 7614559860eSchristos else 7624559860eSchristos { 7634559860eSchristos if (fcntl (pipes[1], F_SETFD, FD_CLOEXEC) == -1) 7644559860eSchristos { 7654559860eSchristos close (pipes[0]); 7664559860eSchristos close (pipes[1]); 7674559860eSchristos do_pipe = 0; 7684559860eSchristos } 7694559860eSchristos } 7704559860eSchristos #endif 7714559860eSchristos } 77298b9484cSchristos 77398b9484cSchristos /* We declare these to be volatile to avoid warnings from gcc about 77498b9484cSchristos them being clobbered by vfork. */ 7754559860eSchristos volatile int sleep_interval = 1; 77698b9484cSchristos volatile int retries; 77798b9484cSchristos 77898b9484cSchristos /* We vfork and then set environ in the child before calling execvp. 77998b9484cSchristos This clobbers the parent's environ so we need to restore it. 78098b9484cSchristos It would be nice to use one of the exec* functions that takes an 7814559860eSchristos environment as a parameter, but that may have portability 7824559860eSchristos issues. It is marked volatile so the child doesn't consider it a 7834559860eSchristos dead variable and therefore clobber where ever it is stored. */ 7844559860eSchristos char **volatile save_environ = environ; 78598b9484cSchristos 78698b9484cSchristos for (retries = 0; retries < 4; ++retries) 78798b9484cSchristos { 78898b9484cSchristos pid = vfork (); 78998b9484cSchristos if (pid >= 0) 79098b9484cSchristos break; 79198b9484cSchristos sleep (sleep_interval); 79298b9484cSchristos sleep_interval *= 2; 79398b9484cSchristos } 79498b9484cSchristos 79598b9484cSchristos switch (pid) 79698b9484cSchristos { 79798b9484cSchristos case -1: 7984559860eSchristos if (do_pipe) 7994559860eSchristos { 8004559860eSchristos close (pipes[0]); 8014559860eSchristos close (pipes[1]); 8024559860eSchristos } 80398b9484cSchristos *err = errno; 80498b9484cSchristos *errmsg = VFORK_STRING; 80598b9484cSchristos return (pid_t) -1; 80698b9484cSchristos 80798b9484cSchristos case 0: 80898b9484cSchristos /* Child process. */ 8094559860eSchristos { 8104559860eSchristos struct fn_err failed; 8114559860eSchristos failed.fn = NULL; 8124559860eSchristos 8134559860eSchristos if (do_pipe) 8144559860eSchristos close (pipes[0]); 8154559860eSchristos if (!failed.fn && in != STDIN_FILE_NO) 81698b9484cSchristos { 81798b9484cSchristos if (dup2 (in, STDIN_FILE_NO) < 0) 8184559860eSchristos failed.fn = "dup2", failed.err = errno; 8194559860eSchristos else if (close (in) < 0) 8204559860eSchristos failed.fn = "close", failed.err = errno; 82198b9484cSchristos } 8224559860eSchristos if (!failed.fn && out != STDOUT_FILE_NO) 82398b9484cSchristos { 82498b9484cSchristos if (dup2 (out, STDOUT_FILE_NO) < 0) 8254559860eSchristos failed.fn = "dup2", failed.err = errno; 8264559860eSchristos else if (close (out) < 0) 8274559860eSchristos failed.fn = "close", failed.err = errno; 82898b9484cSchristos } 8294559860eSchristos if (!failed.fn && errdes != STDERR_FILE_NO) 83098b9484cSchristos { 83198b9484cSchristos if (dup2 (errdes, STDERR_FILE_NO) < 0) 8324559860eSchristos failed.fn = "dup2", failed.err = errno; 8334559860eSchristos else if (close (errdes) < 0) 8344559860eSchristos failed.fn = "close", failed.err = errno; 83598b9484cSchristos } 8364559860eSchristos if (!failed.fn && toclose >= 0) 83798b9484cSchristos { 83898b9484cSchristos if (close (toclose) < 0) 8394559860eSchristos failed.fn = "close", failed.err = errno; 84098b9484cSchristos } 8414559860eSchristos if (!failed.fn && (flags & PEX_STDERR_TO_STDOUT) != 0) 84298b9484cSchristos { 84398b9484cSchristos if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0) 8444559860eSchristos failed.fn = "dup2", failed.err = errno; 84598b9484cSchristos } 8464559860eSchristos if (!failed.fn) 84798b9484cSchristos { 8484559860eSchristos if (env) 8494559860eSchristos /* NOTE: In a standard vfork implementation this clobbers 8504559860eSchristos the parent's copy of environ "too" (in reality there's 8514559860eSchristos only one copy). This is ok as we restore it below. */ 85298b9484cSchristos environ = (char**) env; 85398b9484cSchristos if ((flags & PEX_SEARCH) != 0) 85498b9484cSchristos { 85598b9484cSchristos execvp (executable, to_ptr32 (argv)); 8564559860eSchristos failed.fn = "execvp", failed.err = errno; 85798b9484cSchristos } 85898b9484cSchristos else 85998b9484cSchristos { 86098b9484cSchristos execv (executable, to_ptr32 (argv)); 8614559860eSchristos failed.fn = "execv", failed.err = errno; 8624559860eSchristos } 86398b9484cSchristos } 86498b9484cSchristos 8654559860eSchristos /* Something failed, report an error. We don't use stdio 8664559860eSchristos routines, because we might be here due to a vfork call. */ 8674559860eSchristos ssize_t retval = 0; 8684559860eSchristos 8694559860eSchristos if (!do_pipe 8704559860eSchristos || write (pipes[1], &failed, sizeof (failed)) != sizeof (failed)) 8714559860eSchristos { 8724559860eSchristos /* The parent will not see our scream above, so write to 8734559860eSchristos stdout. */ 8744559860eSchristos #define writeerr(s) (retval |= write (STDERR_FILE_NO, s, strlen (s))) 8754559860eSchristos writeerr (obj->pname); 8764559860eSchristos writeerr (": error trying to exec '"); 8774559860eSchristos writeerr (executable); 8784559860eSchristos writeerr ("': "); 8794559860eSchristos writeerr (failed.fn); 8804559860eSchristos writeerr (": "); 8814559860eSchristos writeerr (xstrerror (failed.err)); 8824559860eSchristos writeerr ("\n"); 8834559860eSchristos #undef writeerr 8844559860eSchristos } 8854559860eSchristos 8864559860eSchristos /* Exit with -2 if the error output failed, too. */ 8874559860eSchristos _exit (retval < 0 ? -2 : -1); 8884559860eSchristos } 88998b9484cSchristos /* NOTREACHED */ 89098b9484cSchristos return (pid_t) -1; 89198b9484cSchristos 89298b9484cSchristos default: 89398b9484cSchristos /* Parent process. */ 8944559860eSchristos { 8954559860eSchristos /* Restore environ. Note that the parent either doesn't run 8964559860eSchristos until the child execs/exits (standard vfork behaviour), or 8974559860eSchristos if it does run then vfork is behaving more like fork. In 8984559860eSchristos either case we needn't worry about clobbering the child's 8994559860eSchristos copy of environ. */ 90098b9484cSchristos environ = save_environ; 90198b9484cSchristos 9024559860eSchristos struct fn_err failed; 9034559860eSchristos failed.fn = NULL; 9044559860eSchristos if (do_pipe) 90598b9484cSchristos { 9064559860eSchristos close (pipes[1]); 9074559860eSchristos ssize_t len = read (pipes[0], &failed, sizeof (failed)); 9084559860eSchristos if (len < 0) 9094559860eSchristos failed.fn = NULL; 9104559860eSchristos close (pipes[0]); 91198b9484cSchristos } 91298b9484cSchristos 9134559860eSchristos if (!failed.fn && in != STDIN_FILE_NO) 9144559860eSchristos if (close (in) < 0) 9154559860eSchristos failed.fn = "close", failed.err = errno; 9164559860eSchristos if (!failed.fn && out != STDOUT_FILE_NO) 9174559860eSchristos if (close (out) < 0) 9184559860eSchristos failed.fn = "close", failed.err = errno; 9194559860eSchristos if (!failed.fn && errdes != STDERR_FILE_NO) 9204559860eSchristos if (close (errdes) < 0) 9214559860eSchristos failed.fn = "close", failed.err = errno; 9224559860eSchristos 9234559860eSchristos if (failed.fn) 9244559860eSchristos { 9254559860eSchristos *err = failed.err; 9264559860eSchristos *errmsg = failed.fn; 9274559860eSchristos return (pid_t) -1; 9284559860eSchristos } 9294559860eSchristos } 93098b9484cSchristos return pid; 93198b9484cSchristos } 93298b9484cSchristos } 93398b9484cSchristos #endif /* SPAWN */ 93498b9484cSchristos 93598b9484cSchristos /* Wait for a child process to complete. */ 93698b9484cSchristos 937*7e120ff0Schristos static pid_t 93898b9484cSchristos pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status, 93998b9484cSchristos struct pex_time *time, int done, const char **errmsg, 94098b9484cSchristos int *err) 94198b9484cSchristos { 94298b9484cSchristos /* If we are cleaning up when the caller didn't retrieve process 94398b9484cSchristos status for some reason, encourage the process to go away. */ 94498b9484cSchristos if (done) 94598b9484cSchristos kill (pid, SIGTERM); 94698b9484cSchristos 94798b9484cSchristos if (pex_wait (obj, pid, status, time) < 0) 94898b9484cSchristos { 94998b9484cSchristos *err = errno; 95098b9484cSchristos *errmsg = "wait"; 95198b9484cSchristos return -1; 95298b9484cSchristos } 95398b9484cSchristos 95498b9484cSchristos return 0; 95598b9484cSchristos } 95698b9484cSchristos 95798b9484cSchristos /* Create a pipe. */ 95898b9484cSchristos 95998b9484cSchristos static int 96098b9484cSchristos pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p, 96198b9484cSchristos int binary ATTRIBUTE_UNUSED) 96298b9484cSchristos { 96398b9484cSchristos return pipe (p); 96498b9484cSchristos } 96598b9484cSchristos 96698b9484cSchristos /* Get a FILE pointer to read from a file descriptor. */ 96798b9484cSchristos 96898b9484cSchristos static FILE * 96998b9484cSchristos pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, 97098b9484cSchristos int binary ATTRIBUTE_UNUSED) 97198b9484cSchristos { 97298b9484cSchristos return fdopen (fd, "r"); 97398b9484cSchristos } 97498b9484cSchristos 97598b9484cSchristos static FILE * 97698b9484cSchristos pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, 97798b9484cSchristos int binary ATTRIBUTE_UNUSED) 97898b9484cSchristos { 97998b9484cSchristos if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) 98098b9484cSchristos return NULL; 98198b9484cSchristos return fdopen (fd, "w"); 98298b9484cSchristos } 98398b9484cSchristos 98498b9484cSchristos static void 98598b9484cSchristos pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED) 98698b9484cSchristos { 98798b9484cSchristos #if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID) 98898b9484cSchristos while (obj->sysdep != NULL) 98998b9484cSchristos { 99098b9484cSchristos struct status_list *this; 99198b9484cSchristos struct status_list *next; 99298b9484cSchristos 99398b9484cSchristos this = (struct status_list *) obj->sysdep; 99498b9484cSchristos next = this->next; 99598b9484cSchristos free (this); 99698b9484cSchristos obj->sysdep = (void *) next; 99798b9484cSchristos } 99898b9484cSchristos #endif 99998b9484cSchristos } 1000