source: rtems-tools/rtemstoolkit/libiberty/pex-unix.c @ 78bbe4c

5
Last change on this file since 78bbe4c was 78bbe4c, checked in by Chris Johns <chrisj@…>, on 08/16/17 at 08:09:59

linkers/exe-info Support ARM static constructors.

Note, ARM destructors are registered at runtime and currently not
easly found.

Update libiberty to get a newer demangler.

Closes #3102.

  • Property mode set to 100644
File size: 19.6 KB
Line 
1/* Utilities to execute a program in a subprocess (possibly linked by pipes
2   with other subprocesses), and wait for it.  Generic Unix version
3   (also used for UWIN and VMS).
4   Copyright (C) 1996-2017 Free Software Foundation, Inc.
5
6This file is part of the libiberty library.
7Libiberty is free software; you can redistribute it and/or
8modify it under the terms of the GNU Library General Public
9License as published by the Free Software Foundation; either
10version 2 of the License, or (at your option) any later version.
11
12Libiberty is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15Library General Public License for more details.
16
17You should have received a copy of the GNU Library General Public
18License along with libiberty; see the file COPYING.LIB.  If not,
19write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20Boston, MA 02110-1301, USA.  */
21
22#include "config.h"
23#include "libiberty.h"
24#include "pex-common.h"
25#include "environ.h"
26
27#include <stdio.h>
28#include <signal.h>
29#include <errno.h>
30#ifdef NEED_DECLARATION_ERRNO
31extern int errno;
32#endif
33#ifdef HAVE_STDLIB_H
34#include <stdlib.h>
35#endif
36#ifdef HAVE_STRING_H
37#include <string.h>
38#endif
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42
43#include <sys/types.h>
44
45#ifdef HAVE_FCNTL_H
46#include <fcntl.h>
47#endif
48#ifdef HAVE_SYS_WAIT_H
49#include <sys/wait.h>
50#endif
51#ifdef HAVE_GETRUSAGE
52#include <sys/time.h>
53#include <sys/resource.h>
54#endif
55#ifdef HAVE_SYS_STAT_H
56#include <sys/stat.h>
57#endif
58#ifdef HAVE_PROCESS_H
59#include <process.h>
60#endif
61
62#ifdef vfork /* Autoconf may define this to fork for us. */
63# define VFORK_STRING "fork"
64#else
65# define VFORK_STRING "vfork"
66#endif
67#ifdef HAVE_VFORK_H
68#include <vfork.h>
69#endif
70#if defined(VMS) && defined (__LONG_POINTERS)
71#ifndef __CHAR_PTR32
72typedef char * __char_ptr32
73__attribute__ ((mode (SI)));
74#endif
75
76typedef __char_ptr32 *__char_ptr_char_ptr32
77__attribute__ ((mode (SI)));
78
79/* Return a 32 bit pointer to an array of 32 bit pointers
80   given a 64 bit pointer to an array of 64 bit pointers.  */
81
82static __char_ptr_char_ptr32
83to_ptr32 (char **ptr64)
84{
85  int argc;
86  __char_ptr_char_ptr32 short_argv;
87
88  /* Count number of arguments.  */
89  for (argc = 0; ptr64[argc] != NULL; argc++)
90    ;
91
92  /* Reallocate argv with 32 bit pointers.  */
93  short_argv = (__char_ptr_char_ptr32) decc$malloc
94    (sizeof (__char_ptr32) * (argc + 1));
95
96  for (argc = 0; ptr64[argc] != NULL; argc++)
97    short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
98
99  short_argv[argc] = (__char_ptr32) 0;
100  return short_argv;
101
102}
103#else
104#define to_ptr32(argv) argv
105#endif
106
107/* File mode to use for private and world-readable files.  */
108
109#if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH)
110#define PUBLIC_MODE  \
111    (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
112#else
113#define PUBLIC_MODE 0666
114#endif
115
116/* Get the exit status of a particular process, and optionally get the
117   time that it took.  This is simple if we have wait4, slightly
118   harder if we have waitpid, and is a pain if we only have wait.  */
119
120static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *);
121
122#ifdef HAVE_WAIT4
123
124static pid_t
125pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
126          struct pex_time *time)
127{
128  pid_t ret;
129  struct rusage r;
130
131#ifdef HAVE_WAITPID
132  if (time == NULL)
133    return waitpid (pid, status, 0);
134#endif
135
136  ret = wait4 (pid, status, 0, &r);
137
138  if (time != NULL)
139    {
140      time->user_seconds = r.ru_utime.tv_sec;
141      time->user_microseconds= r.ru_utime.tv_usec;
142      time->system_seconds = r.ru_stime.tv_sec;
143      time->system_microseconds= r.ru_stime.tv_usec;
144    }
145
146  return ret;
147}
148
149#else /* ! defined (HAVE_WAIT4) */
150
151#ifdef HAVE_WAITPID
152
153#ifndef HAVE_GETRUSAGE
154
155static pid_t
156pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
157          struct pex_time *time)
158{
159  if (time != NULL)
160    memset (time, 0, sizeof (struct pex_time));
161  return waitpid (pid, status, 0);
162}
163
164#else /* defined (HAVE_GETRUSAGE) */
165
166static pid_t
167pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
168          struct pex_time *time)
169{
170  struct rusage r1, r2;
171  pid_t ret;
172
173  if (time == NULL)
174    return waitpid (pid, status, 0);
175
176  getrusage (RUSAGE_CHILDREN, &r1);
177
178  ret = waitpid (pid, status, 0);
179  if (ret < 0)
180    return ret;
181
182  getrusage (RUSAGE_CHILDREN, &r2);
183
184  time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
185  time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
186  if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec)
187    {
188      --time->user_seconds;
189      time->user_microseconds += 1000000;
190    }
191
192  time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
193  time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
194  if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec)
195    {
196      --time->system_seconds;
197      time->system_microseconds += 1000000;
198    }
199
200  return ret;
201}
202
203#endif /* defined (HAVE_GETRUSAGE) */
204
205#else /* ! defined (HAVE_WAITPID) */
206
207struct status_list
208{
209  struct status_list *next;
210  pid_t pid;
211  int status;
212  struct pex_time time;
213};
214
215static pid_t
216pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time)
217{
218  struct status_list **pp;
219
220  for (pp = (struct status_list **) &obj->sysdep;
221       *pp != NULL;
222       pp = &(*pp)->next)
223    {
224      if ((*pp)->pid == pid)
225        {
226          struct status_list *p;
227
228          p = *pp;
229          *status = p->status;
230          if (time != NULL)
231            *time = p->time;
232          *pp = p->next;
233          free (p);
234          return pid;
235        }
236    }
237
238  while (1)
239    {
240      pid_t cpid;
241      struct status_list *psl;
242      struct pex_time pt;
243#ifdef HAVE_GETRUSAGE
244      struct rusage r1, r2;
245#endif
246
247      if (time != NULL)
248        {
249#ifdef HAVE_GETRUSAGE
250          getrusage (RUSAGE_CHILDREN, &r1);
251#else
252          memset (&pt, 0, sizeof (struct pex_time));
253#endif
254        }
255
256      cpid = wait (status);
257
258#ifdef HAVE_GETRUSAGE
259      if (time != NULL && cpid >= 0)
260        {
261          getrusage (RUSAGE_CHILDREN, &r2);
262
263          pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
264          pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
265          if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec)
266            {
267              --pt.user_seconds;
268              pt.user_microseconds += 1000000;
269            }
270
271          pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
272          pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
273          if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec)
274            {
275              --pt.system_seconds;
276              pt.system_microseconds += 1000000;
277            }
278        }
279#endif
280
281      if (cpid < 0 || cpid == pid)
282        {
283          if (time != NULL)
284            *time = pt;
285          return cpid;
286        }
287
288      psl = XNEW (struct status_list);
289      psl->pid = cpid;
290      psl->status = *status;
291      if (time != NULL)
292        psl->time = pt;
293      psl->next = (struct status_list *) obj->sysdep;
294      obj->sysdep = (void *) psl;
295    }
296}
297
298#endif /* ! defined (HAVE_WAITPID) */
299#endif /* ! defined (HAVE_WAIT4) */
300
301static void pex_child_error (struct pex_obj *, const char *, const char *, int)
302     ATTRIBUTE_NORETURN;
303static int pex_unix_open_read (struct pex_obj *, const char *, int);
304static int pex_unix_open_write (struct pex_obj *, const char *, int, int);
305static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *,
306                                 char * const *, char * const *,
307                                 int, int, int, int,
308                                 const char **, int *);
309static int pex_unix_close (struct pex_obj *, int);
310static int pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
311                          int, const char **, int *);
312static int pex_unix_pipe (struct pex_obj *, int *, int);
313static FILE *pex_unix_fdopenr (struct pex_obj *, int, int);
314static FILE *pex_unix_fdopenw (struct pex_obj *, int, int);
315static void pex_unix_cleanup (struct pex_obj *);
316
317/* The list of functions we pass to the common routines.  */
318
319const struct pex_funcs funcs =
320{
321  pex_unix_open_read,
322  pex_unix_open_write,
323  pex_unix_exec_child,
324  pex_unix_close,
325  pex_unix_wait,
326  pex_unix_pipe,
327  pex_unix_fdopenr,
328  pex_unix_fdopenw,
329  pex_unix_cleanup
330};
331
332/* Return a newly initialized pex_obj structure.  */
333
334struct pex_obj *
335pex_init (int flags, const char *pname, const char *tempbase)
336{
337  return pex_init_common (flags, pname, tempbase, &funcs);
338}
339
340/* Open a file for reading.  */
341
342static int
343pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
344                    int binary ATTRIBUTE_UNUSED)
345{
346  return open (name, O_RDONLY);
347}
348
349/* Open a file for writing.  */
350
351static int
352pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
353                     int binary ATTRIBUTE_UNUSED, int append)
354{
355  /* Note that we can't use O_EXCL here because gcc may have already
356     created the temporary file via make_temp_file.  */
357  return open (name, O_WRONLY | O_CREAT
358                     | (append ? O_APPEND : O_TRUNC), PUBLIC_MODE);
359}
360
361/* Close a file.  */
362
363static int
364pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
365{
366  return close (fd);
367}
368
369/* Report an error from a child process.  We don't use stdio routines,
370   because we might be here due to a vfork call.  */
371
372static void
373pex_child_error (struct pex_obj *obj, const char *executable,
374                 const char *errmsg, int err)
375{
376  int retval = 0;
377#define writeerr(s) retval |= (write (STDERR_FILE_NO, s, strlen (s)) < 0)
378  writeerr (obj->pname);
379  writeerr (": error trying to exec '");
380  writeerr (executable);
381  writeerr ("': ");
382  writeerr (errmsg);
383  writeerr (": ");
384  writeerr (xstrerror (err));
385  writeerr ("\n");
386#undef writeerr
387  /* Exit with -2 if the error output failed, too.  */
388  _exit (retval == 0 ? -1 : -2);
389}
390
391/* Execute a child.  */
392
393#if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE)
394/* Implementation of pex->exec_child using the Cygwin spawn operation.  */
395
396/* Subroutine of pex_unix_exec_child.  Move OLD_FD to a new file descriptor
397   to be stored in *PNEW_FD, save the flags in *PFLAGS, and arrange for the
398   saved copy to be close-on-exec.  Move CHILD_FD into OLD_FD.  If CHILD_FD
399   is -1, OLD_FD is to be closed.  Return -1 on error.  */
400
401static int
402save_and_install_fd(int *pnew_fd, int *pflags, int old_fd, int child_fd)
403{
404  int new_fd, flags;
405
406  flags = fcntl (old_fd, F_GETFD);
407
408  /* If we could not retrieve the flags, then OLD_FD was not open.  */
409  if (flags < 0)
410    {
411      new_fd = -1, flags = 0;
412      if (child_fd >= 0 && dup2 (child_fd, old_fd) < 0)
413        return -1;
414    }
415  /* If we wish to close OLD_FD, just mark it CLOEXEC.  */
416  else if (child_fd == -1)
417    {
418      new_fd = old_fd;
419      if ((flags & FD_CLOEXEC) == 0 && fcntl (old_fd, F_SETFD, FD_CLOEXEC) < 0)
420        return -1;
421    }
422  /* Otherwise we need to save a copy of OLD_FD before installing CHILD_FD.  */
423  else
424    {
425#ifdef F_DUPFD_CLOEXEC
426      new_fd = fcntl (old_fd, F_DUPFD_CLOEXEC, 3);
427      if (new_fd < 0)
428        return -1;
429#else
430      /* Prefer F_DUPFD over dup in order to avoid getting a new fd
431         in the range 0-2, right where a new stderr fd might get put.  */
432      new_fd = fcntl (old_fd, F_DUPFD, 3);
433      if (new_fd < 0)
434        return -1;
435      if (fcntl (new_fd, F_SETFD, FD_CLOEXEC) < 0)
436        return -1;
437#endif
438      if (dup2 (child_fd, old_fd) < 0)
439        return -1;
440    }
441
442  *pflags = flags;
443  if (pnew_fd)
444    *pnew_fd = new_fd;
445  else if (new_fd != old_fd)
446    abort ();
447
448  return 0;
449}
450
451/* Subroutine of pex_unix_exec_child.  Move SAVE_FD back to OLD_FD
452   restoring FLAGS.  If SAVE_FD < 0, OLD_FD is to be closed.  */
453
454static int
455restore_fd(int old_fd, int save_fd, int flags)
456{
457  /* For SAVE_FD < 0, all we have to do is restore the
458     "closed-ness" of the original.  */
459  if (save_fd < 0)
460    return close (old_fd);
461
462  /* For SAVE_FD == OLD_FD, all we have to do is restore the
463     original setting of the CLOEXEC flag.  */
464  if (save_fd == old_fd)
465    {
466      if (flags & FD_CLOEXEC)
467        return 0;
468      return fcntl (old_fd, F_SETFD, flags);
469    }
470
471  /* Otherwise we have to move the descriptor back, restore the flags,
472     and close the saved copy.  */
473#ifdef HAVE_DUP3
474  if (flags == FD_CLOEXEC)
475    {
476      if (dup3 (save_fd, old_fd, O_CLOEXEC) < 0)
477        return -1;
478    }
479  else
480#endif
481    {
482      if (dup2 (save_fd, old_fd) < 0)
483        return -1;
484      if (flags != 0 && fcntl (old_fd, F_SETFD, flags) < 0)
485        return -1;
486    }
487  return close (save_fd);
488}
489
490static pid_t
491pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED,
492                     int flags, const char *executable,
493                     char * const * argv, char * const * env,
494                     int in, int out, int errdes, int toclose,
495                     const char **errmsg, int *err)
496{
497  int fl_in = 0, fl_out = 0, fl_err = 0, fl_tc = 0;
498  int save_in = -1, save_out = -1, save_err = -1;
499  int max, retries;
500  pid_t pid;
501
502  if (flags & PEX_STDERR_TO_STDOUT)
503    errdes = out;
504
505  /* We need the three standard file descriptors to be set up as for
506     the child before we perform the spawn.  The file descriptors for
507     the parent need to be moved and marked for close-on-exec.  */
508  if (in != STDIN_FILE_NO
509      && save_and_install_fd (&save_in, &fl_in, STDIN_FILE_NO, in) < 0)
510    goto error_dup2;
511  if (out != STDOUT_FILE_NO
512      && save_and_install_fd (&save_out, &fl_out, STDOUT_FILE_NO, out) < 0)
513    goto error_dup2;
514  if (errdes != STDERR_FILE_NO
515      && save_and_install_fd (&save_err, &fl_err, STDERR_FILE_NO, errdes) < 0)
516    goto error_dup2;
517  if (toclose >= 0
518      && save_and_install_fd (NULL, &fl_tc, toclose, -1) < 0)
519    goto error_dup2;
520
521  /* Now that we've moved the file descriptors for the child into place,
522     close the originals.  Be careful not to close any of the standard
523     file descriptors that we just set up.  */
524  max = -1;
525  if (errdes >= 0)
526    max = STDERR_FILE_NO;
527  else if (out >= 0)
528    max = STDOUT_FILE_NO;
529  else if (in >= 0)
530    max = STDIN_FILE_NO;
531  if (in > max)
532    close (in);
533  if (out > max)
534    close (out);
535  if (errdes > max && errdes != out)
536    close (errdes);
537
538  /* If we were not given an environment, use the global environment.  */
539  if (env == NULL)
540    env = environ;
541
542  /* Launch the program.  If we get EAGAIN (normally out of pid's), try
543     again a few times with increasing backoff times.  */
544  retries = 0;
545  while (1)
546    {
547      typedef const char * const *cc_cp;
548
549      if (flags & PEX_SEARCH)
550        pid = spawnvpe (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
551      else
552        pid = spawnve (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
553
554      if (pid > 0)
555        break;
556
557      *err = errno;
558      *errmsg = "spawn";
559      if (errno != EAGAIN || ++retries == 4)
560        return (pid_t) -1;
561      sleep (1 << retries);
562    }
563
564  /* Success.  Restore the parent's file descriptors that we saved above.  */
565  if (toclose >= 0
566      && restore_fd (toclose, toclose, fl_tc) < 0)
567    goto error_dup2;
568  if (in != STDIN_FILE_NO
569      && restore_fd (STDIN_FILE_NO, save_in, fl_in) < 0)
570    goto error_dup2;
571  if (out != STDOUT_FILE_NO
572      && restore_fd (STDOUT_FILE_NO, save_out, fl_out) < 0)
573    goto error_dup2;
574  if (errdes != STDERR_FILE_NO
575      && restore_fd (STDERR_FILE_NO, save_err, fl_err) < 0)
576    goto error_dup2;
577
578  return pid;
579
580 error_dup2:
581  *err = errno;
582  *errmsg = "dup2";
583  return (pid_t) -1;
584}
585
586#else
587/* Implementation of pex->exec_child using standard vfork + exec.  */
588
589static pid_t
590pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
591                     char * const * argv, char * const * env,
592                     int in, int out, int errdes,
593                     int toclose, const char **errmsg, int *err)
594{
595  pid_t pid;
596
597  /* We declare these to be volatile to avoid warnings from gcc about
598     them being clobbered by vfork.  */
599  volatile int sleep_interval;
600  volatile int retries;
601
602  /* We vfork and then set environ in the child before calling execvp.
603     This clobbers the parent's environ so we need to restore it.
604     It would be nice to use one of the exec* functions that takes an
605     environment as a parameter, but that may have portability issues.  */
606  char **save_environ = environ;
607
608  sleep_interval = 1;
609  pid = -1;
610  for (retries = 0; retries < 4; ++retries)
611    {
612      pid = vfork ();
613      if (pid >= 0)
614        break;
615      sleep (sleep_interval);
616      sleep_interval *= 2;
617    }
618
619  switch (pid)
620    {
621    case -1:
622      *err = errno;
623      *errmsg = VFORK_STRING;
624      return (pid_t) -1;
625
626    case 0:
627      /* Child process.  */
628      if (in != STDIN_FILE_NO)
629        {
630          if (dup2 (in, STDIN_FILE_NO) < 0)
631            pex_child_error (obj, executable, "dup2", errno);
632          if (close (in) < 0)
633            pex_child_error (obj, executable, "close", errno);
634        }
635      if (out != STDOUT_FILE_NO)
636        {
637          if (dup2 (out, STDOUT_FILE_NO) < 0)
638            pex_child_error (obj, executable, "dup2", errno);
639          if (close (out) < 0)
640            pex_child_error (obj, executable, "close", errno);
641        }
642      if (errdes != STDERR_FILE_NO)
643        {
644          if (dup2 (errdes, STDERR_FILE_NO) < 0)
645            pex_child_error (obj, executable, "dup2", errno);
646          if (close (errdes) < 0)
647            pex_child_error (obj, executable, "close", errno);
648        }
649      if (toclose >= 0)
650        {
651          if (close (toclose) < 0)
652            pex_child_error (obj, executable, "close", errno);
653        }
654      if ((flags & PEX_STDERR_TO_STDOUT) != 0)
655        {
656          if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
657            pex_child_error (obj, executable, "dup2", errno);
658        }
659
660      if (env)
661        {
662          /* NOTE: In a standard vfork implementation this clobbers the
663             parent's copy of environ "too" (in reality there's only one copy).
664             This is ok as we restore it below.  */
665          environ = (char**) env;
666        }
667
668      if ((flags & PEX_SEARCH) != 0)
669        {
670          execvp (executable, to_ptr32 (argv));
671          pex_child_error (obj, executable, "execvp", errno);
672        }
673      else
674        {
675          execv (executable, to_ptr32 (argv));
676          pex_child_error (obj, executable, "execv", errno);
677        }
678
679      /* NOTREACHED */
680      return (pid_t) -1;
681
682    default:
683      /* Parent process.  */
684
685      /* Restore environ.
686         Note that the parent either doesn't run until the child execs/exits
687         (standard vfork behaviour), or if it does run then vfork is behaving
688         more like fork.  In either case we needn't worry about clobbering
689         the child's copy of environ.  */
690      environ = save_environ;
691
692      if (in != STDIN_FILE_NO)
693        {
694          if (close (in) < 0)
695            {
696              *err = errno;
697              *errmsg = "close";
698              return (pid_t) -1;
699            }
700        }
701      if (out != STDOUT_FILE_NO)
702        {
703          if (close (out) < 0)
704            {
705              *err = errno;
706              *errmsg = "close";
707              return (pid_t) -1;
708            }
709        }
710      if (errdes != STDERR_FILE_NO)
711        {
712          if (close (errdes) < 0)
713            {
714              *err = errno;
715              *errmsg = "close";
716              return (pid_t) -1;
717            }
718        }
719
720      return pid;
721    }
722}
723#endif /* SPAWN */
724
725/* Wait for a child process to complete.  */
726
727static int
728pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status,
729               struct pex_time *time, int done, const char **errmsg,
730               int *err)
731{
732  /* If we are cleaning up when the caller didn't retrieve process
733     status for some reason, encourage the process to go away.  */
734  if (done)
735    kill (pid, SIGTERM);
736
737  if (pex_wait (obj, pid, status, time) < 0)
738    {
739      *err = errno;
740      *errmsg = "wait";
741      return -1;
742    }
743
744  return 0;
745}
746
747/* Create a pipe.  */
748
749static int
750pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
751               int binary ATTRIBUTE_UNUSED)
752{
753  return pipe (p);
754}
755
756/* Get a FILE pointer to read from a file descriptor.  */
757
758static FILE *
759pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
760                  int binary ATTRIBUTE_UNUSED)
761{
762  return fdopen (fd, "r");
763}
764
765static FILE *
766pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
767                  int binary ATTRIBUTE_UNUSED)
768{
769  if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
770    return NULL;
771  return fdopen (fd, "w");
772}
773
774static void
775pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED)
776{
777#if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID)
778  while (obj->sysdep != NULL)
779    {
780      struct status_list *this;
781      struct status_list *next;
782
783      this = (struct status_list *) obj->sysdep;
784      next = this->next;
785      free (this);
786      obj->sysdep = (void *) next;
787    }
788#endif
789}
Note: See TracBrowser for help on using the repository browser.