xref: /dflybsd-src/contrib/gdb-7/libiberty/pex-unix.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
15796c8dcSSimon Schubert /* Utilities to execute a program in a subprocess (possibly linked by pipes
25796c8dcSSimon Schubert    with other subprocesses), and wait for it.  Generic Unix version
35796c8dcSSimon Schubert    (also used for UWIN and VMS).
4c50c785cSJohn Marino    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2009,
5c50c785cSJohn Marino    2010 Free Software Foundation, Inc.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert This file is part of the libiberty library.
85796c8dcSSimon Schubert Libiberty is free software; you can redistribute it and/or
95796c8dcSSimon Schubert modify it under the terms of the GNU Library General Public
105796c8dcSSimon Schubert License as published by the Free Software Foundation; either
115796c8dcSSimon Schubert version 2 of the License, or (at your option) any later version.
125796c8dcSSimon Schubert 
135796c8dcSSimon Schubert Libiberty is distributed in the hope that it will be useful,
145796c8dcSSimon Schubert but WITHOUT ANY WARRANTY; without even the implied warranty of
155796c8dcSSimon Schubert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
165796c8dcSSimon Schubert Library General Public License for more details.
175796c8dcSSimon Schubert 
185796c8dcSSimon Schubert You should have received a copy of the GNU Library General Public
195796c8dcSSimon Schubert License along with libiberty; see the file COPYING.LIB.  If not,
205796c8dcSSimon Schubert write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
215796c8dcSSimon Schubert Boston, MA 02110-1301, USA.  */
225796c8dcSSimon Schubert 
235796c8dcSSimon Schubert #include "config.h"
245796c8dcSSimon Schubert #include "libiberty.h"
255796c8dcSSimon Schubert #include "pex-common.h"
265796c8dcSSimon Schubert 
275796c8dcSSimon Schubert #include <stdio.h>
285796c8dcSSimon Schubert #include <signal.h>
295796c8dcSSimon Schubert #include <errno.h>
305796c8dcSSimon Schubert #ifdef NEED_DECLARATION_ERRNO
315796c8dcSSimon Schubert extern int errno;
325796c8dcSSimon Schubert #endif
335796c8dcSSimon Schubert #ifdef HAVE_STDLIB_H
345796c8dcSSimon Schubert #include <stdlib.h>
355796c8dcSSimon Schubert #endif
365796c8dcSSimon Schubert #ifdef HAVE_STRING_H
375796c8dcSSimon Schubert #include <string.h>
385796c8dcSSimon Schubert #endif
395796c8dcSSimon Schubert #ifdef HAVE_UNISTD_H
405796c8dcSSimon Schubert #include <unistd.h>
415796c8dcSSimon Schubert #endif
425796c8dcSSimon Schubert 
435796c8dcSSimon Schubert #include <sys/types.h>
445796c8dcSSimon Schubert 
455796c8dcSSimon Schubert #ifdef HAVE_FCNTL_H
465796c8dcSSimon Schubert #include <fcntl.h>
475796c8dcSSimon Schubert #endif
485796c8dcSSimon Schubert #ifdef HAVE_SYS_WAIT_H
495796c8dcSSimon Schubert #include <sys/wait.h>
505796c8dcSSimon Schubert #endif
515796c8dcSSimon Schubert #ifdef HAVE_GETRUSAGE
525796c8dcSSimon Schubert #include <sys/time.h>
535796c8dcSSimon Schubert #include <sys/resource.h>
545796c8dcSSimon Schubert #endif
555796c8dcSSimon Schubert #ifdef HAVE_SYS_STAT_H
565796c8dcSSimon Schubert #include <sys/stat.h>
575796c8dcSSimon Schubert #endif
58c50c785cSJohn Marino #ifdef HAVE_PROCESS_H
59c50c785cSJohn Marino #include <process.h>
60c50c785cSJohn Marino #endif
615796c8dcSSimon Schubert 
625796c8dcSSimon Schubert #ifdef vfork /* Autoconf may define this to fork for us. */
635796c8dcSSimon Schubert # define VFORK_STRING "fork"
645796c8dcSSimon Schubert #else
655796c8dcSSimon Schubert # define VFORK_STRING "vfork"
665796c8dcSSimon Schubert #endif
675796c8dcSSimon Schubert #ifdef HAVE_VFORK_H
685796c8dcSSimon Schubert #include <vfork.h>
695796c8dcSSimon Schubert #endif
705796c8dcSSimon Schubert #if defined(VMS) && defined (__LONG_POINTERS)
715796c8dcSSimon Schubert #ifndef __CHAR_PTR32
725796c8dcSSimon Schubert typedef char * __char_ptr32
735796c8dcSSimon Schubert __attribute__ ((mode (SI)));
745796c8dcSSimon Schubert #endif
755796c8dcSSimon Schubert 
765796c8dcSSimon Schubert typedef __char_ptr32 *__char_ptr_char_ptr32
775796c8dcSSimon Schubert __attribute__ ((mode (SI)));
785796c8dcSSimon Schubert 
795796c8dcSSimon Schubert /* Return a 32 bit pointer to an array of 32 bit pointers
805796c8dcSSimon Schubert    given a 64 bit pointer to an array of 64 bit pointers.  */
815796c8dcSSimon Schubert 
825796c8dcSSimon Schubert static __char_ptr_char_ptr32
to_ptr32(char ** ptr64)835796c8dcSSimon Schubert to_ptr32 (char **ptr64)
845796c8dcSSimon Schubert {
855796c8dcSSimon Schubert   int argc;
865796c8dcSSimon Schubert   __char_ptr_char_ptr32 short_argv;
875796c8dcSSimon Schubert 
88*ef5ccd6cSJohn Marino   /* Count number of arguments.  */
89*ef5ccd6cSJohn Marino   for (argc = 0; ptr64[argc] != NULL; argc++)
90*ef5ccd6cSJohn Marino     ;
915796c8dcSSimon Schubert 
925796c8dcSSimon Schubert   /* Reallocate argv with 32 bit pointers.  */
935796c8dcSSimon Schubert   short_argv = (__char_ptr_char_ptr32) decc$malloc
945796c8dcSSimon Schubert     (sizeof (__char_ptr32) * (argc + 1));
955796c8dcSSimon Schubert 
96*ef5ccd6cSJohn Marino   for (argc = 0; ptr64[argc] != NULL; argc++)
975796c8dcSSimon Schubert     short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
985796c8dcSSimon Schubert 
995796c8dcSSimon Schubert   short_argv[argc] = (__char_ptr32) 0;
1005796c8dcSSimon Schubert   return short_argv;
1015796c8dcSSimon Schubert 
1025796c8dcSSimon Schubert }
1035796c8dcSSimon Schubert #else
1045796c8dcSSimon Schubert #define to_ptr32(argv) argv
1055796c8dcSSimon Schubert #endif
1065796c8dcSSimon Schubert 
1075796c8dcSSimon Schubert /* File mode to use for private and world-readable files.  */
1085796c8dcSSimon Schubert 
1095796c8dcSSimon Schubert #if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH)
1105796c8dcSSimon Schubert #define PUBLIC_MODE  \
1115796c8dcSSimon Schubert     (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
1125796c8dcSSimon Schubert #else
1135796c8dcSSimon Schubert #define PUBLIC_MODE 0666
1145796c8dcSSimon Schubert #endif
1155796c8dcSSimon Schubert 
1165796c8dcSSimon Schubert /* Get the exit status of a particular process, and optionally get the
1175796c8dcSSimon Schubert    time that it took.  This is simple if we have wait4, slightly
1185796c8dcSSimon Schubert    harder if we have waitpid, and is a pain if we only have wait.  */
1195796c8dcSSimon Schubert 
1205796c8dcSSimon Schubert static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *);
1215796c8dcSSimon Schubert 
1225796c8dcSSimon Schubert #ifdef HAVE_WAIT4
1235796c8dcSSimon Schubert 
1245796c8dcSSimon Schubert static pid_t
pex_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time)1255796c8dcSSimon Schubert pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
1265796c8dcSSimon Schubert 	  struct pex_time *time)
1275796c8dcSSimon Schubert {
1285796c8dcSSimon Schubert   pid_t ret;
1295796c8dcSSimon Schubert   struct rusage r;
1305796c8dcSSimon Schubert 
1315796c8dcSSimon Schubert #ifdef HAVE_WAITPID
1325796c8dcSSimon Schubert   if (time == NULL)
1335796c8dcSSimon Schubert     return waitpid (pid, status, 0);
1345796c8dcSSimon Schubert #endif
1355796c8dcSSimon Schubert 
1365796c8dcSSimon Schubert   ret = wait4 (pid, status, 0, &r);
1375796c8dcSSimon Schubert 
1385796c8dcSSimon Schubert   if (time != NULL)
1395796c8dcSSimon Schubert     {
1405796c8dcSSimon Schubert       time->user_seconds = r.ru_utime.tv_sec;
1415796c8dcSSimon Schubert       time->user_microseconds= r.ru_utime.tv_usec;
1425796c8dcSSimon Schubert       time->system_seconds = r.ru_stime.tv_sec;
1435796c8dcSSimon Schubert       time->system_microseconds= r.ru_stime.tv_usec;
1445796c8dcSSimon Schubert     }
1455796c8dcSSimon Schubert 
1465796c8dcSSimon Schubert   return ret;
1475796c8dcSSimon Schubert }
1485796c8dcSSimon Schubert 
1495796c8dcSSimon Schubert #else /* ! defined (HAVE_WAIT4) */
1505796c8dcSSimon Schubert 
1515796c8dcSSimon Schubert #ifdef HAVE_WAITPID
1525796c8dcSSimon Schubert 
1535796c8dcSSimon Schubert #ifndef HAVE_GETRUSAGE
1545796c8dcSSimon Schubert 
1555796c8dcSSimon Schubert static pid_t
pex_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time)1565796c8dcSSimon Schubert pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
1575796c8dcSSimon Schubert 	  struct pex_time *time)
1585796c8dcSSimon Schubert {
1595796c8dcSSimon Schubert   if (time != NULL)
1605796c8dcSSimon Schubert     memset (time, 0, sizeof (struct pex_time));
1615796c8dcSSimon Schubert   return waitpid (pid, status, 0);
1625796c8dcSSimon Schubert }
1635796c8dcSSimon Schubert 
1645796c8dcSSimon Schubert #else /* defined (HAVE_GETRUSAGE) */
1655796c8dcSSimon Schubert 
1665796c8dcSSimon Schubert static pid_t
pex_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time)1675796c8dcSSimon Schubert pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
1685796c8dcSSimon Schubert 	  struct pex_time *time)
1695796c8dcSSimon Schubert {
1705796c8dcSSimon Schubert   struct rusage r1, r2;
1715796c8dcSSimon Schubert   pid_t ret;
1725796c8dcSSimon Schubert 
1735796c8dcSSimon Schubert   if (time == NULL)
1745796c8dcSSimon Schubert     return waitpid (pid, status, 0);
1755796c8dcSSimon Schubert 
1765796c8dcSSimon Schubert   getrusage (RUSAGE_CHILDREN, &r1);
1775796c8dcSSimon Schubert 
1785796c8dcSSimon Schubert   ret = waitpid (pid, status, 0);
1795796c8dcSSimon Schubert   if (ret < 0)
1805796c8dcSSimon Schubert     return ret;
1815796c8dcSSimon Schubert 
1825796c8dcSSimon Schubert   getrusage (RUSAGE_CHILDREN, &r2);
1835796c8dcSSimon Schubert 
1845796c8dcSSimon Schubert   time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
1855796c8dcSSimon Schubert   time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
1865796c8dcSSimon Schubert   if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec)
1875796c8dcSSimon Schubert     {
1885796c8dcSSimon Schubert       --time->user_seconds;
1895796c8dcSSimon Schubert       time->user_microseconds += 1000000;
1905796c8dcSSimon Schubert     }
1915796c8dcSSimon Schubert 
1925796c8dcSSimon Schubert   time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
1935796c8dcSSimon Schubert   time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
1945796c8dcSSimon Schubert   if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec)
1955796c8dcSSimon Schubert     {
1965796c8dcSSimon Schubert       --time->system_seconds;
1975796c8dcSSimon Schubert       time->system_microseconds += 1000000;
1985796c8dcSSimon Schubert     }
1995796c8dcSSimon Schubert 
2005796c8dcSSimon Schubert   return ret;
2015796c8dcSSimon Schubert }
2025796c8dcSSimon Schubert 
2035796c8dcSSimon Schubert #endif /* defined (HAVE_GETRUSAGE) */
2045796c8dcSSimon Schubert 
2055796c8dcSSimon Schubert #else /* ! defined (HAVE_WAITPID) */
2065796c8dcSSimon Schubert 
2075796c8dcSSimon Schubert struct status_list
2085796c8dcSSimon Schubert {
2095796c8dcSSimon Schubert   struct status_list *next;
2105796c8dcSSimon Schubert   pid_t pid;
2115796c8dcSSimon Schubert   int status;
2125796c8dcSSimon Schubert   struct pex_time time;
2135796c8dcSSimon Schubert };
2145796c8dcSSimon Schubert 
2155796c8dcSSimon Schubert static pid_t
pex_wait(struct pex_obj * obj,pid_t pid,int * status,struct pex_time * time)2165796c8dcSSimon Schubert pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time)
2175796c8dcSSimon Schubert {
2185796c8dcSSimon Schubert   struct status_list **pp;
2195796c8dcSSimon Schubert 
2205796c8dcSSimon Schubert   for (pp = (struct status_list **) &obj->sysdep;
2215796c8dcSSimon Schubert        *pp != NULL;
2225796c8dcSSimon Schubert        pp = &(*pp)->next)
2235796c8dcSSimon Schubert     {
2245796c8dcSSimon Schubert       if ((*pp)->pid == pid)
2255796c8dcSSimon Schubert 	{
2265796c8dcSSimon Schubert 	  struct status_list *p;
2275796c8dcSSimon Schubert 
2285796c8dcSSimon Schubert 	  p = *pp;
2295796c8dcSSimon Schubert 	  *status = p->status;
2305796c8dcSSimon Schubert 	  if (time != NULL)
2315796c8dcSSimon Schubert 	    *time = p->time;
2325796c8dcSSimon Schubert 	  *pp = p->next;
2335796c8dcSSimon Schubert 	  free (p);
2345796c8dcSSimon Schubert 	  return pid;
2355796c8dcSSimon Schubert 	}
2365796c8dcSSimon Schubert     }
2375796c8dcSSimon Schubert 
2385796c8dcSSimon Schubert   while (1)
2395796c8dcSSimon Schubert     {
2405796c8dcSSimon Schubert       pid_t cpid;
2415796c8dcSSimon Schubert       struct status_list *psl;
2425796c8dcSSimon Schubert       struct pex_time pt;
2435796c8dcSSimon Schubert #ifdef HAVE_GETRUSAGE
2445796c8dcSSimon Schubert       struct rusage r1, r2;
2455796c8dcSSimon Schubert #endif
2465796c8dcSSimon Schubert 
2475796c8dcSSimon Schubert       if (time != NULL)
2485796c8dcSSimon Schubert 	{
2495796c8dcSSimon Schubert #ifdef HAVE_GETRUSAGE
2505796c8dcSSimon Schubert 	  getrusage (RUSAGE_CHILDREN, &r1);
2515796c8dcSSimon Schubert #else
2525796c8dcSSimon Schubert 	  memset (&pt, 0, sizeof (struct pex_time));
2535796c8dcSSimon Schubert #endif
2545796c8dcSSimon Schubert 	}
2555796c8dcSSimon Schubert 
2565796c8dcSSimon Schubert       cpid = wait (status);
2575796c8dcSSimon Schubert 
2585796c8dcSSimon Schubert #ifdef HAVE_GETRUSAGE
2595796c8dcSSimon Schubert       if (time != NULL && cpid >= 0)
2605796c8dcSSimon Schubert 	{
2615796c8dcSSimon Schubert 	  getrusage (RUSAGE_CHILDREN, &r2);
2625796c8dcSSimon Schubert 
2635796c8dcSSimon Schubert 	  pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
2645796c8dcSSimon Schubert 	  pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
2655796c8dcSSimon Schubert 	  if (pt.user_microseconds < 0)
2665796c8dcSSimon Schubert 	    {
2675796c8dcSSimon Schubert 	      --pt.user_seconds;
2685796c8dcSSimon Schubert 	      pt.user_microseconds += 1000000;
2695796c8dcSSimon Schubert 	    }
2705796c8dcSSimon Schubert 
2715796c8dcSSimon Schubert 	  pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
2725796c8dcSSimon Schubert 	  pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
2735796c8dcSSimon Schubert 	  if (pt.system_microseconds < 0)
2745796c8dcSSimon Schubert 	    {
2755796c8dcSSimon Schubert 	      --pt.system_seconds;
2765796c8dcSSimon Schubert 	      pt.system_microseconds += 1000000;
2775796c8dcSSimon Schubert 	    }
2785796c8dcSSimon Schubert 	}
2795796c8dcSSimon Schubert #endif
2805796c8dcSSimon Schubert 
2815796c8dcSSimon Schubert       if (cpid < 0 || cpid == pid)
2825796c8dcSSimon Schubert 	{
2835796c8dcSSimon Schubert 	  if (time != NULL)
2845796c8dcSSimon Schubert 	    *time = pt;
2855796c8dcSSimon Schubert 	  return cpid;
2865796c8dcSSimon Schubert 	}
2875796c8dcSSimon Schubert 
2885796c8dcSSimon Schubert       psl = XNEW (struct status_list);
2895796c8dcSSimon Schubert       psl->pid = cpid;
2905796c8dcSSimon Schubert       psl->status = *status;
2915796c8dcSSimon Schubert       if (time != NULL)
2925796c8dcSSimon Schubert 	psl->time = pt;
2935796c8dcSSimon Schubert       psl->next = (struct status_list *) obj->sysdep;
2945796c8dcSSimon Schubert       obj->sysdep = (void *) psl;
2955796c8dcSSimon Schubert     }
2965796c8dcSSimon Schubert }
2975796c8dcSSimon Schubert 
2985796c8dcSSimon Schubert #endif /* ! defined (HAVE_WAITPID) */
2995796c8dcSSimon Schubert #endif /* ! defined (HAVE_WAIT4) */
3005796c8dcSSimon Schubert 
3015796c8dcSSimon Schubert static void pex_child_error (struct pex_obj *, const char *, const char *, int)
3025796c8dcSSimon Schubert      ATTRIBUTE_NORETURN;
3035796c8dcSSimon Schubert static int pex_unix_open_read (struct pex_obj *, const char *, int);
3045796c8dcSSimon Schubert static int pex_unix_open_write (struct pex_obj *, const char *, int);
3055796c8dcSSimon Schubert static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *,
3065796c8dcSSimon Schubert 				 char * const *, char * const *,
3075796c8dcSSimon Schubert 				 int, int, int, int,
3085796c8dcSSimon Schubert 				 const char **, int *);
3095796c8dcSSimon Schubert static int pex_unix_close (struct pex_obj *, int);
3105796c8dcSSimon Schubert static int pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
3115796c8dcSSimon Schubert 			  int, const char **, int *);
3125796c8dcSSimon Schubert static int pex_unix_pipe (struct pex_obj *, int *, int);
3135796c8dcSSimon Schubert static FILE *pex_unix_fdopenr (struct pex_obj *, int, int);
3145796c8dcSSimon Schubert static FILE *pex_unix_fdopenw (struct pex_obj *, int, int);
3155796c8dcSSimon Schubert static void pex_unix_cleanup (struct pex_obj *);
3165796c8dcSSimon Schubert 
3175796c8dcSSimon Schubert /* The list of functions we pass to the common routines.  */
3185796c8dcSSimon Schubert 
3195796c8dcSSimon Schubert const struct pex_funcs funcs =
3205796c8dcSSimon Schubert {
3215796c8dcSSimon Schubert   pex_unix_open_read,
3225796c8dcSSimon Schubert   pex_unix_open_write,
3235796c8dcSSimon Schubert   pex_unix_exec_child,
3245796c8dcSSimon Schubert   pex_unix_close,
3255796c8dcSSimon Schubert   pex_unix_wait,
3265796c8dcSSimon Schubert   pex_unix_pipe,
3275796c8dcSSimon Schubert   pex_unix_fdopenr,
3285796c8dcSSimon Schubert   pex_unix_fdopenw,
3295796c8dcSSimon Schubert   pex_unix_cleanup
3305796c8dcSSimon Schubert };
3315796c8dcSSimon Schubert 
3325796c8dcSSimon Schubert /* Return a newly initialized pex_obj structure.  */
3335796c8dcSSimon Schubert 
3345796c8dcSSimon Schubert struct pex_obj *
pex_init(int flags,const char * pname,const char * tempbase)3355796c8dcSSimon Schubert pex_init (int flags, const char *pname, const char *tempbase)
3365796c8dcSSimon Schubert {
3375796c8dcSSimon Schubert   return pex_init_common (flags, pname, tempbase, &funcs);
3385796c8dcSSimon Schubert }
3395796c8dcSSimon Schubert 
3405796c8dcSSimon Schubert /* Open a file for reading.  */
3415796c8dcSSimon Schubert 
3425796c8dcSSimon Schubert static int
pex_unix_open_read(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary ATTRIBUTE_UNUSED)3435796c8dcSSimon Schubert pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
3445796c8dcSSimon Schubert 		    int binary ATTRIBUTE_UNUSED)
3455796c8dcSSimon Schubert {
3465796c8dcSSimon Schubert   return open (name, O_RDONLY);
3475796c8dcSSimon Schubert }
3485796c8dcSSimon Schubert 
3495796c8dcSSimon Schubert /* Open a file for writing.  */
3505796c8dcSSimon Schubert 
3515796c8dcSSimon Schubert static int
pex_unix_open_write(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary ATTRIBUTE_UNUSED)3525796c8dcSSimon Schubert pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
3535796c8dcSSimon Schubert 		     int binary ATTRIBUTE_UNUSED)
3545796c8dcSSimon Schubert {
3555796c8dcSSimon Schubert   /* Note that we can't use O_EXCL here because gcc may have already
3565796c8dcSSimon Schubert      created the temporary file via make_temp_file.  */
3575796c8dcSSimon Schubert   return open (name, O_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE);
3585796c8dcSSimon Schubert }
3595796c8dcSSimon Schubert 
3605796c8dcSSimon Schubert /* Close a file.  */
3615796c8dcSSimon Schubert 
3625796c8dcSSimon Schubert static int
pex_unix_close(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd)3635796c8dcSSimon Schubert pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
3645796c8dcSSimon Schubert {
3655796c8dcSSimon Schubert   return close (fd);
3665796c8dcSSimon Schubert }
3675796c8dcSSimon Schubert 
3685796c8dcSSimon Schubert /* Report an error from a child process.  We don't use stdio routines,
3695796c8dcSSimon Schubert    because we might be here due to a vfork call.  */
3705796c8dcSSimon Schubert 
3715796c8dcSSimon Schubert static void
pex_child_error(struct pex_obj * obj,const char * executable,const char * errmsg,int err)3725796c8dcSSimon Schubert pex_child_error (struct pex_obj *obj, const char *executable,
3735796c8dcSSimon Schubert 		 const char *errmsg, int err)
3745796c8dcSSimon Schubert {
375cf7f2e2dSJohn Marino   int retval = 0;
376cf7f2e2dSJohn Marino #define writeerr(s) retval |= (write (STDERR_FILE_NO, s, strlen (s)) < 0)
3775796c8dcSSimon Schubert   writeerr (obj->pname);
3785796c8dcSSimon Schubert   writeerr (": error trying to exec '");
3795796c8dcSSimon Schubert   writeerr (executable);
3805796c8dcSSimon Schubert   writeerr ("': ");
3815796c8dcSSimon Schubert   writeerr (errmsg);
3825796c8dcSSimon Schubert   writeerr (": ");
3835796c8dcSSimon Schubert   writeerr (xstrerror (err));
3845796c8dcSSimon Schubert   writeerr ("\n");
385cf7f2e2dSJohn Marino #undef writeerr
386cf7f2e2dSJohn Marino   /* Exit with -2 if the error output failed, too.  */
387cf7f2e2dSJohn Marino   _exit (retval == 0 ? -1 : -2);
3885796c8dcSSimon Schubert }
3895796c8dcSSimon Schubert 
3905796c8dcSSimon Schubert /* Execute a child.  */
3915796c8dcSSimon Schubert 
3925796c8dcSSimon Schubert extern char **environ;
3935796c8dcSSimon Schubert 
394c50c785cSJohn Marino #if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE)
395c50c785cSJohn Marino /* Implementation of pex->exec_child using the Cygwin spawn operation.  */
396c50c785cSJohn Marino 
397c50c785cSJohn Marino /* Subroutine of pex_unix_exec_child.  Move OLD_FD to a new file descriptor
398c50c785cSJohn Marino    to be stored in *PNEW_FD, save the flags in *PFLAGS, and arrange for the
399c50c785cSJohn Marino    saved copy to be close-on-exec.  Move CHILD_FD into OLD_FD.  If CHILD_FD
400c50c785cSJohn Marino    is -1, OLD_FD is to be closed.  Return -1 on error.  */
401c50c785cSJohn Marino 
402c50c785cSJohn Marino static int
save_and_install_fd(int * pnew_fd,int * pflags,int old_fd,int child_fd)403c50c785cSJohn Marino save_and_install_fd(int *pnew_fd, int *pflags, int old_fd, int child_fd)
404c50c785cSJohn Marino {
405c50c785cSJohn Marino   int new_fd, flags;
406c50c785cSJohn Marino 
407c50c785cSJohn Marino   flags = fcntl (old_fd, F_GETFD);
408c50c785cSJohn Marino 
409c50c785cSJohn Marino   /* If we could not retrieve the flags, then OLD_FD was not open.  */
410c50c785cSJohn Marino   if (flags < 0)
411c50c785cSJohn Marino     {
412c50c785cSJohn Marino       new_fd = -1, flags = 0;
413c50c785cSJohn Marino       if (child_fd >= 0 && dup2 (child_fd, old_fd) < 0)
414c50c785cSJohn Marino 	return -1;
415c50c785cSJohn Marino     }
416c50c785cSJohn Marino   /* If we wish to close OLD_FD, just mark it CLOEXEC.  */
417c50c785cSJohn Marino   else if (child_fd == -1)
418c50c785cSJohn Marino     {
419c50c785cSJohn Marino       new_fd = old_fd;
420c50c785cSJohn Marino       if ((flags & FD_CLOEXEC) == 0 && fcntl (old_fd, F_SETFD, FD_CLOEXEC) < 0)
421c50c785cSJohn Marino 	return -1;
422c50c785cSJohn Marino     }
423c50c785cSJohn Marino   /* Otherwise we need to save a copy of OLD_FD before installing CHILD_FD.  */
424c50c785cSJohn Marino   else
425c50c785cSJohn Marino     {
426c50c785cSJohn Marino #ifdef F_DUPFD_CLOEXEC
427c50c785cSJohn Marino       new_fd = fcntl (old_fd, F_DUPFD_CLOEXEC, 3);
428c50c785cSJohn Marino       if (new_fd < 0)
429c50c785cSJohn Marino 	return -1;
430c50c785cSJohn Marino #else
431c50c785cSJohn Marino       /* Prefer F_DUPFD over dup in order to avoid getting a new fd
432c50c785cSJohn Marino 	 in the range 0-2, right where a new stderr fd might get put.  */
433c50c785cSJohn Marino       new_fd = fcntl (old_fd, F_DUPFD, 3);
434c50c785cSJohn Marino       if (new_fd < 0)
435c50c785cSJohn Marino 	return -1;
436c50c785cSJohn Marino       if (fcntl (new_fd, F_SETFD, FD_CLOEXEC) < 0)
437c50c785cSJohn Marino 	return -1;
438c50c785cSJohn Marino #endif
439c50c785cSJohn Marino       if (dup2 (child_fd, old_fd) < 0)
440c50c785cSJohn Marino 	return -1;
441c50c785cSJohn Marino     }
442c50c785cSJohn Marino 
443c50c785cSJohn Marino   *pflags = flags;
444c50c785cSJohn Marino   if (pnew_fd)
445c50c785cSJohn Marino     *pnew_fd = new_fd;
446c50c785cSJohn Marino   else if (new_fd != old_fd)
447c50c785cSJohn Marino     abort ();
448c50c785cSJohn Marino 
449c50c785cSJohn Marino   return 0;
450c50c785cSJohn Marino }
451c50c785cSJohn Marino 
452c50c785cSJohn Marino /* Subroutine of pex_unix_exec_child.  Move SAVE_FD back to OLD_FD
453c50c785cSJohn Marino    restoring FLAGS.  If SAVE_FD < 0, OLD_FD is to be closed.  */
454c50c785cSJohn Marino 
455c50c785cSJohn Marino static int
restore_fd(int old_fd,int save_fd,int flags)456c50c785cSJohn Marino restore_fd(int old_fd, int save_fd, int flags)
457c50c785cSJohn Marino {
458c50c785cSJohn Marino   /* For SAVE_FD < 0, all we have to do is restore the
459c50c785cSJohn Marino      "closed-ness" of the original.  */
460c50c785cSJohn Marino   if (save_fd < 0)
461c50c785cSJohn Marino     return close (old_fd);
462c50c785cSJohn Marino 
463c50c785cSJohn Marino   /* For SAVE_FD == OLD_FD, all we have to do is restore the
464c50c785cSJohn Marino      original setting of the CLOEXEC flag.  */
465c50c785cSJohn Marino   if (save_fd == old_fd)
466c50c785cSJohn Marino     {
467c50c785cSJohn Marino       if (flags & FD_CLOEXEC)
468c50c785cSJohn Marino 	return 0;
469c50c785cSJohn Marino       return fcntl (old_fd, F_SETFD, flags);
470c50c785cSJohn Marino     }
471c50c785cSJohn Marino 
472c50c785cSJohn Marino   /* Otherwise we have to move the descriptor back, restore the flags,
473c50c785cSJohn Marino      and close the saved copy.  */
474c50c785cSJohn Marino #ifdef HAVE_DUP3
475c50c785cSJohn Marino   if (flags == FD_CLOEXEC)
476c50c785cSJohn Marino     {
477c50c785cSJohn Marino       if (dup3 (save_fd, old_fd, O_CLOEXEC) < 0)
478c50c785cSJohn Marino 	return -1;
479c50c785cSJohn Marino     }
480c50c785cSJohn Marino   else
481c50c785cSJohn Marino #endif
482c50c785cSJohn Marino     {
483c50c785cSJohn Marino       if (dup2 (save_fd, old_fd) < 0)
484c50c785cSJohn Marino 	return -1;
485c50c785cSJohn Marino       if (flags != 0 && fcntl (old_fd, F_SETFD, flags) < 0)
486c50c785cSJohn Marino 	return -1;
487c50c785cSJohn Marino     }
488c50c785cSJohn Marino   return close (save_fd);
489c50c785cSJohn Marino }
490c50c785cSJohn Marino 
491c50c785cSJohn Marino 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)492c50c785cSJohn Marino pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED,
493c50c785cSJohn Marino 		     int flags, const char *executable,
494c50c785cSJohn Marino 		     char * const * argv, char * const * env,
495c50c785cSJohn Marino                      int in, int out, int errdes, int toclose,
496c50c785cSJohn Marino 		     const char **errmsg, int *err)
497c50c785cSJohn Marino {
498c50c785cSJohn Marino   int fl_in = 0, fl_out = 0, fl_err = 0, fl_tc = 0;
499c50c785cSJohn Marino   int save_in = -1, save_out = -1, save_err = -1;
500c50c785cSJohn Marino   int max, retries;
501c50c785cSJohn Marino   pid_t pid;
502c50c785cSJohn Marino 
503c50c785cSJohn Marino   if (flags & PEX_STDERR_TO_STDOUT)
504c50c785cSJohn Marino     errdes = out;
505c50c785cSJohn Marino 
506c50c785cSJohn Marino   /* We need the three standard file descriptors to be set up as for
507c50c785cSJohn Marino      the child before we perform the spawn.  The file descriptors for
508c50c785cSJohn Marino      the parent need to be moved and marked for close-on-exec.  */
509c50c785cSJohn Marino   if (in != STDIN_FILE_NO
510c50c785cSJohn Marino       && save_and_install_fd (&save_in, &fl_in, STDIN_FILE_NO, in) < 0)
511c50c785cSJohn Marino     goto error_dup2;
512c50c785cSJohn Marino   if (out != STDOUT_FILE_NO
513c50c785cSJohn Marino       && save_and_install_fd (&save_out, &fl_out, STDOUT_FILE_NO, out) < 0)
514c50c785cSJohn Marino     goto error_dup2;
515c50c785cSJohn Marino   if (errdes != STDERR_FILE_NO
516c50c785cSJohn Marino       && save_and_install_fd (&save_err, &fl_err, STDERR_FILE_NO, errdes) < 0)
517c50c785cSJohn Marino     goto error_dup2;
518c50c785cSJohn Marino   if (toclose >= 0
519c50c785cSJohn Marino       && save_and_install_fd (NULL, &fl_tc, toclose, -1) < 0)
520c50c785cSJohn Marino     goto error_dup2;
521c50c785cSJohn Marino 
522c50c785cSJohn Marino   /* Now that we've moved the file descriptors for the child into place,
523c50c785cSJohn Marino      close the originals.  Be careful not to close any of the standard
524c50c785cSJohn Marino      file descriptors that we just set up.  */
525c50c785cSJohn Marino   max = -1;
526c50c785cSJohn Marino   if (errdes >= 0)
527c50c785cSJohn Marino     max = STDERR_FILE_NO;
528c50c785cSJohn Marino   else if (out >= 0)
529c50c785cSJohn Marino     max = STDOUT_FILE_NO;
530c50c785cSJohn Marino   else if (in >= 0)
531c50c785cSJohn Marino     max = STDIN_FILE_NO;
532c50c785cSJohn Marino   if (in > max)
533c50c785cSJohn Marino     close (in);
534c50c785cSJohn Marino   if (out > max)
535c50c785cSJohn Marino     close (out);
536c50c785cSJohn Marino   if (errdes > max && errdes != out)
537c50c785cSJohn Marino     close (errdes);
538c50c785cSJohn Marino 
539c50c785cSJohn Marino   /* If we were not given an environment, use the global environment.  */
540c50c785cSJohn Marino   if (env == NULL)
541c50c785cSJohn Marino     env = environ;
542c50c785cSJohn Marino 
543c50c785cSJohn Marino   /* Launch the program.  If we get EAGAIN (normally out of pid's), try
544c50c785cSJohn Marino      again a few times with increasing backoff times.  */
545c50c785cSJohn Marino   retries = 0;
546c50c785cSJohn Marino   while (1)
547c50c785cSJohn Marino     {
548c50c785cSJohn Marino       typedef const char * const *cc_cp;
549c50c785cSJohn Marino 
550c50c785cSJohn Marino       if (flags & PEX_SEARCH)
551c50c785cSJohn Marino 	pid = spawnvpe (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
552c50c785cSJohn Marino       else
553c50c785cSJohn Marino 	pid = spawnve (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
554c50c785cSJohn Marino 
555c50c785cSJohn Marino       if (pid > 0)
556c50c785cSJohn Marino 	break;
557c50c785cSJohn Marino 
558c50c785cSJohn Marino       *err = errno;
559c50c785cSJohn Marino       *errmsg = "spawn";
560c50c785cSJohn Marino       if (errno != EAGAIN || ++retries == 4)
561c50c785cSJohn Marino 	return (pid_t) -1;
562c50c785cSJohn Marino       sleep (1 << retries);
563c50c785cSJohn Marino     }
564c50c785cSJohn Marino 
565c50c785cSJohn Marino   /* Success.  Restore the parent's file descriptors that we saved above.  */
566c50c785cSJohn Marino   if (toclose >= 0
567c50c785cSJohn Marino       && restore_fd (toclose, toclose, fl_tc) < 0)
568c50c785cSJohn Marino     goto error_dup2;
569c50c785cSJohn Marino   if (in != STDIN_FILE_NO
570c50c785cSJohn Marino       && restore_fd (STDIN_FILE_NO, save_in, fl_in) < 0)
571c50c785cSJohn Marino     goto error_dup2;
572c50c785cSJohn Marino   if (out != STDOUT_FILE_NO
573c50c785cSJohn Marino       && restore_fd (STDOUT_FILE_NO, save_out, fl_out) < 0)
574c50c785cSJohn Marino     goto error_dup2;
575c50c785cSJohn Marino   if (errdes != STDERR_FILE_NO
576c50c785cSJohn Marino       && restore_fd (STDERR_FILE_NO, save_err, fl_err) < 0)
577c50c785cSJohn Marino     goto error_dup2;
578c50c785cSJohn Marino 
579c50c785cSJohn Marino   return pid;
580c50c785cSJohn Marino 
581c50c785cSJohn Marino  error_dup2:
582c50c785cSJohn Marino   *err = errno;
583c50c785cSJohn Marino   *errmsg = "dup2";
584c50c785cSJohn Marino   return (pid_t) -1;
585c50c785cSJohn Marino }
586c50c785cSJohn Marino 
587c50c785cSJohn Marino #else
588c50c785cSJohn Marino /* Implementation of pex->exec_child using standard vfork + exec.  */
589c50c785cSJohn Marino 
5905796c8dcSSimon Schubert 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)5915796c8dcSSimon Schubert pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
5925796c8dcSSimon Schubert 		     char * const * argv, char * const * env,
5935796c8dcSSimon Schubert                      int in, int out, int errdes,
5945796c8dcSSimon Schubert 		     int toclose, const char **errmsg, int *err)
5955796c8dcSSimon Schubert {
5965796c8dcSSimon Schubert   pid_t pid;
5975796c8dcSSimon Schubert 
5985796c8dcSSimon Schubert   /* We declare these to be volatile to avoid warnings from gcc about
5995796c8dcSSimon Schubert      them being clobbered by vfork.  */
6005796c8dcSSimon Schubert   volatile int sleep_interval;
6015796c8dcSSimon Schubert   volatile int retries;
6025796c8dcSSimon Schubert 
603cf7f2e2dSJohn Marino   /* We vfork and then set environ in the child before calling execvp.
604cf7f2e2dSJohn Marino      This clobbers the parent's environ so we need to restore it.
605cf7f2e2dSJohn Marino      It would be nice to use one of the exec* functions that takes an
606cf7f2e2dSJohn Marino      environment as a parameter, but that may have portability issues.  */
607cf7f2e2dSJohn Marino   char **save_environ = environ;
608cf7f2e2dSJohn Marino 
6095796c8dcSSimon Schubert   sleep_interval = 1;
6105796c8dcSSimon Schubert   pid = -1;
6115796c8dcSSimon Schubert   for (retries = 0; retries < 4; ++retries)
6125796c8dcSSimon Schubert     {
6135796c8dcSSimon Schubert       pid = vfork ();
6145796c8dcSSimon Schubert       if (pid >= 0)
6155796c8dcSSimon Schubert 	break;
6165796c8dcSSimon Schubert       sleep (sleep_interval);
6175796c8dcSSimon Schubert       sleep_interval *= 2;
6185796c8dcSSimon Schubert     }
6195796c8dcSSimon Schubert 
6205796c8dcSSimon Schubert   switch (pid)
6215796c8dcSSimon Schubert     {
6225796c8dcSSimon Schubert     case -1:
6235796c8dcSSimon Schubert       *err = errno;
6245796c8dcSSimon Schubert       *errmsg = VFORK_STRING;
6255796c8dcSSimon Schubert       return (pid_t) -1;
6265796c8dcSSimon Schubert 
6275796c8dcSSimon Schubert     case 0:
6285796c8dcSSimon Schubert       /* Child process.  */
6295796c8dcSSimon Schubert       if (in != STDIN_FILE_NO)
6305796c8dcSSimon Schubert 	{
6315796c8dcSSimon Schubert 	  if (dup2 (in, STDIN_FILE_NO) < 0)
6325796c8dcSSimon Schubert 	    pex_child_error (obj, executable, "dup2", errno);
6335796c8dcSSimon Schubert 	  if (close (in) < 0)
6345796c8dcSSimon Schubert 	    pex_child_error (obj, executable, "close", errno);
6355796c8dcSSimon Schubert 	}
6365796c8dcSSimon Schubert       if (out != STDOUT_FILE_NO)
6375796c8dcSSimon Schubert 	{
6385796c8dcSSimon Schubert 	  if (dup2 (out, STDOUT_FILE_NO) < 0)
6395796c8dcSSimon Schubert 	    pex_child_error (obj, executable, "dup2", errno);
6405796c8dcSSimon Schubert 	  if (close (out) < 0)
6415796c8dcSSimon Schubert 	    pex_child_error (obj, executable, "close", errno);
6425796c8dcSSimon Schubert 	}
6435796c8dcSSimon Schubert       if (errdes != STDERR_FILE_NO)
6445796c8dcSSimon Schubert 	{
6455796c8dcSSimon Schubert 	  if (dup2 (errdes, STDERR_FILE_NO) < 0)
6465796c8dcSSimon Schubert 	    pex_child_error (obj, executable, "dup2", errno);
6475796c8dcSSimon Schubert 	  if (close (errdes) < 0)
6485796c8dcSSimon Schubert 	    pex_child_error (obj, executable, "close", errno);
6495796c8dcSSimon Schubert 	}
6505796c8dcSSimon Schubert       if (toclose >= 0)
6515796c8dcSSimon Schubert 	{
6525796c8dcSSimon Schubert 	  if (close (toclose) < 0)
6535796c8dcSSimon Schubert 	    pex_child_error (obj, executable, "close", errno);
6545796c8dcSSimon Schubert 	}
6555796c8dcSSimon Schubert       if ((flags & PEX_STDERR_TO_STDOUT) != 0)
6565796c8dcSSimon Schubert 	{
6575796c8dcSSimon Schubert 	  if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
6585796c8dcSSimon Schubert 	    pex_child_error (obj, executable, "dup2", errno);
6595796c8dcSSimon Schubert 	}
6605796c8dcSSimon Schubert 
6615796c8dcSSimon Schubert       if (env)
662cf7f2e2dSJohn Marino 	{
663cf7f2e2dSJohn Marino 	  /* NOTE: In a standard vfork implementation this clobbers the
664cf7f2e2dSJohn Marino 	     parent's copy of environ "too" (in reality there's only one copy).
665cf7f2e2dSJohn Marino 	     This is ok as we restore it below.  */
6665796c8dcSSimon Schubert 	  environ = (char**) env;
667cf7f2e2dSJohn Marino 	}
6685796c8dcSSimon Schubert 
6695796c8dcSSimon Schubert       if ((flags & PEX_SEARCH) != 0)
6705796c8dcSSimon Schubert 	{
6715796c8dcSSimon Schubert 	  execvp (executable, to_ptr32 (argv));
6725796c8dcSSimon Schubert 	  pex_child_error (obj, executable, "execvp", errno);
6735796c8dcSSimon Schubert 	}
6745796c8dcSSimon Schubert       else
6755796c8dcSSimon Schubert 	{
6765796c8dcSSimon Schubert 	  execv (executable, to_ptr32 (argv));
6775796c8dcSSimon Schubert 	  pex_child_error (obj, executable, "execv", errno);
6785796c8dcSSimon Schubert 	}
6795796c8dcSSimon Schubert 
6805796c8dcSSimon Schubert       /* NOTREACHED */
6815796c8dcSSimon Schubert       return (pid_t) -1;
6825796c8dcSSimon Schubert 
6835796c8dcSSimon Schubert     default:
6845796c8dcSSimon Schubert       /* Parent process.  */
685cf7f2e2dSJohn Marino 
686cf7f2e2dSJohn Marino       /* Restore environ.
687cf7f2e2dSJohn Marino 	 Note that the parent either doesn't run until the child execs/exits
688cf7f2e2dSJohn Marino 	 (standard vfork behaviour), or if it does run then vfork is behaving
689cf7f2e2dSJohn Marino 	 more like fork.  In either case we needn't worry about clobbering
690cf7f2e2dSJohn Marino 	 the child's copy of environ.  */
691cf7f2e2dSJohn Marino       environ = save_environ;
692cf7f2e2dSJohn Marino 
6935796c8dcSSimon Schubert       if (in != STDIN_FILE_NO)
6945796c8dcSSimon Schubert 	{
6955796c8dcSSimon Schubert 	  if (close (in) < 0)
6965796c8dcSSimon Schubert 	    {
6975796c8dcSSimon Schubert 	      *err = errno;
6985796c8dcSSimon Schubert 	      *errmsg = "close";
6995796c8dcSSimon Schubert 	      return (pid_t) -1;
7005796c8dcSSimon Schubert 	    }
7015796c8dcSSimon Schubert 	}
7025796c8dcSSimon Schubert       if (out != STDOUT_FILE_NO)
7035796c8dcSSimon Schubert 	{
7045796c8dcSSimon Schubert 	  if (close (out) < 0)
7055796c8dcSSimon Schubert 	    {
7065796c8dcSSimon Schubert 	      *err = errno;
7075796c8dcSSimon Schubert 	      *errmsg = "close";
7085796c8dcSSimon Schubert 	      return (pid_t) -1;
7095796c8dcSSimon Schubert 	    }
7105796c8dcSSimon Schubert 	}
7115796c8dcSSimon Schubert       if (errdes != STDERR_FILE_NO)
7125796c8dcSSimon Schubert 	{
7135796c8dcSSimon Schubert 	  if (close (errdes) < 0)
7145796c8dcSSimon Schubert 	    {
7155796c8dcSSimon Schubert 	      *err = errno;
7165796c8dcSSimon Schubert 	      *errmsg = "close";
7175796c8dcSSimon Schubert 	      return (pid_t) -1;
7185796c8dcSSimon Schubert 	    }
7195796c8dcSSimon Schubert 	}
7205796c8dcSSimon Schubert 
7215796c8dcSSimon Schubert       return pid;
7225796c8dcSSimon Schubert     }
7235796c8dcSSimon Schubert }
724c50c785cSJohn Marino #endif /* SPAWN */
7255796c8dcSSimon Schubert 
7265796c8dcSSimon Schubert /* Wait for a child process to complete.  */
7275796c8dcSSimon Schubert 
7285796c8dcSSimon Schubert 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)7295796c8dcSSimon Schubert pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status,
7305796c8dcSSimon Schubert 	       struct pex_time *time, int done, const char **errmsg,
7315796c8dcSSimon Schubert 	       int *err)
7325796c8dcSSimon Schubert {
7335796c8dcSSimon Schubert   /* If we are cleaning up when the caller didn't retrieve process
7345796c8dcSSimon Schubert      status for some reason, encourage the process to go away.  */
7355796c8dcSSimon Schubert   if (done)
7365796c8dcSSimon Schubert     kill (pid, SIGTERM);
7375796c8dcSSimon Schubert 
7385796c8dcSSimon Schubert   if (pex_wait (obj, pid, status, time) < 0)
7395796c8dcSSimon Schubert     {
7405796c8dcSSimon Schubert       *err = errno;
7415796c8dcSSimon Schubert       *errmsg = "wait";
7425796c8dcSSimon Schubert       return -1;
7435796c8dcSSimon Schubert     }
7445796c8dcSSimon Schubert 
7455796c8dcSSimon Schubert   return 0;
7465796c8dcSSimon Schubert }
7475796c8dcSSimon Schubert 
7485796c8dcSSimon Schubert /* Create a pipe.  */
7495796c8dcSSimon Schubert 
7505796c8dcSSimon Schubert static int
pex_unix_pipe(struct pex_obj * obj ATTRIBUTE_UNUSED,int * p,int binary ATTRIBUTE_UNUSED)7515796c8dcSSimon Schubert pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
7525796c8dcSSimon Schubert 	       int binary ATTRIBUTE_UNUSED)
7535796c8dcSSimon Schubert {
7545796c8dcSSimon Schubert   return pipe (p);
7555796c8dcSSimon Schubert }
7565796c8dcSSimon Schubert 
7575796c8dcSSimon Schubert /* Get a FILE pointer to read from a file descriptor.  */
7585796c8dcSSimon Schubert 
7595796c8dcSSimon Schubert static FILE *
pex_unix_fdopenr(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary ATTRIBUTE_UNUSED)7605796c8dcSSimon Schubert pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
7615796c8dcSSimon Schubert 		  int binary ATTRIBUTE_UNUSED)
7625796c8dcSSimon Schubert {
7635796c8dcSSimon Schubert   return fdopen (fd, "r");
7645796c8dcSSimon Schubert }
7655796c8dcSSimon Schubert 
7665796c8dcSSimon Schubert static FILE *
pex_unix_fdopenw(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary ATTRIBUTE_UNUSED)7675796c8dcSSimon Schubert pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
7685796c8dcSSimon Schubert 		  int binary ATTRIBUTE_UNUSED)
7695796c8dcSSimon Schubert {
7705796c8dcSSimon Schubert   if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
7715796c8dcSSimon Schubert     return NULL;
7725796c8dcSSimon Schubert   return fdopen (fd, "w");
7735796c8dcSSimon Schubert }
7745796c8dcSSimon Schubert 
7755796c8dcSSimon Schubert static void
pex_unix_cleanup(struct pex_obj * obj ATTRIBUTE_UNUSED)7765796c8dcSSimon Schubert pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED)
7775796c8dcSSimon Schubert {
7785796c8dcSSimon Schubert #if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID)
7795796c8dcSSimon Schubert   while (obj->sysdep != NULL)
7805796c8dcSSimon Schubert     {
7815796c8dcSSimon Schubert       struct status_list *this;
7825796c8dcSSimon Schubert       struct status_list *next;
7835796c8dcSSimon Schubert 
7845796c8dcSSimon Schubert       this = (struct status_list *) obj->sysdep;
7855796c8dcSSimon Schubert       next = this->next;
7865796c8dcSSimon Schubert       free (this);
7875796c8dcSSimon Schubert       obj->sysdep = (void *) next;
7885796c8dcSSimon Schubert     }
7895796c8dcSSimon Schubert #endif
7905796c8dcSSimon Schubert }
791