xref: /netbsd-src/external/gpl3/binutils.old/dist/libiberty/pex-unix.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
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