Back to index

cell-binutils  2.17cvs20070401
pex-unix.c
Go to the documentation of this file.
00001 /* Utilities to execute a program in a subprocess (possibly linked by pipes
00002    with other subprocesses), and wait for it.  Generic Unix version
00003    (also used for UWIN and VMS).
00004    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
00005    Free Software Foundation, Inc.
00006 
00007 This file is part of the libiberty library.
00008 Libiberty is free software; you can redistribute it and/or
00009 modify it under the terms of the GNU Library General Public
00010 License as published by the Free Software Foundation; either
00011 version 2 of the License, or (at your option) any later version.
00012 
00013 Libiberty is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 Library General Public License for more details.
00017 
00018 You should have received a copy of the GNU Library General Public
00019 License along with libiberty; see the file COPYING.LIB.  If not,
00020 write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00021 Boston, MA 02110-1301, USA.  */
00022 
00023 #include "config.h"
00024 #include "libiberty.h"
00025 #include "pex-common.h"
00026 
00027 #include <stdio.h>
00028 #include <signal.h>
00029 #include <errno.h>
00030 #ifdef NEED_DECLARATION_ERRNO
00031 extern int errno;
00032 #endif
00033 #ifdef HAVE_STDLIB_H
00034 #include <stdlib.h>
00035 #endif
00036 #ifdef HAVE_STRING_H
00037 #include <string.h>
00038 #endif
00039 #ifdef HAVE_UNISTD_H
00040 #include <unistd.h>
00041 #endif
00042 
00043 #include <sys/types.h>
00044 
00045 #ifdef HAVE_FCNTL_H
00046 #include <fcntl.h>
00047 #endif
00048 #ifdef HAVE_SYS_WAIT_H
00049 #include <sys/wait.h>
00050 #endif
00051 #ifdef HAVE_GETRUSAGE
00052 #include <sys/time.h>
00053 #include <sys/resource.h>
00054 #endif
00055 #ifdef HAVE_SYS_STAT_H
00056 #include <sys/stat.h>
00057 #endif
00058 
00059 
00060 #ifdef vfork /* Autoconf may define this to fork for us. */
00061 # define VFORK_STRING "fork"
00062 #else
00063 # define VFORK_STRING "vfork"
00064 #endif
00065 #ifdef HAVE_VFORK_H
00066 #include <vfork.h>
00067 #endif
00068 #ifdef VMS
00069 #define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \
00070                lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1)
00071 #endif /* VMS */
00072 
00073 
00074 /* File mode to use for private and world-readable files.  */
00075 
00076 #if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH)
00077 #define PUBLIC_MODE  \
00078     (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
00079 #else
00080 #define PUBLIC_MODE 0666
00081 #endif
00082 
00083 /* Get the exit status of a particular process, and optionally get the
00084    time that it took.  This is simple if we have wait4, slightly
00085    harder if we have waitpid, and is a pain if we only have wait.  */
00086 
00087 static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *);
00088 
00089 #ifdef HAVE_WAIT4
00090 
00091 static pid_t
00092 pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
00093          struct pex_time *time)
00094 {
00095   pid_t ret;
00096   struct rusage r;
00097 
00098 #ifdef HAVE_WAITPID
00099   if (time == NULL)
00100     return waitpid (pid, status, 0);
00101 #endif
00102 
00103   ret = wait4 (pid, status, 0, &r);
00104 
00105   if (time != NULL)
00106     {
00107       time->user_seconds = r.ru_utime.tv_sec;
00108       time->user_microseconds= r.ru_utime.tv_usec;
00109       time->system_seconds = r.ru_stime.tv_sec;
00110       time->system_microseconds= r.ru_stime.tv_usec;
00111     }
00112 
00113   return ret;
00114 }
00115 
00116 #else /* ! defined (HAVE_WAIT4) */
00117 
00118 #ifdef HAVE_WAITPID
00119 
00120 #ifndef HAVE_GETRUSAGE
00121 
00122 static pid_t
00123 pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
00124          struct pex_time *time)
00125 {
00126   if (time != NULL)
00127     memset (time, 0, sizeof (struct pex_time));
00128   return waitpid (pid, status, 0);
00129 }
00130 
00131 #else /* defined (HAVE_GETRUSAGE) */
00132 
00133 static pid_t
00134 pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
00135          struct pex_time *time)
00136 {
00137   struct rusage r1, r2;
00138   pid_t ret;
00139 
00140   if (time == NULL)
00141     return waitpid (pid, status, 0);
00142 
00143   getrusage (RUSAGE_CHILDREN, &r1);
00144 
00145   ret = waitpid (pid, status, 0);
00146   if (ret < 0)
00147     return ret;
00148 
00149   getrusage (RUSAGE_CHILDREN, &r2);
00150 
00151   time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
00152   time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
00153   if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec)
00154     {
00155       --time->user_seconds;
00156       time->user_microseconds += 1000000;
00157     }
00158 
00159   time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
00160   time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
00161   if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec)
00162     {
00163       --time->system_seconds;
00164       time->system_microseconds += 1000000;
00165     }
00166 
00167   return ret;
00168 }
00169 
00170 #endif /* defined (HAVE_GETRUSAGE) */
00171 
00172 #else /* ! defined (HAVE_WAITPID) */
00173 
00174 struct status_list
00175 {
00176   struct status_list *next;
00177   pid_t pid;
00178   int status;
00179   struct pex_time time;
00180 };
00181 
00182 static pid_t
00183 pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time)
00184 {
00185   struct status_list **pp;
00186 
00187   for (pp = (struct status_list **) &obj->sysdep;
00188        *pp != NULL;
00189        pp = &(*pp)->next)
00190     {
00191       if ((*pp)->pid == pid)
00192        {
00193          struct status_list *p;
00194 
00195          p = *pp;
00196          *status = p->status;
00197          if (time != NULL)
00198            *time = p->time;
00199          *pp = p->next;
00200          free (p);
00201          return pid;
00202        }
00203     }
00204 
00205   while (1)
00206     {
00207       pid_t cpid;
00208       struct status_list *psl;
00209       struct pex_time pt;
00210 #ifdef HAVE_GETRUSAGE
00211       struct rusage r1, r2;
00212 #endif
00213 
00214       if (time != NULL)
00215        {
00216 #ifdef HAVE_GETRUSAGE
00217          getrusage (RUSAGE_CHILDREN, &r1);
00218 #else
00219          memset (&pt, 0, sizeof (struct pex_time));
00220 #endif
00221        }
00222 
00223       cpid = wait (status);
00224 
00225 #ifdef HAVE_GETRUSAGE
00226       if (time != NULL && cpid >= 0)
00227        {
00228          getrusage (RUSAGE_CHILDREN, &r2);
00229 
00230          pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
00231          pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
00232          if (pt.user_microseconds < 0)
00233            {
00234              --pt.user_seconds;
00235              pt.user_microseconds += 1000000;
00236            }
00237 
00238          pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
00239          pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
00240          if (pt.system_microseconds < 0)
00241            {
00242              --pt.system_seconds;
00243              pt.system_microseconds += 1000000;
00244            }
00245        }
00246 #endif
00247 
00248       if (cpid < 0 || cpid == pid)
00249        {
00250          if (time != NULL)
00251            *time = pt;
00252          return cpid;
00253        }
00254 
00255       psl = XNEW (struct status_list);
00256       psl->pid = cpid;
00257       psl->status = *status;
00258       if (time != NULL)
00259        psl->time = pt;
00260       psl->next = (struct status_list *) obj->sysdep;
00261       obj->sysdep = (void *) psl;
00262     }
00263 }
00264 
00265 #endif /* ! defined (HAVE_WAITPID) */
00266 #endif /* ! defined (HAVE_WAIT4) */
00267 
00268 static void pex_child_error (struct pex_obj *, const char *, const char *, int)
00269      ATTRIBUTE_NORETURN;
00270 static int pex_unix_open_read (struct pex_obj *, const char *, int);
00271 static int pex_unix_open_write (struct pex_obj *, const char *, int);
00272 static long pex_unix_exec_child (struct pex_obj *, int, const char *,
00273                              char * const *, char * const *,
00274                              int, int, int, int,
00275                              const char **, int *);
00276 static int pex_unix_close (struct pex_obj *, int);
00277 static int pex_unix_wait (struct pex_obj *, long, int *, struct pex_time *,
00278                        int, const char **, int *);
00279 static int pex_unix_pipe (struct pex_obj *, int *, int);
00280 static FILE *pex_unix_fdopenr (struct pex_obj *, int, int);
00281 static FILE *pex_unix_fdopenw (struct pex_obj *, int, int);
00282 static void pex_unix_cleanup (struct pex_obj *);
00283 
00284 /* The list of functions we pass to the common routines.  */
00285 
00286 const struct pex_funcs funcs =
00287 {
00288   pex_unix_open_read,
00289   pex_unix_open_write,
00290   pex_unix_exec_child,
00291   pex_unix_close,
00292   pex_unix_wait,
00293   pex_unix_pipe,
00294   pex_unix_fdopenr,
00295   pex_unix_fdopenw,
00296   pex_unix_cleanup
00297 };
00298 
00299 /* Return a newly initialized pex_obj structure.  */
00300 
00301 struct pex_obj *
00302 pex_init (int flags, const char *pname, const char *tempbase)
00303 {
00304   return pex_init_common (flags, pname, tempbase, &funcs);
00305 }
00306 
00307 /* Open a file for reading.  */
00308 
00309 static int
00310 pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
00311                   int binary ATTRIBUTE_UNUSED)
00312 {
00313   return open (name, O_RDONLY);
00314 }
00315 
00316 /* Open a file for writing.  */
00317 
00318 static int
00319 pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
00320                    int binary ATTRIBUTE_UNUSED)
00321 {
00322   /* Note that we can't use O_EXCL here because gcc may have already
00323      created the temporary file via make_temp_file.  */
00324   return open (name, O_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE);
00325 }
00326 
00327 /* Close a file.  */
00328 
00329 static int
00330 pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
00331 {
00332   return close (fd);
00333 }
00334 
00335 /* Report an error from a child process.  We don't use stdio routines,
00336    because we might be here due to a vfork call.  */
00337 
00338 static void
00339 pex_child_error (struct pex_obj *obj, const char *executable,
00340                const char *errmsg, int err)
00341 {
00342 #define writeerr(s) (void) write (STDERR_FILE_NO, s, strlen (s))
00343   writeerr (obj->pname);
00344   writeerr (": error trying to exec '");
00345   writeerr (executable);
00346   writeerr ("': ");
00347   writeerr (errmsg);
00348   writeerr (": ");
00349   writeerr (xstrerror (err));
00350   writeerr ("\n");
00351   _exit (-1);
00352 }
00353 
00354 /* Execute a child.  */
00355 
00356 extern char **environ;
00357 
00358 static long
00359 pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
00360                    char * const * argv, char * const * env,
00361                      int in, int out, int errdes,
00362                    int toclose, const char **errmsg, int *err)
00363 {
00364   pid_t pid;
00365 
00366   /* We declare these to be volatile to avoid warnings from gcc about
00367      them being clobbered by vfork.  */
00368   volatile int sleep_interval;
00369   volatile int retries;
00370 
00371   sleep_interval = 1;
00372   pid = -1;
00373   for (retries = 0; retries < 4; ++retries)
00374     {
00375       pid = vfork ();
00376       if (pid >= 0)
00377        break;
00378       sleep (sleep_interval);
00379       sleep_interval *= 2;
00380     }
00381 
00382   switch (pid)
00383     {
00384     case -1:
00385       *err = errno;
00386       *errmsg = VFORK_STRING;
00387       return -1;
00388 
00389     case 0:
00390       /* Child process.  */
00391       if (in != STDIN_FILE_NO)
00392        {
00393          if (dup2 (in, STDIN_FILE_NO) < 0)
00394            pex_child_error (obj, executable, "dup2", errno);
00395          if (close (in) < 0)
00396            pex_child_error (obj, executable, "close", errno);
00397        }
00398       if (out != STDOUT_FILE_NO)
00399        {
00400          if (dup2 (out, STDOUT_FILE_NO) < 0)
00401            pex_child_error (obj, executable, "dup2", errno);
00402          if (close (out) < 0)
00403            pex_child_error (obj, executable, "close", errno);
00404        }
00405       if (errdes != STDERR_FILE_NO)
00406        {
00407          if (dup2 (errdes, STDERR_FILE_NO) < 0)
00408            pex_child_error (obj, executable, "dup2", errno);
00409          if (close (errdes) < 0)
00410            pex_child_error (obj, executable, "close", errno);
00411        }
00412       if (toclose >= 0)
00413        {
00414          if (close (toclose) < 0)
00415            pex_child_error (obj, executable, "close", errno);
00416        }
00417       if ((flags & PEX_STDERR_TO_STDOUT) != 0)
00418        {
00419          if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
00420            pex_child_error (obj, executable, "dup2", errno);
00421        }
00422 
00423       if (env)
00424         environ = (char**) env;
00425 
00426       if ((flags & PEX_SEARCH) != 0)
00427        {
00428          execvp (executable, argv);
00429          pex_child_error (obj, executable, "execvp", errno);
00430        }
00431       else
00432        {
00433          execv (executable, argv);
00434          pex_child_error (obj, executable, "execv", errno);
00435        }
00436 
00437       /* NOTREACHED */
00438       return -1;
00439 
00440     default:
00441       /* Parent process.  */
00442       if (in != STDIN_FILE_NO)
00443        {
00444          if (close (in) < 0)
00445            {
00446              *err = errno;
00447              *errmsg = "close";
00448              return -1;
00449            }
00450        }
00451       if (out != STDOUT_FILE_NO)
00452        {
00453          if (close (out) < 0)
00454            {
00455              *err = errno;
00456              *errmsg = "close";
00457              return -1;
00458            }
00459        }
00460       if (errdes != STDERR_FILE_NO)
00461        {
00462          if (close (errdes) < 0)
00463            {
00464              *err = errno;
00465              *errmsg = "close";
00466              return -1;
00467            }
00468        }
00469 
00470       return (long) pid;
00471     }
00472 }
00473 
00474 /* Wait for a child process to complete.  */
00475 
00476 static int
00477 pex_unix_wait (struct pex_obj *obj, long pid, int *status,
00478               struct pex_time *time, int done, const char **errmsg,
00479               int *err)
00480 {
00481   /* If we are cleaning up when the caller didn't retrieve process
00482      status for some reason, encourage the process to go away.  */
00483   if (done)
00484     kill (pid, SIGTERM);
00485 
00486   if (pex_wait (obj, pid, status, time) < 0)
00487     {
00488       *err = errno;
00489       *errmsg = "wait";
00490       return -1;
00491     }
00492 
00493   return 0;
00494 }
00495 
00496 /* Create a pipe.  */
00497 
00498 static int
00499 pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
00500               int binary ATTRIBUTE_UNUSED)
00501 {
00502   return pipe (p);
00503 }
00504 
00505 /* Get a FILE pointer to read from a file descriptor.  */
00506 
00507 static FILE *
00508 pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
00509                 int binary ATTRIBUTE_UNUSED)
00510 {
00511   return fdopen (fd, "r");
00512 }
00513 
00514 static FILE *
00515 pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
00516                 int binary ATTRIBUTE_UNUSED)
00517 {
00518   if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
00519     return NULL;
00520   return fdopen (fd, "w");
00521 }
00522 
00523 static void
00524 pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED)
00525 {
00526 #if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID)
00527   while (obj->sysdep != NULL)
00528     {
00529       struct status_list *this;
00530       struct status_list *next;
00531 
00532       this = (struct status_list *) obj->sysdep;
00533       next = this->next;
00534       free (this);
00535       obj->sysdep = (void *) next;
00536     }
00537 #endif
00538 }