116dce513Schristos /* Utilities to execute a program in a subprocess (possibly linked by pipes
216dce513Schristos with other subprocesses), and wait for it. Generic Unix version
316dce513Schristos (also used for UWIN and VMS).
4*e992f068Schristos Copyright (C) 1996-2022 Free Software Foundation, Inc.
516dce513Schristos
616dce513Schristos This file is part of the libiberty library.
716dce513Schristos Libiberty is free software; you can redistribute it and/or
816dce513Schristos modify it under the terms of the GNU Library General Public
916dce513Schristos License as published by the Free Software Foundation; either
1016dce513Schristos version 2 of the License, or (at your option) any later version.
1116dce513Schristos
1216dce513Schristos Libiberty is distributed in the hope that it will be useful,
1316dce513Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1416dce513Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1516dce513Schristos Library General Public License for more details.
1616dce513Schristos
1716dce513Schristos You should have received a copy of the GNU Library General Public
1816dce513Schristos License along with libiberty; see the file COPYING.LIB. If not,
1916dce513Schristos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
2016dce513Schristos Boston, MA 02110-1301, USA. */
2116dce513Schristos
2216dce513Schristos #include "config.h"
2316dce513Schristos #include "libiberty.h"
2416dce513Schristos #include "pex-common.h"
2516dce513Schristos #include "environ.h"
2616dce513Schristos
2716dce513Schristos #include <stdio.h>
2816dce513Schristos #include <signal.h>
2916dce513Schristos #include <errno.h>
3016dce513Schristos #ifdef NEED_DECLARATION_ERRNO
3116dce513Schristos extern int errno;
3216dce513Schristos #endif
3316dce513Schristos #ifdef HAVE_STDLIB_H
3416dce513Schristos #include <stdlib.h>
3516dce513Schristos #endif
3616dce513Schristos #ifdef HAVE_STRING_H
3716dce513Schristos #include <string.h>
3816dce513Schristos #endif
3916dce513Schristos #ifdef HAVE_UNISTD_H
4016dce513Schristos #include <unistd.h>
4116dce513Schristos #endif
4216dce513Schristos
4316dce513Schristos #include <sys/types.h>
4416dce513Schristos
4516dce513Schristos #ifdef HAVE_FCNTL_H
4616dce513Schristos #include <fcntl.h>
4716dce513Schristos #endif
4816dce513Schristos #ifdef HAVE_SYS_WAIT_H
4916dce513Schristos #include <sys/wait.h>
5016dce513Schristos #endif
5116dce513Schristos #ifdef HAVE_GETRUSAGE
5216dce513Schristos #include <sys/time.h>
5316dce513Schristos #include <sys/resource.h>
5416dce513Schristos #endif
5516dce513Schristos #ifdef HAVE_SYS_STAT_H
5616dce513Schristos #include <sys/stat.h>
5716dce513Schristos #endif
5816dce513Schristos #ifdef HAVE_PROCESS_H
5916dce513Schristos #include <process.h>
6016dce513Schristos #endif
6116dce513Schristos
6216dce513Schristos #ifdef vfork /* Autoconf may define this to fork for us. */
6316dce513Schristos # define VFORK_STRING "fork"
6416dce513Schristos #else
6516dce513Schristos # define VFORK_STRING "vfork"
6616dce513Schristos #endif
6716dce513Schristos #ifdef HAVE_VFORK_H
6816dce513Schristos #include <vfork.h>
6916dce513Schristos #endif
7016dce513Schristos #if defined(VMS) && defined (__LONG_POINTERS)
7116dce513Schristos #ifndef __CHAR_PTR32
7216dce513Schristos typedef char * __char_ptr32
7316dce513Schristos __attribute__ ((mode (SI)));
7416dce513Schristos #endif
7516dce513Schristos
7616dce513Schristos typedef __char_ptr32 *__char_ptr_char_ptr32
7716dce513Schristos __attribute__ ((mode (SI)));
7816dce513Schristos
7916dce513Schristos /* Return a 32 bit pointer to an array of 32 bit pointers
8016dce513Schristos given a 64 bit pointer to an array of 64 bit pointers. */
8116dce513Schristos
8216dce513Schristos static __char_ptr_char_ptr32
to_ptr32(char ** ptr64)8316dce513Schristos to_ptr32 (char **ptr64)
8416dce513Schristos {
8516dce513Schristos int argc;
8616dce513Schristos __char_ptr_char_ptr32 short_argv;
8716dce513Schristos
8816dce513Schristos /* Count number of arguments. */
8916dce513Schristos for (argc = 0; ptr64[argc] != NULL; argc++)
9016dce513Schristos ;
9116dce513Schristos
9216dce513Schristos /* Reallocate argv with 32 bit pointers. */
9316dce513Schristos short_argv = (__char_ptr_char_ptr32) decc$malloc
9416dce513Schristos (sizeof (__char_ptr32) * (argc + 1));
9516dce513Schristos
9616dce513Schristos for (argc = 0; ptr64[argc] != NULL; argc++)
9716dce513Schristos short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
9816dce513Schristos
9916dce513Schristos short_argv[argc] = (__char_ptr32) 0;
10016dce513Schristos return short_argv;
10116dce513Schristos
10216dce513Schristos }
10316dce513Schristos #else
10416dce513Schristos #define to_ptr32(argv) argv
10516dce513Schristos #endif
10616dce513Schristos
10716dce513Schristos /* File mode to use for private and world-readable files. */
10816dce513Schristos
10916dce513Schristos #if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH)
11016dce513Schristos #define PUBLIC_MODE \
11116dce513Schristos (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
11216dce513Schristos #else
11316dce513Schristos #define PUBLIC_MODE 0666
11416dce513Schristos #endif
11516dce513Schristos
11616dce513Schristos /* Get the exit status of a particular process, and optionally get the
11716dce513Schristos time that it took. This is simple if we have wait4, slightly
11816dce513Schristos harder if we have waitpid, and is a pain if we only have wait. */
11916dce513Schristos
12016dce513Schristos static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *);
12116dce513Schristos
12216dce513Schristos #ifdef HAVE_WAIT4
12316dce513Schristos
12416dce513Schristos static pid_t
pex_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time)12516dce513Schristos pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
12616dce513Schristos struct pex_time *time)
12716dce513Schristos {
12816dce513Schristos pid_t ret;
12916dce513Schristos struct rusage r;
13016dce513Schristos
13116dce513Schristos #ifdef HAVE_WAITPID
13216dce513Schristos if (time == NULL)
13316dce513Schristos return waitpid (pid, status, 0);
13416dce513Schristos #endif
13516dce513Schristos
13616dce513Schristos ret = wait4 (pid, status, 0, &r);
13716dce513Schristos
13816dce513Schristos if (time != NULL)
13916dce513Schristos {
14016dce513Schristos time->user_seconds = r.ru_utime.tv_sec;
14116dce513Schristos time->user_microseconds= r.ru_utime.tv_usec;
14216dce513Schristos time->system_seconds = r.ru_stime.tv_sec;
14316dce513Schristos time->system_microseconds= r.ru_stime.tv_usec;
14416dce513Schristos }
14516dce513Schristos
14616dce513Schristos return ret;
14716dce513Schristos }
14816dce513Schristos
14916dce513Schristos #else /* ! defined (HAVE_WAIT4) */
15016dce513Schristos
15116dce513Schristos #ifdef HAVE_WAITPID
15216dce513Schristos
15316dce513Schristos #ifndef HAVE_GETRUSAGE
15416dce513Schristos
15516dce513Schristos static pid_t
pex_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time)15616dce513Schristos pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
15716dce513Schristos struct pex_time *time)
15816dce513Schristos {
15916dce513Schristos if (time != NULL)
16016dce513Schristos memset (time, 0, sizeof (struct pex_time));
16116dce513Schristos return waitpid (pid, status, 0);
16216dce513Schristos }
16316dce513Schristos
16416dce513Schristos #else /* defined (HAVE_GETRUSAGE) */
16516dce513Schristos
16616dce513Schristos static pid_t
pex_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time)16716dce513Schristos pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
16816dce513Schristos struct pex_time *time)
16916dce513Schristos {
17016dce513Schristos struct rusage r1, r2;
17116dce513Schristos pid_t ret;
17216dce513Schristos
17316dce513Schristos if (time == NULL)
17416dce513Schristos return waitpid (pid, status, 0);
17516dce513Schristos
17616dce513Schristos getrusage (RUSAGE_CHILDREN, &r1);
17716dce513Schristos
17816dce513Schristos ret = waitpid (pid, status, 0);
17916dce513Schristos if (ret < 0)
18016dce513Schristos return ret;
18116dce513Schristos
18216dce513Schristos getrusage (RUSAGE_CHILDREN, &r2);
18316dce513Schristos
18416dce513Schristos time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
18516dce513Schristos time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
18616dce513Schristos if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec)
18716dce513Schristos {
18816dce513Schristos --time->user_seconds;
18916dce513Schristos time->user_microseconds += 1000000;
19016dce513Schristos }
19116dce513Schristos
19216dce513Schristos time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
19316dce513Schristos time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
19416dce513Schristos if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec)
19516dce513Schristos {
19616dce513Schristos --time->system_seconds;
19716dce513Schristos time->system_microseconds += 1000000;
19816dce513Schristos }
19916dce513Schristos
20016dce513Schristos return ret;
20116dce513Schristos }
20216dce513Schristos
20316dce513Schristos #endif /* defined (HAVE_GETRUSAGE) */
20416dce513Schristos
20516dce513Schristos #else /* ! defined (HAVE_WAITPID) */
20616dce513Schristos
20716dce513Schristos struct status_list
20816dce513Schristos {
20916dce513Schristos struct status_list *next;
21016dce513Schristos pid_t pid;
21116dce513Schristos int status;
21216dce513Schristos struct pex_time time;
21316dce513Schristos };
21416dce513Schristos
21516dce513Schristos static pid_t
pex_wait(struct pex_obj * obj,pid_t pid,int * status,struct pex_time * time)21616dce513Schristos pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time)
21716dce513Schristos {
21816dce513Schristos struct status_list **pp;
21916dce513Schristos
22016dce513Schristos for (pp = (struct status_list **) &obj->sysdep;
22116dce513Schristos *pp != NULL;
22216dce513Schristos pp = &(*pp)->next)
22316dce513Schristos {
22416dce513Schristos if ((*pp)->pid == pid)
22516dce513Schristos {
22616dce513Schristos struct status_list *p;
22716dce513Schristos
22816dce513Schristos p = *pp;
22916dce513Schristos *status = p->status;
23016dce513Schristos if (time != NULL)
23116dce513Schristos *time = p->time;
23216dce513Schristos *pp = p->next;
23316dce513Schristos free (p);
23416dce513Schristos return pid;
23516dce513Schristos }
23616dce513Schristos }
23716dce513Schristos
23816dce513Schristos while (1)
23916dce513Schristos {
24016dce513Schristos pid_t cpid;
24116dce513Schristos struct status_list *psl;
24216dce513Schristos struct pex_time pt;
24316dce513Schristos #ifdef HAVE_GETRUSAGE
24416dce513Schristos struct rusage r1, r2;
24516dce513Schristos #endif
24616dce513Schristos
24716dce513Schristos if (time != NULL)
24816dce513Schristos {
24916dce513Schristos #ifdef HAVE_GETRUSAGE
25016dce513Schristos getrusage (RUSAGE_CHILDREN, &r1);
25116dce513Schristos #else
25216dce513Schristos memset (&pt, 0, sizeof (struct pex_time));
25316dce513Schristos #endif
25416dce513Schristos }
25516dce513Schristos
25616dce513Schristos cpid = wait (status);
25716dce513Schristos
25816dce513Schristos #ifdef HAVE_GETRUSAGE
25916dce513Schristos if (time != NULL && cpid >= 0)
26016dce513Schristos {
26116dce513Schristos getrusage (RUSAGE_CHILDREN, &r2);
26216dce513Schristos
26316dce513Schristos pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
26416dce513Schristos pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
26516dce513Schristos if (pt.user_microseconds < 0)
26616dce513Schristos {
26716dce513Schristos --pt.user_seconds;
26816dce513Schristos pt.user_microseconds += 1000000;
26916dce513Schristos }
27016dce513Schristos
27116dce513Schristos pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
27216dce513Schristos pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
27316dce513Schristos if (pt.system_microseconds < 0)
27416dce513Schristos {
27516dce513Schristos --pt.system_seconds;
27616dce513Schristos pt.system_microseconds += 1000000;
27716dce513Schristos }
27816dce513Schristos }
27916dce513Schristos #endif
28016dce513Schristos
28116dce513Schristos if (cpid < 0 || cpid == pid)
28216dce513Schristos {
28316dce513Schristos if (time != NULL)
28416dce513Schristos *time = pt;
28516dce513Schristos return cpid;
28616dce513Schristos }
28716dce513Schristos
28816dce513Schristos psl = XNEW (struct status_list);
28916dce513Schristos psl->pid = cpid;
29016dce513Schristos psl->status = *status;
29116dce513Schristos if (time != NULL)
29216dce513Schristos psl->time = pt;
29316dce513Schristos psl->next = (struct status_list *) obj->sysdep;
29416dce513Schristos obj->sysdep = (void *) psl;
29516dce513Schristos }
29616dce513Schristos }
29716dce513Schristos
29816dce513Schristos #endif /* ! defined (HAVE_WAITPID) */
29916dce513Schristos #endif /* ! defined (HAVE_WAIT4) */
30016dce513Schristos
30116dce513Schristos static int pex_unix_open_read (struct pex_obj *, const char *, int);
30216dce513Schristos static int pex_unix_open_write (struct pex_obj *, const char *, int, int);
30316dce513Schristos static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *,
30416dce513Schristos char * const *, char * const *,
30516dce513Schristos int, int, int, int,
30616dce513Schristos const char **, int *);
30716dce513Schristos static int pex_unix_close (struct pex_obj *, int);
30816dce513Schristos static int pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
30916dce513Schristos int, const char **, int *);
31016dce513Schristos static int pex_unix_pipe (struct pex_obj *, int *, int);
31116dce513Schristos static FILE *pex_unix_fdopenr (struct pex_obj *, int, int);
31216dce513Schristos static FILE *pex_unix_fdopenw (struct pex_obj *, int, int);
31316dce513Schristos static void pex_unix_cleanup (struct pex_obj *);
31416dce513Schristos
31516dce513Schristos /* The list of functions we pass to the common routines. */
31616dce513Schristos
31716dce513Schristos const struct pex_funcs funcs =
31816dce513Schristos {
31916dce513Schristos pex_unix_open_read,
32016dce513Schristos pex_unix_open_write,
32116dce513Schristos pex_unix_exec_child,
32216dce513Schristos pex_unix_close,
32316dce513Schristos pex_unix_wait,
32416dce513Schristos pex_unix_pipe,
32516dce513Schristos pex_unix_fdopenr,
32616dce513Schristos pex_unix_fdopenw,
32716dce513Schristos pex_unix_cleanup
32816dce513Schristos };
32916dce513Schristos
33016dce513Schristos /* Return a newly initialized pex_obj structure. */
33116dce513Schristos
33216dce513Schristos struct pex_obj *
pex_init(int flags,const char * pname,const char * tempbase)33316dce513Schristos pex_init (int flags, const char *pname, const char *tempbase)
33416dce513Schristos {
33516dce513Schristos return pex_init_common (flags, pname, tempbase, &funcs);
33616dce513Schristos }
33716dce513Schristos
33816dce513Schristos /* Open a file for reading. */
33916dce513Schristos
34016dce513Schristos static int
pex_unix_open_read(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary ATTRIBUTE_UNUSED)34116dce513Schristos pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
34216dce513Schristos int binary ATTRIBUTE_UNUSED)
34316dce513Schristos {
34416dce513Schristos return open (name, O_RDONLY);
34516dce513Schristos }
34616dce513Schristos
34716dce513Schristos /* Open a file for writing. */
34816dce513Schristos
34916dce513Schristos static int
pex_unix_open_write(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary ATTRIBUTE_UNUSED,int append)35016dce513Schristos pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
35116dce513Schristos int binary ATTRIBUTE_UNUSED, int append)
35216dce513Schristos {
35316dce513Schristos /* Note that we can't use O_EXCL here because gcc may have already
35416dce513Schristos created the temporary file via make_temp_file. */
35516dce513Schristos return open (name, O_WRONLY | O_CREAT
35616dce513Schristos | (append ? O_APPEND : O_TRUNC), PUBLIC_MODE);
35716dce513Schristos }
35816dce513Schristos
35916dce513Schristos /* Close a file. */
36016dce513Schristos
36116dce513Schristos static int
pex_unix_close(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd)36216dce513Schristos pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
36316dce513Schristos {
36416dce513Schristos return close (fd);
36516dce513Schristos }
36616dce513Schristos
36716dce513Schristos /* Execute a child. */
36816dce513Schristos
36916dce513Schristos #if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE)
37016dce513Schristos /* Implementation of pex->exec_child using the Cygwin spawn operation. */
37116dce513Schristos
37216dce513Schristos /* Subroutine of pex_unix_exec_child. Move OLD_FD to a new file descriptor
37316dce513Schristos to be stored in *PNEW_FD, save the flags in *PFLAGS, and arrange for the
37416dce513Schristos saved copy to be close-on-exec. Move CHILD_FD into OLD_FD. If CHILD_FD
37516dce513Schristos is -1, OLD_FD is to be closed. Return -1 on error. */
37616dce513Schristos
37716dce513Schristos static int
save_and_install_fd(int * pnew_fd,int * pflags,int old_fd,int child_fd)37816dce513Schristos save_and_install_fd(int *pnew_fd, int *pflags, int old_fd, int child_fd)
37916dce513Schristos {
38016dce513Schristos int new_fd, flags;
38116dce513Schristos
38216dce513Schristos flags = fcntl (old_fd, F_GETFD);
38316dce513Schristos
38416dce513Schristos /* If we could not retrieve the flags, then OLD_FD was not open. */
38516dce513Schristos if (flags < 0)
38616dce513Schristos {
38716dce513Schristos new_fd = -1, flags = 0;
38816dce513Schristos if (child_fd >= 0 && dup2 (child_fd, old_fd) < 0)
38916dce513Schristos return -1;
39016dce513Schristos }
39116dce513Schristos /* If we wish to close OLD_FD, just mark it CLOEXEC. */
39216dce513Schristos else if (child_fd == -1)
39316dce513Schristos {
39416dce513Schristos new_fd = old_fd;
39516dce513Schristos if ((flags & FD_CLOEXEC) == 0 && fcntl (old_fd, F_SETFD, FD_CLOEXEC) < 0)
39616dce513Schristos return -1;
39716dce513Schristos }
39816dce513Schristos /* Otherwise we need to save a copy of OLD_FD before installing CHILD_FD. */
39916dce513Schristos else
40016dce513Schristos {
40116dce513Schristos #ifdef F_DUPFD_CLOEXEC
40216dce513Schristos new_fd = fcntl (old_fd, F_DUPFD_CLOEXEC, 3);
40316dce513Schristos if (new_fd < 0)
40416dce513Schristos return -1;
40516dce513Schristos #else
40616dce513Schristos /* Prefer F_DUPFD over dup in order to avoid getting a new fd
40716dce513Schristos in the range 0-2, right where a new stderr fd might get put. */
40816dce513Schristos new_fd = fcntl (old_fd, F_DUPFD, 3);
40916dce513Schristos if (new_fd < 0)
41016dce513Schristos return -1;
41116dce513Schristos if (fcntl (new_fd, F_SETFD, FD_CLOEXEC) < 0)
41216dce513Schristos return -1;
41316dce513Schristos #endif
41416dce513Schristos if (dup2 (child_fd, old_fd) < 0)
41516dce513Schristos return -1;
41616dce513Schristos }
41716dce513Schristos
41816dce513Schristos *pflags = flags;
41916dce513Schristos if (pnew_fd)
42016dce513Schristos *pnew_fd = new_fd;
42116dce513Schristos else if (new_fd != old_fd)
42216dce513Schristos abort ();
42316dce513Schristos
42416dce513Schristos return 0;
42516dce513Schristos }
42616dce513Schristos
42716dce513Schristos /* Subroutine of pex_unix_exec_child. Move SAVE_FD back to OLD_FD
42816dce513Schristos restoring FLAGS. If SAVE_FD < 0, OLD_FD is to be closed. */
42916dce513Schristos
43016dce513Schristos static int
restore_fd(int old_fd,int save_fd,int flags)43116dce513Schristos restore_fd(int old_fd, int save_fd, int flags)
43216dce513Schristos {
43316dce513Schristos /* For SAVE_FD < 0, all we have to do is restore the
43416dce513Schristos "closed-ness" of the original. */
43516dce513Schristos if (save_fd < 0)
43616dce513Schristos return close (old_fd);
43716dce513Schristos
43816dce513Schristos /* For SAVE_FD == OLD_FD, all we have to do is restore the
43916dce513Schristos original setting of the CLOEXEC flag. */
44016dce513Schristos if (save_fd == old_fd)
44116dce513Schristos {
44216dce513Schristos if (flags & FD_CLOEXEC)
44316dce513Schristos return 0;
44416dce513Schristos return fcntl (old_fd, F_SETFD, flags);
44516dce513Schristos }
44616dce513Schristos
44716dce513Schristos /* Otherwise we have to move the descriptor back, restore the flags,
44816dce513Schristos and close the saved copy. */
44916dce513Schristos #ifdef HAVE_DUP3
45016dce513Schristos if (flags == FD_CLOEXEC)
45116dce513Schristos {
45216dce513Schristos if (dup3 (save_fd, old_fd, O_CLOEXEC) < 0)
45316dce513Schristos return -1;
45416dce513Schristos }
45516dce513Schristos else
45616dce513Schristos #endif
45716dce513Schristos {
45816dce513Schristos if (dup2 (save_fd, old_fd) < 0)
45916dce513Schristos return -1;
46016dce513Schristos if (flags != 0 && fcntl (old_fd, F_SETFD, flags) < 0)
46116dce513Schristos return -1;
46216dce513Schristos }
46316dce513Schristos return close (save_fd);
46416dce513Schristos }
46516dce513Schristos
46616dce513Schristos 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)46716dce513Schristos pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED,
46816dce513Schristos int flags, const char *executable,
46916dce513Schristos char * const * argv, char * const * env,
47016dce513Schristos int in, int out, int errdes, int toclose,
47116dce513Schristos const char **errmsg, int *err)
47216dce513Schristos {
47316dce513Schristos int fl_in = 0, fl_out = 0, fl_err = 0, fl_tc = 0;
47416dce513Schristos int save_in = -1, save_out = -1, save_err = -1;
47516dce513Schristos int max, retries;
47616dce513Schristos pid_t pid;
47716dce513Schristos
47816dce513Schristos if (flags & PEX_STDERR_TO_STDOUT)
47916dce513Schristos errdes = out;
48016dce513Schristos
48116dce513Schristos /* We need the three standard file descriptors to be set up as for
48216dce513Schristos the child before we perform the spawn. The file descriptors for
48316dce513Schristos the parent need to be moved and marked for close-on-exec. */
48416dce513Schristos if (in != STDIN_FILE_NO
48516dce513Schristos && save_and_install_fd (&save_in, &fl_in, STDIN_FILE_NO, in) < 0)
48616dce513Schristos goto error_dup2;
48716dce513Schristos if (out != STDOUT_FILE_NO
48816dce513Schristos && save_and_install_fd (&save_out, &fl_out, STDOUT_FILE_NO, out) < 0)
48916dce513Schristos goto error_dup2;
49016dce513Schristos if (errdes != STDERR_FILE_NO
49116dce513Schristos && save_and_install_fd (&save_err, &fl_err, STDERR_FILE_NO, errdes) < 0)
49216dce513Schristos goto error_dup2;
49316dce513Schristos if (toclose >= 0
49416dce513Schristos && save_and_install_fd (NULL, &fl_tc, toclose, -1) < 0)
49516dce513Schristos goto error_dup2;
49616dce513Schristos
49716dce513Schristos /* Now that we've moved the file descriptors for the child into place,
49816dce513Schristos close the originals. Be careful not to close any of the standard
49916dce513Schristos file descriptors that we just set up. */
50016dce513Schristos max = -1;
50116dce513Schristos if (errdes >= 0)
50216dce513Schristos max = STDERR_FILE_NO;
50316dce513Schristos else if (out >= 0)
50416dce513Schristos max = STDOUT_FILE_NO;
50516dce513Schristos else if (in >= 0)
50616dce513Schristos max = STDIN_FILE_NO;
50716dce513Schristos if (in > max)
50816dce513Schristos close (in);
50916dce513Schristos if (out > max)
51016dce513Schristos close (out);
51116dce513Schristos if (errdes > max && errdes != out)
51216dce513Schristos close (errdes);
51316dce513Schristos
51416dce513Schristos /* If we were not given an environment, use the global environment. */
51516dce513Schristos if (env == NULL)
51616dce513Schristos env = environ;
51716dce513Schristos
51816dce513Schristos /* Launch the program. If we get EAGAIN (normally out of pid's), try
51916dce513Schristos again a few times with increasing backoff times. */
52016dce513Schristos retries = 0;
52116dce513Schristos while (1)
52216dce513Schristos {
52316dce513Schristos typedef const char * const *cc_cp;
52416dce513Schristos
52516dce513Schristos if (flags & PEX_SEARCH)
52616dce513Schristos pid = spawnvpe (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
52716dce513Schristos else
52816dce513Schristos pid = spawnve (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
52916dce513Schristos
53016dce513Schristos if (pid > 0)
53116dce513Schristos break;
53216dce513Schristos
53316dce513Schristos *err = errno;
53416dce513Schristos *errmsg = "spawn";
53516dce513Schristos if (errno != EAGAIN || ++retries == 4)
53616dce513Schristos return (pid_t) -1;
53716dce513Schristos sleep (1 << retries);
53816dce513Schristos }
53916dce513Schristos
54016dce513Schristos /* Success. Restore the parent's file descriptors that we saved above. */
54116dce513Schristos if (toclose >= 0
54216dce513Schristos && restore_fd (toclose, toclose, fl_tc) < 0)
54316dce513Schristos goto error_dup2;
54416dce513Schristos if (in != STDIN_FILE_NO
54516dce513Schristos && restore_fd (STDIN_FILE_NO, save_in, fl_in) < 0)
54616dce513Schristos goto error_dup2;
54716dce513Schristos if (out != STDOUT_FILE_NO
54816dce513Schristos && restore_fd (STDOUT_FILE_NO, save_out, fl_out) < 0)
54916dce513Schristos goto error_dup2;
55016dce513Schristos if (errdes != STDERR_FILE_NO
55116dce513Schristos && restore_fd (STDERR_FILE_NO, save_err, fl_err) < 0)
55216dce513Schristos goto error_dup2;
55316dce513Schristos
55416dce513Schristos return pid;
55516dce513Schristos
55616dce513Schristos error_dup2:
55716dce513Schristos *err = errno;
55816dce513Schristos *errmsg = "dup2";
55916dce513Schristos return (pid_t) -1;
56016dce513Schristos }
56116dce513Schristos
56216dce513Schristos #else
56316dce513Schristos /* Implementation of pex->exec_child using standard vfork + exec. */
56416dce513Schristos
56516dce513Schristos 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)56616dce513Schristos pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
56716dce513Schristos char * const * argv, char * const * env,
56816dce513Schristos int in, int out, int errdes,
56916dce513Schristos int toclose, const char **errmsg, int *err)
57016dce513Schristos {
571012573ebSchristos pid_t pid = -1;
572012573ebSchristos /* Tuple to communicate error from child to parent. We can safely
573012573ebSchristos transfer string literal pointers as both run with identical
574012573ebSchristos address mappings. */
575012573ebSchristos struct fn_err
576012573ebSchristos {
577012573ebSchristos const char *fn;
578012573ebSchristos int err;
579012573ebSchristos };
580012573ebSchristos volatile int do_pipe = 0;
581012573ebSchristos volatile int pipes[2]; /* [0]:reader,[1]:writer. */
582012573ebSchristos #ifdef O_CLOEXEC
583012573ebSchristos do_pipe = 1;
584012573ebSchristos #endif
585012573ebSchristos if (do_pipe)
586012573ebSchristos {
587012573ebSchristos #ifdef HAVE_PIPE2
588012573ebSchristos if (pipe2 ((int *)pipes, O_CLOEXEC))
589012573ebSchristos do_pipe = 0;
590012573ebSchristos #else
591012573ebSchristos if (pipe ((int *)pipes))
592012573ebSchristos do_pipe = 0;
593012573ebSchristos else
594012573ebSchristos {
595012573ebSchristos if (fcntl (pipes[1], F_SETFD, FD_CLOEXEC) == -1)
596012573ebSchristos {
597012573ebSchristos close (pipes[0]);
598012573ebSchristos close (pipes[1]);
599012573ebSchristos do_pipe = 0;
600012573ebSchristos }
601012573ebSchristos }
602012573ebSchristos #endif
603012573ebSchristos }
60416dce513Schristos
60516dce513Schristos /* We declare these to be volatile to avoid warnings from gcc about
60616dce513Schristos them being clobbered by vfork. */
607012573ebSchristos volatile int sleep_interval = 1;
60816dce513Schristos volatile int retries;
60916dce513Schristos
61016dce513Schristos /* We vfork and then set environ in the child before calling execvp.
61116dce513Schristos This clobbers the parent's environ so we need to restore it.
61216dce513Schristos It would be nice to use one of the exec* functions that takes an
613012573ebSchristos environment as a parameter, but that may have portability
614012573ebSchristos issues. It is marked volatile so the child doesn't consider it a
615012573ebSchristos dead variable and therefore clobber where ever it is stored. */
616012573ebSchristos char **volatile save_environ = environ;
61716dce513Schristos
61816dce513Schristos for (retries = 0; retries < 4; ++retries)
61916dce513Schristos {
62016dce513Schristos pid = vfork ();
62116dce513Schristos if (pid >= 0)
62216dce513Schristos break;
62316dce513Schristos sleep (sleep_interval);
62416dce513Schristos sleep_interval *= 2;
62516dce513Schristos }
62616dce513Schristos
62716dce513Schristos switch (pid)
62816dce513Schristos {
62916dce513Schristos case -1:
630012573ebSchristos if (do_pipe)
631012573ebSchristos {
632012573ebSchristos close (pipes[0]);
633012573ebSchristos close (pipes[1]);
634012573ebSchristos }
63516dce513Schristos *err = errno;
63616dce513Schristos *errmsg = VFORK_STRING;
63716dce513Schristos return (pid_t) -1;
63816dce513Schristos
63916dce513Schristos case 0:
64016dce513Schristos /* Child process. */
641012573ebSchristos {
642012573ebSchristos struct fn_err failed;
643012573ebSchristos failed.fn = NULL;
644012573ebSchristos
645012573ebSchristos if (do_pipe)
646012573ebSchristos close (pipes[0]);
647012573ebSchristos if (!failed.fn && in != STDIN_FILE_NO)
64816dce513Schristos {
64916dce513Schristos if (dup2 (in, STDIN_FILE_NO) < 0)
650012573ebSchristos failed.fn = "dup2", failed.err = errno;
651012573ebSchristos else if (close (in) < 0)
652012573ebSchristos failed.fn = "close", failed.err = errno;
65316dce513Schristos }
654012573ebSchristos if (!failed.fn && out != STDOUT_FILE_NO)
65516dce513Schristos {
65616dce513Schristos if (dup2 (out, STDOUT_FILE_NO) < 0)
657012573ebSchristos failed.fn = "dup2", failed.err = errno;
658012573ebSchristos else if (close (out) < 0)
659012573ebSchristos failed.fn = "close", failed.err = errno;
66016dce513Schristos }
661012573ebSchristos if (!failed.fn && errdes != STDERR_FILE_NO)
66216dce513Schristos {
66316dce513Schristos if (dup2 (errdes, STDERR_FILE_NO) < 0)
664012573ebSchristos failed.fn = "dup2", failed.err = errno;
665012573ebSchristos else if (close (errdes) < 0)
666012573ebSchristos failed.fn = "close", failed.err = errno;
66716dce513Schristos }
668012573ebSchristos if (!failed.fn && toclose >= 0)
66916dce513Schristos {
67016dce513Schristos if (close (toclose) < 0)
671012573ebSchristos failed.fn = "close", failed.err = errno;
67216dce513Schristos }
673012573ebSchristos if (!failed.fn && (flags & PEX_STDERR_TO_STDOUT) != 0)
67416dce513Schristos {
67516dce513Schristos if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
676012573ebSchristos failed.fn = "dup2", failed.err = errno;
67716dce513Schristos }
678012573ebSchristos if (!failed.fn)
67916dce513Schristos {
680012573ebSchristos if (env)
681012573ebSchristos /* NOTE: In a standard vfork implementation this clobbers
682012573ebSchristos the parent's copy of environ "too" (in reality there's
683012573ebSchristos only one copy). This is ok as we restore it below. */
68416dce513Schristos environ = (char**) env;
68516dce513Schristos if ((flags & PEX_SEARCH) != 0)
68616dce513Schristos {
68716dce513Schristos execvp (executable, to_ptr32 (argv));
688012573ebSchristos failed.fn = "execvp", failed.err = errno;
68916dce513Schristos }
69016dce513Schristos else
69116dce513Schristos {
69216dce513Schristos execv (executable, to_ptr32 (argv));
693012573ebSchristos failed.fn = "execv", failed.err = errno;
694012573ebSchristos }
69516dce513Schristos }
69616dce513Schristos
697012573ebSchristos /* Something failed, report an error. We don't use stdio
698012573ebSchristos routines, because we might be here due to a vfork call. */
699012573ebSchristos ssize_t retval = 0;
700012573ebSchristos
701012573ebSchristos if (!do_pipe
702012573ebSchristos || write (pipes[1], &failed, sizeof (failed)) != sizeof (failed))
703012573ebSchristos {
704012573ebSchristos /* The parent will not see our scream above, so write to
705012573ebSchristos stdout. */
706012573ebSchristos #define writeerr(s) (retval |= write (STDERR_FILE_NO, s, strlen (s)))
707012573ebSchristos writeerr (obj->pname);
708012573ebSchristos writeerr (": error trying to exec '");
709012573ebSchristos writeerr (executable);
710012573ebSchristos writeerr ("': ");
711012573ebSchristos writeerr (failed.fn);
712012573ebSchristos writeerr (": ");
713012573ebSchristos writeerr (xstrerror (failed.err));
714012573ebSchristos writeerr ("\n");
715012573ebSchristos #undef writeerr
716012573ebSchristos }
717012573ebSchristos
718012573ebSchristos /* Exit with -2 if the error output failed, too. */
719012573ebSchristos _exit (retval < 0 ? -2 : -1);
720012573ebSchristos }
72116dce513Schristos /* NOTREACHED */
72216dce513Schristos return (pid_t) -1;
72316dce513Schristos
72416dce513Schristos default:
72516dce513Schristos /* Parent process. */
726012573ebSchristos {
727012573ebSchristos /* Restore environ. Note that the parent either doesn't run
728012573ebSchristos until the child execs/exits (standard vfork behaviour), or
729012573ebSchristos if it does run then vfork is behaving more like fork. In
730012573ebSchristos either case we needn't worry about clobbering the child's
731012573ebSchristos copy of environ. */
73216dce513Schristos environ = save_environ;
73316dce513Schristos
734012573ebSchristos struct fn_err failed;
735012573ebSchristos failed.fn = NULL;
736012573ebSchristos if (do_pipe)
73716dce513Schristos {
738012573ebSchristos close (pipes[1]);
739012573ebSchristos ssize_t len = read (pipes[0], &failed, sizeof (failed));
740012573ebSchristos if (len < 0)
741012573ebSchristos failed.fn = NULL;
742012573ebSchristos close (pipes[0]);
74316dce513Schristos }
74416dce513Schristos
745012573ebSchristos if (!failed.fn && in != STDIN_FILE_NO)
746012573ebSchristos if (close (in) < 0)
747012573ebSchristos failed.fn = "close", failed.err = errno;
748012573ebSchristos if (!failed.fn && out != STDOUT_FILE_NO)
749012573ebSchristos if (close (out) < 0)
750012573ebSchristos failed.fn = "close", failed.err = errno;
751012573ebSchristos if (!failed.fn && errdes != STDERR_FILE_NO)
752012573ebSchristos if (close (errdes) < 0)
753012573ebSchristos failed.fn = "close", failed.err = errno;
754012573ebSchristos
755012573ebSchristos if (failed.fn)
756012573ebSchristos {
757012573ebSchristos *err = failed.err;
758012573ebSchristos *errmsg = failed.fn;
759012573ebSchristos return (pid_t) -1;
760012573ebSchristos }
761012573ebSchristos }
76216dce513Schristos return pid;
76316dce513Schristos }
76416dce513Schristos }
76516dce513Schristos #endif /* SPAWN */
76616dce513Schristos
76716dce513Schristos /* Wait for a child process to complete. */
76816dce513Schristos
76916dce513Schristos static int
pex_unix_wait(struct pex_obj * obj,pid_t pid,int * status,struct pex_time * time,int done,const char ** errmsg,int * err)77016dce513Schristos pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status,
77116dce513Schristos struct pex_time *time, int done, const char **errmsg,
77216dce513Schristos int *err)
77316dce513Schristos {
77416dce513Schristos /* If we are cleaning up when the caller didn't retrieve process
77516dce513Schristos status for some reason, encourage the process to go away. */
77616dce513Schristos if (done)
77716dce513Schristos kill (pid, SIGTERM);
77816dce513Schristos
77916dce513Schristos if (pex_wait (obj, pid, status, time) < 0)
78016dce513Schristos {
78116dce513Schristos *err = errno;
78216dce513Schristos *errmsg = "wait";
78316dce513Schristos return -1;
78416dce513Schristos }
78516dce513Schristos
78616dce513Schristos return 0;
78716dce513Schristos }
78816dce513Schristos
78916dce513Schristos /* Create a pipe. */
79016dce513Schristos
79116dce513Schristos static int
pex_unix_pipe(struct pex_obj * obj ATTRIBUTE_UNUSED,int * p,int binary ATTRIBUTE_UNUSED)79216dce513Schristos pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
79316dce513Schristos int binary ATTRIBUTE_UNUSED)
79416dce513Schristos {
79516dce513Schristos return pipe (p);
79616dce513Schristos }
79716dce513Schristos
79816dce513Schristos /* Get a FILE pointer to read from a file descriptor. */
79916dce513Schristos
80016dce513Schristos static FILE *
pex_unix_fdopenr(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary ATTRIBUTE_UNUSED)80116dce513Schristos pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
80216dce513Schristos int binary ATTRIBUTE_UNUSED)
80316dce513Schristos {
80416dce513Schristos return fdopen (fd, "r");
80516dce513Schristos }
80616dce513Schristos
80716dce513Schristos static FILE *
pex_unix_fdopenw(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary ATTRIBUTE_UNUSED)80816dce513Schristos pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
80916dce513Schristos int binary ATTRIBUTE_UNUSED)
81016dce513Schristos {
81116dce513Schristos if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
81216dce513Schristos return NULL;
81316dce513Schristos return fdopen (fd, "w");
81416dce513Schristos }
81516dce513Schristos
81616dce513Schristos static void
pex_unix_cleanup(struct pex_obj * obj ATTRIBUTE_UNUSED)81716dce513Schristos pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED)
81816dce513Schristos {
81916dce513Schristos #if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID)
82016dce513Schristos while (obj->sysdep != NULL)
82116dce513Schristos {
82216dce513Schristos struct status_list *this;
82316dce513Schristos struct status_list *next;
82416dce513Schristos
82516dce513Schristos this = (struct status_list *) obj->sysdep;
82616dce513Schristos next = this->next;
82716dce513Schristos free (this);
82816dce513Schristos obj->sysdep = (void *) next;
82916dce513Schristos }
83016dce513Schristos #endif
83116dce513Schristos }
832