12a6b7db3Sskrll /* Utilities to execute a program in a subprocess (possibly linked by pipes
22a6b7db3Sskrll with other subprocesses), and wait for it. Generic Unix version
32a6b7db3Sskrll (also used for UWIN and VMS).
4*cb63e24eSchristos Copyright (C) 1996-2024 Free Software Foundation, Inc.
52a6b7db3Sskrll
62a6b7db3Sskrll This file is part of the libiberty library.
72a6b7db3Sskrll Libiberty is free software; you can redistribute it and/or
82a6b7db3Sskrll modify it under the terms of the GNU Library General Public
92a6b7db3Sskrll License as published by the Free Software Foundation; either
102a6b7db3Sskrll version 2 of the License, or (at your option) any later version.
112a6b7db3Sskrll
122a6b7db3Sskrll Libiberty is distributed in the hope that it will be useful,
132a6b7db3Sskrll but WITHOUT ANY WARRANTY; without even the implied warranty of
142a6b7db3Sskrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
152a6b7db3Sskrll Library General Public License for more details.
162a6b7db3Sskrll
172a6b7db3Sskrll You should have received a copy of the GNU Library General Public
182a6b7db3Sskrll License along with libiberty; see the file COPYING.LIB. If not,
192a6b7db3Sskrll write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
202a6b7db3Sskrll Boston, MA 02110-1301, USA. */
212a6b7db3Sskrll
222a6b7db3Sskrll #include "config.h"
232a6b7db3Sskrll #include "libiberty.h"
242a6b7db3Sskrll #include "pex-common.h"
258cbf5cb7Schristos #include "environ.h"
262a6b7db3Sskrll
272a6b7db3Sskrll #include <stdio.h>
282a6b7db3Sskrll #include <signal.h>
292a6b7db3Sskrll #include <errno.h>
302a6b7db3Sskrll #ifdef NEED_DECLARATION_ERRNO
312a6b7db3Sskrll extern int errno;
322a6b7db3Sskrll #endif
332a6b7db3Sskrll #ifdef HAVE_STDLIB_H
342a6b7db3Sskrll #include <stdlib.h>
352a6b7db3Sskrll #endif
362a6b7db3Sskrll #ifdef HAVE_STRING_H
372a6b7db3Sskrll #include <string.h>
382a6b7db3Sskrll #endif
392a6b7db3Sskrll #ifdef HAVE_UNISTD_H
402a6b7db3Sskrll #include <unistd.h>
412a6b7db3Sskrll #endif
422a6b7db3Sskrll
432a6b7db3Sskrll #include <sys/types.h>
442a6b7db3Sskrll
452a6b7db3Sskrll #ifdef HAVE_FCNTL_H
462a6b7db3Sskrll #include <fcntl.h>
472a6b7db3Sskrll #endif
482a6b7db3Sskrll #ifdef HAVE_SYS_WAIT_H
492a6b7db3Sskrll #include <sys/wait.h>
502a6b7db3Sskrll #endif
512a6b7db3Sskrll #ifdef HAVE_GETRUSAGE
522a6b7db3Sskrll #include <sys/time.h>
532a6b7db3Sskrll #include <sys/resource.h>
542a6b7db3Sskrll #endif
552a6b7db3Sskrll #ifdef HAVE_SYS_STAT_H
562a6b7db3Sskrll #include <sys/stat.h>
572a6b7db3Sskrll #endif
58be9ac0eaSchristos #ifdef HAVE_PROCESS_H
59be9ac0eaSchristos #include <process.h>
60be9ac0eaSchristos #endif
61*cb63e24eSchristos #ifdef HAVE_SPAWN_H
62*cb63e24eSchristos #include <spawn.h>
63*cb63e24eSchristos #endif
642a6b7db3Sskrll
652a6b7db3Sskrll #ifdef vfork /* Autoconf may define this to fork for us. */
662a6b7db3Sskrll # define VFORK_STRING "fork"
672a6b7db3Sskrll #else
682a6b7db3Sskrll # define VFORK_STRING "vfork"
692a6b7db3Sskrll #endif
702a6b7db3Sskrll #ifdef HAVE_VFORK_H
712a6b7db3Sskrll #include <vfork.h>
722a6b7db3Sskrll #endif
73be9ac0eaSchristos #if defined(VMS) && defined (__LONG_POINTERS)
74be9ac0eaSchristos #ifndef __CHAR_PTR32
75be9ac0eaSchristos typedef char * __char_ptr32
76be9ac0eaSchristos __attribute__ ((mode (SI)));
77be9ac0eaSchristos #endif
782a6b7db3Sskrll
79be9ac0eaSchristos typedef __char_ptr32 *__char_ptr_char_ptr32
80be9ac0eaSchristos __attribute__ ((mode (SI)));
81be9ac0eaSchristos
82be9ac0eaSchristos /* Return a 32 bit pointer to an array of 32 bit pointers
83be9ac0eaSchristos given a 64 bit pointer to an array of 64 bit pointers. */
84be9ac0eaSchristos
85be9ac0eaSchristos static __char_ptr_char_ptr32
to_ptr32(char ** ptr64)86be9ac0eaSchristos to_ptr32 (char **ptr64)
87be9ac0eaSchristos {
88be9ac0eaSchristos int argc;
89be9ac0eaSchristos __char_ptr_char_ptr32 short_argv;
90be9ac0eaSchristos
91883529b6Schristos /* Count number of arguments. */
92883529b6Schristos for (argc = 0; ptr64[argc] != NULL; argc++)
93883529b6Schristos ;
94be9ac0eaSchristos
95be9ac0eaSchristos /* Reallocate argv with 32 bit pointers. */
96be9ac0eaSchristos short_argv = (__char_ptr_char_ptr32) decc$malloc
97be9ac0eaSchristos (sizeof (__char_ptr32) * (argc + 1));
98be9ac0eaSchristos
99883529b6Schristos for (argc = 0; ptr64[argc] != NULL; argc++)
100be9ac0eaSchristos short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
101be9ac0eaSchristos
102be9ac0eaSchristos short_argv[argc] = (__char_ptr32) 0;
103be9ac0eaSchristos return short_argv;
104be9ac0eaSchristos
105be9ac0eaSchristos }
106be9ac0eaSchristos #else
107be9ac0eaSchristos #define to_ptr32(argv) argv
108be9ac0eaSchristos #endif
1092a6b7db3Sskrll
1102a6b7db3Sskrll /* File mode to use for private and world-readable files. */
1112a6b7db3Sskrll
1122a6b7db3Sskrll #if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH)
1132a6b7db3Sskrll #define PUBLIC_MODE \
1142a6b7db3Sskrll (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
1152a6b7db3Sskrll #else
1162a6b7db3Sskrll #define PUBLIC_MODE 0666
1172a6b7db3Sskrll #endif
1182a6b7db3Sskrll
1192a6b7db3Sskrll /* Get the exit status of a particular process, and optionally get the
1202a6b7db3Sskrll time that it took. This is simple if we have wait4, slightly
1212a6b7db3Sskrll harder if we have waitpid, and is a pain if we only have wait. */
1222a6b7db3Sskrll
1232a6b7db3Sskrll static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *);
1242a6b7db3Sskrll
1252a6b7db3Sskrll #ifdef HAVE_WAIT4
1262a6b7db3Sskrll
1272a6b7db3Sskrll static pid_t
pex_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time)1282a6b7db3Sskrll pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
1292a6b7db3Sskrll struct pex_time *time)
1302a6b7db3Sskrll {
1312a6b7db3Sskrll pid_t ret;
1322a6b7db3Sskrll struct rusage r;
1332a6b7db3Sskrll
1342a6b7db3Sskrll #ifdef HAVE_WAITPID
1352a6b7db3Sskrll if (time == NULL)
1362a6b7db3Sskrll return waitpid (pid, status, 0);
1372a6b7db3Sskrll #endif
1382a6b7db3Sskrll
1392a6b7db3Sskrll ret = wait4 (pid, status, 0, &r);
1402a6b7db3Sskrll
1412a6b7db3Sskrll if (time != NULL)
1422a6b7db3Sskrll {
1432a6b7db3Sskrll time->user_seconds = r.ru_utime.tv_sec;
1442a6b7db3Sskrll time->user_microseconds= r.ru_utime.tv_usec;
1452a6b7db3Sskrll time->system_seconds = r.ru_stime.tv_sec;
1462a6b7db3Sskrll time->system_microseconds= r.ru_stime.tv_usec;
1472a6b7db3Sskrll }
1482a6b7db3Sskrll
1492a6b7db3Sskrll return ret;
1502a6b7db3Sskrll }
1512a6b7db3Sskrll
1522a6b7db3Sskrll #else /* ! defined (HAVE_WAIT4) */
1532a6b7db3Sskrll
1542a6b7db3Sskrll #ifdef HAVE_WAITPID
1552a6b7db3Sskrll
1562a6b7db3Sskrll #ifndef HAVE_GETRUSAGE
1572a6b7db3Sskrll
1582a6b7db3Sskrll static pid_t
pex_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time)1592a6b7db3Sskrll pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
1602a6b7db3Sskrll struct pex_time *time)
1612a6b7db3Sskrll {
1622a6b7db3Sskrll if (time != NULL)
1632a6b7db3Sskrll memset (time, 0, sizeof (struct pex_time));
1642a6b7db3Sskrll return waitpid (pid, status, 0);
1652a6b7db3Sskrll }
1662a6b7db3Sskrll
1672a6b7db3Sskrll #else /* defined (HAVE_GETRUSAGE) */
1682a6b7db3Sskrll
1692a6b7db3Sskrll static pid_t
pex_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time)1702a6b7db3Sskrll pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
1712a6b7db3Sskrll struct pex_time *time)
1722a6b7db3Sskrll {
1732a6b7db3Sskrll struct rusage r1, r2;
1742a6b7db3Sskrll pid_t ret;
1752a6b7db3Sskrll
1762a6b7db3Sskrll if (time == NULL)
1772a6b7db3Sskrll return waitpid (pid, status, 0);
1782a6b7db3Sskrll
1792a6b7db3Sskrll getrusage (RUSAGE_CHILDREN, &r1);
1802a6b7db3Sskrll
1812a6b7db3Sskrll ret = waitpid (pid, status, 0);
1822a6b7db3Sskrll if (ret < 0)
1832a6b7db3Sskrll return ret;
1842a6b7db3Sskrll
1852a6b7db3Sskrll getrusage (RUSAGE_CHILDREN, &r2);
1862a6b7db3Sskrll
1872a6b7db3Sskrll time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
1882a6b7db3Sskrll time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
1892a6b7db3Sskrll if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec)
1902a6b7db3Sskrll {
1912a6b7db3Sskrll --time->user_seconds;
1922a6b7db3Sskrll time->user_microseconds += 1000000;
1932a6b7db3Sskrll }
1942a6b7db3Sskrll
1952a6b7db3Sskrll time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
1962a6b7db3Sskrll time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
1972a6b7db3Sskrll if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec)
1982a6b7db3Sskrll {
1992a6b7db3Sskrll --time->system_seconds;
2002a6b7db3Sskrll time->system_microseconds += 1000000;
2012a6b7db3Sskrll }
2022a6b7db3Sskrll
2032a6b7db3Sskrll return ret;
2042a6b7db3Sskrll }
2052a6b7db3Sskrll
2062a6b7db3Sskrll #endif /* defined (HAVE_GETRUSAGE) */
2072a6b7db3Sskrll
2082a6b7db3Sskrll #else /* ! defined (HAVE_WAITPID) */
2092a6b7db3Sskrll
2102a6b7db3Sskrll struct status_list
2112a6b7db3Sskrll {
2122a6b7db3Sskrll struct status_list *next;
2132a6b7db3Sskrll pid_t pid;
2142a6b7db3Sskrll int status;
2152a6b7db3Sskrll struct pex_time time;
2162a6b7db3Sskrll };
2172a6b7db3Sskrll
2182a6b7db3Sskrll static pid_t
pex_wait(struct pex_obj * obj,pid_t pid,int * status,struct pex_time * time)2192a6b7db3Sskrll pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time)
2202a6b7db3Sskrll {
2212a6b7db3Sskrll struct status_list **pp;
2222a6b7db3Sskrll
2232a6b7db3Sskrll for (pp = (struct status_list **) &obj->sysdep;
2242a6b7db3Sskrll *pp != NULL;
2252a6b7db3Sskrll pp = &(*pp)->next)
2262a6b7db3Sskrll {
2272a6b7db3Sskrll if ((*pp)->pid == pid)
2282a6b7db3Sskrll {
2292a6b7db3Sskrll struct status_list *p;
2302a6b7db3Sskrll
2312a6b7db3Sskrll p = *pp;
2322a6b7db3Sskrll *status = p->status;
2332a6b7db3Sskrll if (time != NULL)
2342a6b7db3Sskrll *time = p->time;
2352a6b7db3Sskrll *pp = p->next;
2362a6b7db3Sskrll free (p);
2372a6b7db3Sskrll return pid;
2382a6b7db3Sskrll }
2392a6b7db3Sskrll }
2402a6b7db3Sskrll
2412a6b7db3Sskrll while (1)
2422a6b7db3Sskrll {
2432a6b7db3Sskrll pid_t cpid;
2442a6b7db3Sskrll struct status_list *psl;
2452a6b7db3Sskrll struct pex_time pt;
2462a6b7db3Sskrll #ifdef HAVE_GETRUSAGE
2472a6b7db3Sskrll struct rusage r1, r2;
2482a6b7db3Sskrll #endif
2492a6b7db3Sskrll
2502a6b7db3Sskrll if (time != NULL)
2512a6b7db3Sskrll {
2522a6b7db3Sskrll #ifdef HAVE_GETRUSAGE
2532a6b7db3Sskrll getrusage (RUSAGE_CHILDREN, &r1);
2542a6b7db3Sskrll #else
2552a6b7db3Sskrll memset (&pt, 0, sizeof (struct pex_time));
2562a6b7db3Sskrll #endif
2572a6b7db3Sskrll }
2582a6b7db3Sskrll
2592a6b7db3Sskrll cpid = wait (status);
2602a6b7db3Sskrll
2612a6b7db3Sskrll #ifdef HAVE_GETRUSAGE
2622a6b7db3Sskrll if (time != NULL && cpid >= 0)
2632a6b7db3Sskrll {
2642a6b7db3Sskrll getrusage (RUSAGE_CHILDREN, &r2);
2652a6b7db3Sskrll
2662a6b7db3Sskrll pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
2672a6b7db3Sskrll pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
2682a6b7db3Sskrll if (pt.user_microseconds < 0)
2692a6b7db3Sskrll {
2702a6b7db3Sskrll --pt.user_seconds;
2712a6b7db3Sskrll pt.user_microseconds += 1000000;
2722a6b7db3Sskrll }
2732a6b7db3Sskrll
2742a6b7db3Sskrll pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
2752a6b7db3Sskrll pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
2762a6b7db3Sskrll if (pt.system_microseconds < 0)
2772a6b7db3Sskrll {
2782a6b7db3Sskrll --pt.system_seconds;
2792a6b7db3Sskrll pt.system_microseconds += 1000000;
2802a6b7db3Sskrll }
2812a6b7db3Sskrll }
2822a6b7db3Sskrll #endif
2832a6b7db3Sskrll
2842a6b7db3Sskrll if (cpid < 0 || cpid == pid)
2852a6b7db3Sskrll {
2862a6b7db3Sskrll if (time != NULL)
2872a6b7db3Sskrll *time = pt;
2882a6b7db3Sskrll return cpid;
2892a6b7db3Sskrll }
2902a6b7db3Sskrll
2912a6b7db3Sskrll psl = XNEW (struct status_list);
2922a6b7db3Sskrll psl->pid = cpid;
2932a6b7db3Sskrll psl->status = *status;
2942a6b7db3Sskrll if (time != NULL)
2952a6b7db3Sskrll psl->time = pt;
2962a6b7db3Sskrll psl->next = (struct status_list *) obj->sysdep;
2972a6b7db3Sskrll obj->sysdep = (void *) psl;
2982a6b7db3Sskrll }
2992a6b7db3Sskrll }
3002a6b7db3Sskrll
3012a6b7db3Sskrll #endif /* ! defined (HAVE_WAITPID) */
3022a6b7db3Sskrll #endif /* ! defined (HAVE_WAIT4) */
3032a6b7db3Sskrll
3042a6b7db3Sskrll static int pex_unix_open_read (struct pex_obj *, const char *, int);
3059573673dSchristos static int pex_unix_open_write (struct pex_obj *, const char *, int, int);
3062a6b7db3Sskrll static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *,
3072a6b7db3Sskrll char * const *, char * const *,
3082a6b7db3Sskrll int, int, int, int,
3092a6b7db3Sskrll const char **, int *);
3102a6b7db3Sskrll static int pex_unix_close (struct pex_obj *, int);
311*cb63e24eSchristos static pid_t pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
3122a6b7db3Sskrll int, const char **, int *);
3132a6b7db3Sskrll static int pex_unix_pipe (struct pex_obj *, int *, int);
3142a6b7db3Sskrll static FILE *pex_unix_fdopenr (struct pex_obj *, int, int);
3152a6b7db3Sskrll static FILE *pex_unix_fdopenw (struct pex_obj *, int, int);
3162a6b7db3Sskrll static void pex_unix_cleanup (struct pex_obj *);
3172a6b7db3Sskrll
3182a6b7db3Sskrll /* The list of functions we pass to the common routines. */
3192a6b7db3Sskrll
3202a6b7db3Sskrll const struct pex_funcs funcs =
3212a6b7db3Sskrll {
3222a6b7db3Sskrll pex_unix_open_read,
3232a6b7db3Sskrll pex_unix_open_write,
3242a6b7db3Sskrll pex_unix_exec_child,
3252a6b7db3Sskrll pex_unix_close,
3262a6b7db3Sskrll pex_unix_wait,
3272a6b7db3Sskrll pex_unix_pipe,
3282a6b7db3Sskrll pex_unix_fdopenr,
3292a6b7db3Sskrll pex_unix_fdopenw,
3302a6b7db3Sskrll pex_unix_cleanup
3312a6b7db3Sskrll };
3322a6b7db3Sskrll
3332a6b7db3Sskrll /* Return a newly initialized pex_obj structure. */
3342a6b7db3Sskrll
3352a6b7db3Sskrll struct pex_obj *
pex_init(int flags,const char * pname,const char * tempbase)3362a6b7db3Sskrll pex_init (int flags, const char *pname, const char *tempbase)
3372a6b7db3Sskrll {
3382a6b7db3Sskrll return pex_init_common (flags, pname, tempbase, &funcs);
3392a6b7db3Sskrll }
3402a6b7db3Sskrll
3412a6b7db3Sskrll /* Open a file for reading. */
3422a6b7db3Sskrll
3432a6b7db3Sskrll static int
pex_unix_open_read(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary ATTRIBUTE_UNUSED)3442a6b7db3Sskrll pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
3452a6b7db3Sskrll int binary ATTRIBUTE_UNUSED)
3462a6b7db3Sskrll {
3472a6b7db3Sskrll return open (name, O_RDONLY);
3482a6b7db3Sskrll }
3492a6b7db3Sskrll
3502a6b7db3Sskrll /* Open a file for writing. */
3512a6b7db3Sskrll
3522a6b7db3Sskrll static int
pex_unix_open_write(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary ATTRIBUTE_UNUSED,int append)3532a6b7db3Sskrll pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
3549573673dSchristos int binary ATTRIBUTE_UNUSED, int append)
3552a6b7db3Sskrll {
3562a6b7db3Sskrll /* Note that we can't use O_EXCL here because gcc may have already
3572a6b7db3Sskrll created the temporary file via make_temp_file. */
3589573673dSchristos return open (name, O_WRONLY | O_CREAT
3599573673dSchristos | (append ? O_APPEND : O_TRUNC), PUBLIC_MODE);
3602a6b7db3Sskrll }
3612a6b7db3Sskrll
3622a6b7db3Sskrll /* Close a file. */
3632a6b7db3Sskrll
3642a6b7db3Sskrll static int
pex_unix_close(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd)3652a6b7db3Sskrll pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
3662a6b7db3Sskrll {
3672a6b7db3Sskrll return close (fd);
3682a6b7db3Sskrll }
3692a6b7db3Sskrll
3702a6b7db3Sskrll /* Execute a child. */
3712a6b7db3Sskrll
372be9ac0eaSchristos #if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE)
373be9ac0eaSchristos /* Implementation of pex->exec_child using the Cygwin spawn operation. */
374be9ac0eaSchristos
375be9ac0eaSchristos /* Subroutine of pex_unix_exec_child. Move OLD_FD to a new file descriptor
376be9ac0eaSchristos to be stored in *PNEW_FD, save the flags in *PFLAGS, and arrange for the
377be9ac0eaSchristos saved copy to be close-on-exec. Move CHILD_FD into OLD_FD. If CHILD_FD
378be9ac0eaSchristos is -1, OLD_FD is to be closed. Return -1 on error. */
379be9ac0eaSchristos
380be9ac0eaSchristos static int
save_and_install_fd(int * pnew_fd,int * pflags,int old_fd,int child_fd)381be9ac0eaSchristos save_and_install_fd(int *pnew_fd, int *pflags, int old_fd, int child_fd)
382be9ac0eaSchristos {
383be9ac0eaSchristos int new_fd, flags;
384be9ac0eaSchristos
385be9ac0eaSchristos flags = fcntl (old_fd, F_GETFD);
386be9ac0eaSchristos
387be9ac0eaSchristos /* If we could not retrieve the flags, then OLD_FD was not open. */
388be9ac0eaSchristos if (flags < 0)
389be9ac0eaSchristos {
390be9ac0eaSchristos new_fd = -1, flags = 0;
391be9ac0eaSchristos if (child_fd >= 0 && dup2 (child_fd, old_fd) < 0)
392be9ac0eaSchristos return -1;
393be9ac0eaSchristos }
394be9ac0eaSchristos /* If we wish to close OLD_FD, just mark it CLOEXEC. */
395be9ac0eaSchristos else if (child_fd == -1)
396be9ac0eaSchristos {
397be9ac0eaSchristos new_fd = old_fd;
398be9ac0eaSchristos if ((flags & FD_CLOEXEC) == 0 && fcntl (old_fd, F_SETFD, FD_CLOEXEC) < 0)
399be9ac0eaSchristos return -1;
400be9ac0eaSchristos }
401be9ac0eaSchristos /* Otherwise we need to save a copy of OLD_FD before installing CHILD_FD. */
402be9ac0eaSchristos else
403be9ac0eaSchristos {
404be9ac0eaSchristos #ifdef F_DUPFD_CLOEXEC
405be9ac0eaSchristos new_fd = fcntl (old_fd, F_DUPFD_CLOEXEC, 3);
406be9ac0eaSchristos if (new_fd < 0)
407be9ac0eaSchristos return -1;
408be9ac0eaSchristos #else
409be9ac0eaSchristos /* Prefer F_DUPFD over dup in order to avoid getting a new fd
410be9ac0eaSchristos in the range 0-2, right where a new stderr fd might get put. */
411be9ac0eaSchristos new_fd = fcntl (old_fd, F_DUPFD, 3);
412be9ac0eaSchristos if (new_fd < 0)
413be9ac0eaSchristos return -1;
414be9ac0eaSchristos if (fcntl (new_fd, F_SETFD, FD_CLOEXEC) < 0)
415be9ac0eaSchristos return -1;
416be9ac0eaSchristos #endif
417be9ac0eaSchristos if (dup2 (child_fd, old_fd) < 0)
418be9ac0eaSchristos return -1;
419be9ac0eaSchristos }
420be9ac0eaSchristos
421be9ac0eaSchristos *pflags = flags;
422be9ac0eaSchristos if (pnew_fd)
423be9ac0eaSchristos *pnew_fd = new_fd;
424be9ac0eaSchristos else if (new_fd != old_fd)
425be9ac0eaSchristos abort ();
426be9ac0eaSchristos
427be9ac0eaSchristos return 0;
428be9ac0eaSchristos }
429be9ac0eaSchristos
430be9ac0eaSchristos /* Subroutine of pex_unix_exec_child. Move SAVE_FD back to OLD_FD
431be9ac0eaSchristos restoring FLAGS. If SAVE_FD < 0, OLD_FD is to be closed. */
432be9ac0eaSchristos
433be9ac0eaSchristos static int
restore_fd(int old_fd,int save_fd,int flags)434be9ac0eaSchristos restore_fd(int old_fd, int save_fd, int flags)
435be9ac0eaSchristos {
436be9ac0eaSchristos /* For SAVE_FD < 0, all we have to do is restore the
437be9ac0eaSchristos "closed-ness" of the original. */
438be9ac0eaSchristos if (save_fd < 0)
439be9ac0eaSchristos return close (old_fd);
440be9ac0eaSchristos
441be9ac0eaSchristos /* For SAVE_FD == OLD_FD, all we have to do is restore the
442be9ac0eaSchristos original setting of the CLOEXEC flag. */
443be9ac0eaSchristos if (save_fd == old_fd)
444be9ac0eaSchristos {
445be9ac0eaSchristos if (flags & FD_CLOEXEC)
446be9ac0eaSchristos return 0;
447be9ac0eaSchristos return fcntl (old_fd, F_SETFD, flags);
448be9ac0eaSchristos }
449be9ac0eaSchristos
450be9ac0eaSchristos /* Otherwise we have to move the descriptor back, restore the flags,
451be9ac0eaSchristos and close the saved copy. */
452be9ac0eaSchristos #ifdef HAVE_DUP3
453be9ac0eaSchristos if (flags == FD_CLOEXEC)
454be9ac0eaSchristos {
455be9ac0eaSchristos if (dup3 (save_fd, old_fd, O_CLOEXEC) < 0)
456be9ac0eaSchristos return -1;
457be9ac0eaSchristos }
458be9ac0eaSchristos else
459be9ac0eaSchristos #endif
460be9ac0eaSchristos {
461be9ac0eaSchristos if (dup2 (save_fd, old_fd) < 0)
462be9ac0eaSchristos return -1;
463be9ac0eaSchristos if (flags != 0 && fcntl (old_fd, F_SETFD, flags) < 0)
464be9ac0eaSchristos return -1;
465be9ac0eaSchristos }
466be9ac0eaSchristos return close (save_fd);
467be9ac0eaSchristos }
468be9ac0eaSchristos
469be9ac0eaSchristos static pid_t
pex_unix_exec_child(struct pex_obj * obj ATTRIBUTE_UNUSED,int flags,const char * executable,char * const * argv,char * const * env,int in,int out,int errdes,int toclose,const char ** errmsg,int * err)470be9ac0eaSchristos pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED,
471be9ac0eaSchristos int flags, const char *executable,
472be9ac0eaSchristos char * const * argv, char * const * env,
473be9ac0eaSchristos int in, int out, int errdes, int toclose,
474be9ac0eaSchristos const char **errmsg, int *err)
475be9ac0eaSchristos {
476be9ac0eaSchristos int fl_in = 0, fl_out = 0, fl_err = 0, fl_tc = 0;
477be9ac0eaSchristos int save_in = -1, save_out = -1, save_err = -1;
478be9ac0eaSchristos int max, retries;
479be9ac0eaSchristos pid_t pid;
480be9ac0eaSchristos
481be9ac0eaSchristos if (flags & PEX_STDERR_TO_STDOUT)
482be9ac0eaSchristos errdes = out;
483be9ac0eaSchristos
484be9ac0eaSchristos /* We need the three standard file descriptors to be set up as for
485be9ac0eaSchristos the child before we perform the spawn. The file descriptors for
486be9ac0eaSchristos the parent need to be moved and marked for close-on-exec. */
487be9ac0eaSchristos if (in != STDIN_FILE_NO
488be9ac0eaSchristos && save_and_install_fd (&save_in, &fl_in, STDIN_FILE_NO, in) < 0)
489be9ac0eaSchristos goto error_dup2;
490be9ac0eaSchristos if (out != STDOUT_FILE_NO
491be9ac0eaSchristos && save_and_install_fd (&save_out, &fl_out, STDOUT_FILE_NO, out) < 0)
492be9ac0eaSchristos goto error_dup2;
493be9ac0eaSchristos if (errdes != STDERR_FILE_NO
494be9ac0eaSchristos && save_and_install_fd (&save_err, &fl_err, STDERR_FILE_NO, errdes) < 0)
495be9ac0eaSchristos goto error_dup2;
496be9ac0eaSchristos if (toclose >= 0
497be9ac0eaSchristos && save_and_install_fd (NULL, &fl_tc, toclose, -1) < 0)
498be9ac0eaSchristos goto error_dup2;
499be9ac0eaSchristos
500be9ac0eaSchristos /* Now that we've moved the file descriptors for the child into place,
501be9ac0eaSchristos close the originals. Be careful not to close any of the standard
502be9ac0eaSchristos file descriptors that we just set up. */
503be9ac0eaSchristos max = -1;
504be9ac0eaSchristos if (errdes >= 0)
505be9ac0eaSchristos max = STDERR_FILE_NO;
506be9ac0eaSchristos else if (out >= 0)
507be9ac0eaSchristos max = STDOUT_FILE_NO;
508be9ac0eaSchristos else if (in >= 0)
509be9ac0eaSchristos max = STDIN_FILE_NO;
510be9ac0eaSchristos if (in > max)
511be9ac0eaSchristos close (in);
512be9ac0eaSchristos if (out > max)
513be9ac0eaSchristos close (out);
514be9ac0eaSchristos if (errdes > max && errdes != out)
515be9ac0eaSchristos close (errdes);
516be9ac0eaSchristos
517be9ac0eaSchristos /* If we were not given an environment, use the global environment. */
518be9ac0eaSchristos if (env == NULL)
519be9ac0eaSchristos env = environ;
520be9ac0eaSchristos
521be9ac0eaSchristos /* Launch the program. If we get EAGAIN (normally out of pid's), try
522be9ac0eaSchristos again a few times with increasing backoff times. */
523be9ac0eaSchristos retries = 0;
524be9ac0eaSchristos while (1)
525be9ac0eaSchristos {
526be9ac0eaSchristos typedef const char * const *cc_cp;
527be9ac0eaSchristos
528be9ac0eaSchristos if (flags & PEX_SEARCH)
529be9ac0eaSchristos pid = spawnvpe (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
530be9ac0eaSchristos else
531be9ac0eaSchristos pid = spawnve (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
532be9ac0eaSchristos
533be9ac0eaSchristos if (pid > 0)
534be9ac0eaSchristos break;
535be9ac0eaSchristos
536be9ac0eaSchristos *err = errno;
537be9ac0eaSchristos *errmsg = "spawn";
538be9ac0eaSchristos if (errno != EAGAIN || ++retries == 4)
539be9ac0eaSchristos return (pid_t) -1;
540be9ac0eaSchristos sleep (1 << retries);
541be9ac0eaSchristos }
542be9ac0eaSchristos
543be9ac0eaSchristos /* Success. Restore the parent's file descriptors that we saved above. */
544be9ac0eaSchristos if (toclose >= 0
545be9ac0eaSchristos && restore_fd (toclose, toclose, fl_tc) < 0)
546be9ac0eaSchristos goto error_dup2;
547be9ac0eaSchristos if (in != STDIN_FILE_NO
548be9ac0eaSchristos && restore_fd (STDIN_FILE_NO, save_in, fl_in) < 0)
549be9ac0eaSchristos goto error_dup2;
550be9ac0eaSchristos if (out != STDOUT_FILE_NO
551be9ac0eaSchristos && restore_fd (STDOUT_FILE_NO, save_out, fl_out) < 0)
552be9ac0eaSchristos goto error_dup2;
553be9ac0eaSchristos if (errdes != STDERR_FILE_NO
554be9ac0eaSchristos && restore_fd (STDERR_FILE_NO, save_err, fl_err) < 0)
555be9ac0eaSchristos goto error_dup2;
556be9ac0eaSchristos
557be9ac0eaSchristos return pid;
558be9ac0eaSchristos
559be9ac0eaSchristos error_dup2:
560be9ac0eaSchristos *err = errno;
561be9ac0eaSchristos *errmsg = "dup2";
562be9ac0eaSchristos return (pid_t) -1;
563be9ac0eaSchristos }
564be9ac0eaSchristos
565*cb63e24eSchristos #elif defined(HAVE_POSIX_SPAWN) && defined(HAVE_POSIX_SPAWNP)
566*cb63e24eSchristos /* Implementation of pex->exec_child using posix_spawn. */
567*cb63e24eSchristos
568*cb63e24eSchristos static pid_t
pex_unix_exec_child(struct pex_obj * obj ATTRIBUTE_UNUSED,int flags,const char * executable,char * const * argv,char * const * env,int in,int out,int errdes,int toclose,const char ** errmsg,int * err)569*cb63e24eSchristos pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED,
570*cb63e24eSchristos int flags, const char *executable,
571*cb63e24eSchristos char * const * argv, char * const * env,
572*cb63e24eSchristos int in, int out, int errdes,
573*cb63e24eSchristos int toclose, const char **errmsg, int *err)
574*cb63e24eSchristos {
575*cb63e24eSchristos int ret;
576*cb63e24eSchristos pid_t pid = -1;
577*cb63e24eSchristos posix_spawnattr_t attr;
578*cb63e24eSchristos posix_spawn_file_actions_t actions;
579*cb63e24eSchristos int attr_initialized = 0, actions_initialized = 0;
580*cb63e24eSchristos
581*cb63e24eSchristos *err = 0;
582*cb63e24eSchristos
583*cb63e24eSchristos ret = posix_spawnattr_init (&attr);
584*cb63e24eSchristos if (ret)
585*cb63e24eSchristos {
586*cb63e24eSchristos *err = ret;
587*cb63e24eSchristos *errmsg = "posix_spawnattr_init";
588*cb63e24eSchristos goto exit;
589*cb63e24eSchristos }
590*cb63e24eSchristos attr_initialized = 1;
591*cb63e24eSchristos
592*cb63e24eSchristos /* Use vfork() on glibc <=2.24. */
593*cb63e24eSchristos #ifdef POSIX_SPAWN_USEVFORK
594*cb63e24eSchristos ret = posix_spawnattr_setflags (&attr, POSIX_SPAWN_USEVFORK);
595*cb63e24eSchristos if (ret)
596*cb63e24eSchristos {
597*cb63e24eSchristos *err = ret;
598*cb63e24eSchristos *errmsg = "posix_spawnattr_setflags";
599*cb63e24eSchristos goto exit;
600*cb63e24eSchristos }
601*cb63e24eSchristos #endif
602*cb63e24eSchristos
603*cb63e24eSchristos ret = posix_spawn_file_actions_init (&actions);
604*cb63e24eSchristos if (ret)
605*cb63e24eSchristos {
606*cb63e24eSchristos *err = ret;
607*cb63e24eSchristos *errmsg = "posix_spawn_file_actions_init";
608*cb63e24eSchristos goto exit;
609*cb63e24eSchristos }
610*cb63e24eSchristos actions_initialized = 1;
611*cb63e24eSchristos
612*cb63e24eSchristos if (in != STDIN_FILE_NO)
613*cb63e24eSchristos {
614*cb63e24eSchristos ret = posix_spawn_file_actions_adddup2 (&actions, in, STDIN_FILE_NO);
615*cb63e24eSchristos if (ret)
616*cb63e24eSchristos {
617*cb63e24eSchristos *err = ret;
618*cb63e24eSchristos *errmsg = "posix_spawn_file_actions_adddup2";
619*cb63e24eSchristos goto exit;
620*cb63e24eSchristos }
621*cb63e24eSchristos
622*cb63e24eSchristos ret = posix_spawn_file_actions_addclose (&actions, in);
623*cb63e24eSchristos if (ret)
624*cb63e24eSchristos {
625*cb63e24eSchristos *err = ret;
626*cb63e24eSchristos *errmsg = "posix_spawn_file_actions_addclose";
627*cb63e24eSchristos goto exit;
628*cb63e24eSchristos }
629*cb63e24eSchristos }
630*cb63e24eSchristos
631*cb63e24eSchristos if (out != STDOUT_FILE_NO)
632*cb63e24eSchristos {
633*cb63e24eSchristos ret = posix_spawn_file_actions_adddup2 (&actions, out, STDOUT_FILE_NO);
634*cb63e24eSchristos if (ret)
635*cb63e24eSchristos {
636*cb63e24eSchristos *err = ret;
637*cb63e24eSchristos *errmsg = "posix_spawn_file_actions_adddup2";
638*cb63e24eSchristos goto exit;
639*cb63e24eSchristos }
640*cb63e24eSchristos
641*cb63e24eSchristos ret = posix_spawn_file_actions_addclose (&actions, out);
642*cb63e24eSchristos if (ret)
643*cb63e24eSchristos {
644*cb63e24eSchristos *err = ret;
645*cb63e24eSchristos *errmsg = "posix_spawn_file_actions_addclose";
646*cb63e24eSchristos goto exit;
647*cb63e24eSchristos }
648*cb63e24eSchristos }
649*cb63e24eSchristos
650*cb63e24eSchristos if (errdes != STDERR_FILE_NO)
651*cb63e24eSchristos {
652*cb63e24eSchristos ret = posix_spawn_file_actions_adddup2 (&actions, errdes, STDERR_FILE_NO);
653*cb63e24eSchristos if (ret)
654*cb63e24eSchristos {
655*cb63e24eSchristos *err = ret;
656*cb63e24eSchristos *errmsg = "posix_spawn_file_actions_adddup2";
657*cb63e24eSchristos goto exit;
658*cb63e24eSchristos }
659*cb63e24eSchristos
660*cb63e24eSchristos ret = posix_spawn_file_actions_addclose (&actions, errdes);
661*cb63e24eSchristos if (ret)
662*cb63e24eSchristos {
663*cb63e24eSchristos *err = ret;
664*cb63e24eSchristos *errmsg = "posix_spawn_file_actions_addclose";
665*cb63e24eSchristos goto exit;
666*cb63e24eSchristos }
667*cb63e24eSchristos }
668*cb63e24eSchristos
669*cb63e24eSchristos if (toclose >= 0)
670*cb63e24eSchristos {
671*cb63e24eSchristos ret = posix_spawn_file_actions_addclose (&actions, toclose);
672*cb63e24eSchristos if (ret)
673*cb63e24eSchristos {
674*cb63e24eSchristos *err = ret;
675*cb63e24eSchristos *errmsg = "posix_spawn_file_actions_addclose";
676*cb63e24eSchristos goto exit;
677*cb63e24eSchristos }
678*cb63e24eSchristos }
679*cb63e24eSchristos
680*cb63e24eSchristos if ((flags & PEX_STDERR_TO_STDOUT) != 0)
681*cb63e24eSchristos {
682*cb63e24eSchristos ret = posix_spawn_file_actions_adddup2 (&actions, STDOUT_FILE_NO, STDERR_FILE_NO);
683*cb63e24eSchristos if (ret)
684*cb63e24eSchristos {
685*cb63e24eSchristos *err = ret;
686*cb63e24eSchristos *errmsg = "posix_spawn_file_actions_adddup2";
687*cb63e24eSchristos goto exit;
688*cb63e24eSchristos }
689*cb63e24eSchristos }
690*cb63e24eSchristos
691*cb63e24eSchristos if ((flags & PEX_SEARCH) != 0)
692*cb63e24eSchristos {
693*cb63e24eSchristos ret = posix_spawnp (&pid, executable, &actions, &attr, argv, env ? env : environ);
694*cb63e24eSchristos if (ret)
695*cb63e24eSchristos {
696*cb63e24eSchristos *err = ret;
697*cb63e24eSchristos *errmsg = "posix_spawnp";
698*cb63e24eSchristos goto exit;
699*cb63e24eSchristos }
700*cb63e24eSchristos }
701*cb63e24eSchristos else
702*cb63e24eSchristos {
703*cb63e24eSchristos ret = posix_spawn (&pid, executable, &actions, &attr, argv, env ? env : environ);
704*cb63e24eSchristos if (ret)
705*cb63e24eSchristos {
706*cb63e24eSchristos *err = ret;
707*cb63e24eSchristos *errmsg = "posix_spawn";
708*cb63e24eSchristos goto exit;
709*cb63e24eSchristos }
710*cb63e24eSchristos }
711*cb63e24eSchristos
712*cb63e24eSchristos exit:
713*cb63e24eSchristos if (actions_initialized)
714*cb63e24eSchristos posix_spawn_file_actions_destroy (&actions);
715*cb63e24eSchristos if (attr_initialized)
716*cb63e24eSchristos posix_spawnattr_destroy (&attr);
717*cb63e24eSchristos
718*cb63e24eSchristos if (!*err && in != STDIN_FILE_NO)
719*cb63e24eSchristos if (close (in))
720*cb63e24eSchristos *errmsg = "close", *err = errno, pid = -1;
721*cb63e24eSchristos if (!*err && out != STDOUT_FILE_NO)
722*cb63e24eSchristos if (close (out))
723*cb63e24eSchristos *errmsg = "close", *err = errno, pid = -1;
724*cb63e24eSchristos if (!*err && errdes != STDERR_FILE_NO)
725*cb63e24eSchristos if (close (errdes))
726*cb63e24eSchristos *errmsg = "close", *err = errno, pid = -1;
727*cb63e24eSchristos
728*cb63e24eSchristos return pid;
729*cb63e24eSchristos }
730be9ac0eaSchristos #else
731be9ac0eaSchristos /* Implementation of pex->exec_child using standard vfork + exec. */
732be9ac0eaSchristos
7332a6b7db3Sskrll static pid_t
pex_unix_exec_child(struct pex_obj * obj,int flags,const char * executable,char * const * argv,char * const * env,int in,int out,int errdes,int toclose,const char ** errmsg,int * err)7342a6b7db3Sskrll pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
7352a6b7db3Sskrll char * const * argv, char * const * env,
7362a6b7db3Sskrll int in, int out, int errdes,
7372a6b7db3Sskrll int toclose, const char **errmsg, int *err)
7382a6b7db3Sskrll {
7396f4ced0bSchristos pid_t pid = -1;
7406f4ced0bSchristos /* Tuple to communicate error from child to parent. We can safely
7416f4ced0bSchristos transfer string literal pointers as both run with identical
7426f4ced0bSchristos address mappings. */
7436f4ced0bSchristos struct fn_err
7446f4ced0bSchristos {
7456f4ced0bSchristos const char *fn;
7466f4ced0bSchristos int err;
7476f4ced0bSchristos };
7486f4ced0bSchristos volatile int do_pipe = 0;
7496f4ced0bSchristos volatile int pipes[2]; /* [0]:reader,[1]:writer. */
7506f4ced0bSchristos #ifdef O_CLOEXEC
7516f4ced0bSchristos do_pipe = 1;
7526f4ced0bSchristos #endif
7536f4ced0bSchristos if (do_pipe)
7546f4ced0bSchristos {
7556f4ced0bSchristos #ifdef HAVE_PIPE2
7566f4ced0bSchristos if (pipe2 ((int *)pipes, O_CLOEXEC))
7576f4ced0bSchristos do_pipe = 0;
7586f4ced0bSchristos #else
7596f4ced0bSchristos if (pipe ((int *)pipes))
7606f4ced0bSchristos do_pipe = 0;
7616f4ced0bSchristos else
7626f4ced0bSchristos {
7636f4ced0bSchristos if (fcntl (pipes[1], F_SETFD, FD_CLOEXEC) == -1)
7646f4ced0bSchristos {
7656f4ced0bSchristos close (pipes[0]);
7666f4ced0bSchristos close (pipes[1]);
7676f4ced0bSchristos do_pipe = 0;
7686f4ced0bSchristos }
7696f4ced0bSchristos }
7706f4ced0bSchristos #endif
7716f4ced0bSchristos }
7722a6b7db3Sskrll
7732a6b7db3Sskrll /* We declare these to be volatile to avoid warnings from gcc about
7742a6b7db3Sskrll them being clobbered by vfork. */
7756f4ced0bSchristos volatile int sleep_interval = 1;
7762a6b7db3Sskrll volatile int retries;
7772a6b7db3Sskrll
778be9ac0eaSchristos /* We vfork and then set environ in the child before calling execvp.
779be9ac0eaSchristos This clobbers the parent's environ so we need to restore it.
780be9ac0eaSchristos It would be nice to use one of the exec* functions that takes an
7816f4ced0bSchristos environment as a parameter, but that may have portability
7826f4ced0bSchristos issues. It is marked volatile so the child doesn't consider it a
7836f4ced0bSchristos dead variable and therefore clobber where ever it is stored. */
7846f4ced0bSchristos char **volatile save_environ = environ;
785be9ac0eaSchristos
7862a6b7db3Sskrll for (retries = 0; retries < 4; ++retries)
7872a6b7db3Sskrll {
7882a6b7db3Sskrll pid = vfork ();
7892a6b7db3Sskrll if (pid >= 0)
7902a6b7db3Sskrll break;
7912a6b7db3Sskrll sleep (sleep_interval);
7922a6b7db3Sskrll sleep_interval *= 2;
7932a6b7db3Sskrll }
7942a6b7db3Sskrll
7952a6b7db3Sskrll switch (pid)
7962a6b7db3Sskrll {
7972a6b7db3Sskrll case -1:
7986f4ced0bSchristos if (do_pipe)
7996f4ced0bSchristos {
8006f4ced0bSchristos close (pipes[0]);
8016f4ced0bSchristos close (pipes[1]);
8026f4ced0bSchristos }
8032a6b7db3Sskrll *err = errno;
8042a6b7db3Sskrll *errmsg = VFORK_STRING;
8052a6b7db3Sskrll return (pid_t) -1;
8062a6b7db3Sskrll
8072a6b7db3Sskrll case 0:
8082a6b7db3Sskrll /* Child process. */
8096f4ced0bSchristos {
8106f4ced0bSchristos struct fn_err failed;
8116f4ced0bSchristos failed.fn = NULL;
8126f4ced0bSchristos
8136f4ced0bSchristos if (do_pipe)
8146f4ced0bSchristos close (pipes[0]);
8156f4ced0bSchristos if (!failed.fn && in != STDIN_FILE_NO)
8162a6b7db3Sskrll {
8172a6b7db3Sskrll if (dup2 (in, STDIN_FILE_NO) < 0)
8186f4ced0bSchristos failed.fn = "dup2", failed.err = errno;
8196f4ced0bSchristos else if (close (in) < 0)
8206f4ced0bSchristos failed.fn = "close", failed.err = errno;
8212a6b7db3Sskrll }
8226f4ced0bSchristos if (!failed.fn && out != STDOUT_FILE_NO)
8232a6b7db3Sskrll {
8242a6b7db3Sskrll if (dup2 (out, STDOUT_FILE_NO) < 0)
8256f4ced0bSchristos failed.fn = "dup2", failed.err = errno;
8266f4ced0bSchristos else if (close (out) < 0)
8276f4ced0bSchristos failed.fn = "close", failed.err = errno;
8282a6b7db3Sskrll }
8296f4ced0bSchristos if (!failed.fn && errdes != STDERR_FILE_NO)
8302a6b7db3Sskrll {
8312a6b7db3Sskrll if (dup2 (errdes, STDERR_FILE_NO) < 0)
8326f4ced0bSchristos failed.fn = "dup2", failed.err = errno;
8336f4ced0bSchristos else if (close (errdes) < 0)
8346f4ced0bSchristos failed.fn = "close", failed.err = errno;
8352a6b7db3Sskrll }
8366f4ced0bSchristos if (!failed.fn && toclose >= 0)
8372a6b7db3Sskrll {
8382a6b7db3Sskrll if (close (toclose) < 0)
8396f4ced0bSchristos failed.fn = "close", failed.err = errno;
8402a6b7db3Sskrll }
8416f4ced0bSchristos if (!failed.fn && (flags & PEX_STDERR_TO_STDOUT) != 0)
8422a6b7db3Sskrll {
8432a6b7db3Sskrll if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
8446f4ced0bSchristos failed.fn = "dup2", failed.err = errno;
8452a6b7db3Sskrll }
8466f4ced0bSchristos if (!failed.fn)
847be9ac0eaSchristos {
8486f4ced0bSchristos if (env)
8496f4ced0bSchristos /* NOTE: In a standard vfork implementation this clobbers
8506f4ced0bSchristos the parent's copy of environ "too" (in reality there's
8516f4ced0bSchristos only one copy). This is ok as we restore it below. */
8522a6b7db3Sskrll environ = (char**) env;
8532a6b7db3Sskrll if ((flags & PEX_SEARCH) != 0)
8542a6b7db3Sskrll {
855be9ac0eaSchristos execvp (executable, to_ptr32 (argv));
8566f4ced0bSchristos failed.fn = "execvp", failed.err = errno;
8572a6b7db3Sskrll }
8582a6b7db3Sskrll else
8592a6b7db3Sskrll {
860be9ac0eaSchristos execv (executable, to_ptr32 (argv));
8616f4ced0bSchristos failed.fn = "execv", failed.err = errno;
8626f4ced0bSchristos }
8632a6b7db3Sskrll }
8642a6b7db3Sskrll
8656f4ced0bSchristos /* Something failed, report an error. We don't use stdio
8666f4ced0bSchristos routines, because we might be here due to a vfork call. */
8676f4ced0bSchristos ssize_t retval = 0;
8686f4ced0bSchristos
8696f4ced0bSchristos if (!do_pipe
8706f4ced0bSchristos || write (pipes[1], &failed, sizeof (failed)) != sizeof (failed))
8716f4ced0bSchristos {
8726f4ced0bSchristos /* The parent will not see our scream above, so write to
8736f4ced0bSchristos stdout. */
8746f4ced0bSchristos #define writeerr(s) (retval |= write (STDERR_FILE_NO, s, strlen (s)))
8756f4ced0bSchristos writeerr (obj->pname);
8766f4ced0bSchristos writeerr (": error trying to exec '");
8776f4ced0bSchristos writeerr (executable);
8786f4ced0bSchristos writeerr ("': ");
8796f4ced0bSchristos writeerr (failed.fn);
8806f4ced0bSchristos writeerr (": ");
8816f4ced0bSchristos writeerr (xstrerror (failed.err));
8826f4ced0bSchristos writeerr ("\n");
8836f4ced0bSchristos #undef writeerr
8846f4ced0bSchristos }
8856f4ced0bSchristos
8866f4ced0bSchristos /* Exit with -2 if the error output failed, too. */
8876f4ced0bSchristos _exit (retval < 0 ? -2 : -1);
8886f4ced0bSchristos }
8892a6b7db3Sskrll /* NOTREACHED */
8902a6b7db3Sskrll return (pid_t) -1;
8912a6b7db3Sskrll
8922a6b7db3Sskrll default:
8932a6b7db3Sskrll /* Parent process. */
8946f4ced0bSchristos {
8956f4ced0bSchristos /* Restore environ. Note that the parent either doesn't run
8966f4ced0bSchristos until the child execs/exits (standard vfork behaviour), or
8976f4ced0bSchristos if it does run then vfork is behaving more like fork. In
8986f4ced0bSchristos either case we needn't worry about clobbering the child's
8996f4ced0bSchristos copy of environ. */
900be9ac0eaSchristos environ = save_environ;
901be9ac0eaSchristos
9026f4ced0bSchristos struct fn_err failed;
9036f4ced0bSchristos failed.fn = NULL;
9046f4ced0bSchristos if (do_pipe)
9052a6b7db3Sskrll {
9066f4ced0bSchristos close (pipes[1]);
9076f4ced0bSchristos ssize_t len = read (pipes[0], &failed, sizeof (failed));
9086f4ced0bSchristos if (len < 0)
9096f4ced0bSchristos failed.fn = NULL;
9106f4ced0bSchristos close (pipes[0]);
9112a6b7db3Sskrll }
9122a6b7db3Sskrll
9136f4ced0bSchristos if (!failed.fn && in != STDIN_FILE_NO)
9146f4ced0bSchristos if (close (in) < 0)
9156f4ced0bSchristos failed.fn = "close", failed.err = errno;
9166f4ced0bSchristos if (!failed.fn && out != STDOUT_FILE_NO)
9176f4ced0bSchristos if (close (out) < 0)
9186f4ced0bSchristos failed.fn = "close", failed.err = errno;
9196f4ced0bSchristos if (!failed.fn && errdes != STDERR_FILE_NO)
9206f4ced0bSchristos if (close (errdes) < 0)
9216f4ced0bSchristos failed.fn = "close", failed.err = errno;
9226f4ced0bSchristos
9236f4ced0bSchristos if (failed.fn)
9246f4ced0bSchristos {
9256f4ced0bSchristos *err = failed.err;
9266f4ced0bSchristos *errmsg = failed.fn;
9276f4ced0bSchristos return (pid_t) -1;
9286f4ced0bSchristos }
9296f4ced0bSchristos }
9302a6b7db3Sskrll return pid;
9312a6b7db3Sskrll }
9322a6b7db3Sskrll }
933be9ac0eaSchristos #endif /* SPAWN */
9342a6b7db3Sskrll
9352a6b7db3Sskrll /* Wait for a child process to complete. */
9362a6b7db3Sskrll
937*cb63e24eSchristos static pid_t
pex_unix_wait(struct pex_obj * obj,pid_t pid,int * status,struct pex_time * time,int done,const char ** errmsg,int * err)9382a6b7db3Sskrll pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status,
9392a6b7db3Sskrll struct pex_time *time, int done, const char **errmsg,
9402a6b7db3Sskrll int *err)
9412a6b7db3Sskrll {
9422a6b7db3Sskrll /* If we are cleaning up when the caller didn't retrieve process
9432a6b7db3Sskrll status for some reason, encourage the process to go away. */
9442a6b7db3Sskrll if (done)
9452a6b7db3Sskrll kill (pid, SIGTERM);
9462a6b7db3Sskrll
9472a6b7db3Sskrll if (pex_wait (obj, pid, status, time) < 0)
9482a6b7db3Sskrll {
9492a6b7db3Sskrll *err = errno;
9502a6b7db3Sskrll *errmsg = "wait";
9512a6b7db3Sskrll return -1;
9522a6b7db3Sskrll }
9532a6b7db3Sskrll
9542a6b7db3Sskrll return 0;
9552a6b7db3Sskrll }
9562a6b7db3Sskrll
9572a6b7db3Sskrll /* Create a pipe. */
9582a6b7db3Sskrll
9592a6b7db3Sskrll static int
pex_unix_pipe(struct pex_obj * obj ATTRIBUTE_UNUSED,int * p,int binary ATTRIBUTE_UNUSED)9602a6b7db3Sskrll pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
9612a6b7db3Sskrll int binary ATTRIBUTE_UNUSED)
9622a6b7db3Sskrll {
9632a6b7db3Sskrll return pipe (p);
9642a6b7db3Sskrll }
9652a6b7db3Sskrll
9662a6b7db3Sskrll /* Get a FILE pointer to read from a file descriptor. */
9672a6b7db3Sskrll
9682a6b7db3Sskrll static FILE *
pex_unix_fdopenr(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary ATTRIBUTE_UNUSED)9692a6b7db3Sskrll pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
9702a6b7db3Sskrll int binary ATTRIBUTE_UNUSED)
9712a6b7db3Sskrll {
9722a6b7db3Sskrll return fdopen (fd, "r");
9732a6b7db3Sskrll }
9742a6b7db3Sskrll
9752a6b7db3Sskrll static FILE *
pex_unix_fdopenw(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary ATTRIBUTE_UNUSED)9762a6b7db3Sskrll pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
9772a6b7db3Sskrll int binary ATTRIBUTE_UNUSED)
9782a6b7db3Sskrll {
9792a6b7db3Sskrll if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
9802a6b7db3Sskrll return NULL;
9812a6b7db3Sskrll return fdopen (fd, "w");
9822a6b7db3Sskrll }
9832a6b7db3Sskrll
9842a6b7db3Sskrll static void
pex_unix_cleanup(struct pex_obj * obj ATTRIBUTE_UNUSED)9852a6b7db3Sskrll pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED)
9862a6b7db3Sskrll {
9872a6b7db3Sskrll #if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID)
9882a6b7db3Sskrll while (obj->sysdep != NULL)
9892a6b7db3Sskrll {
9902a6b7db3Sskrll struct status_list *this;
9912a6b7db3Sskrll struct status_list *next;
9922a6b7db3Sskrll
9932a6b7db3Sskrll this = (struct status_list *) obj->sysdep;
9942a6b7db3Sskrll next = this->next;
9952a6b7db3Sskrll free (this);
9962a6b7db3Sskrll obj->sysdep = (void *) next;
9972a6b7db3Sskrll }
9982a6b7db3Sskrll #endif
9992a6b7db3Sskrll }
1000