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