merge from gcc
authorDJ Delorie <dj@redhat.com>
Thu, 18 Mar 2004 04:07:41 +0000 (04:07 +0000)
committerDJ Delorie <dj@redhat.com>
Thu, 18 Mar 2004 04:07:41 +0000 (04:07 +0000)
libiberty/ChangeLog
libiberty/pex-common.h
libiberty/pex-unix.c

index 95cc22262ca18dea5e657c1c27c2c6aded818cc4..2dce4d82d0243736a66c0cf454fcaeaa20af986f 100644 (file)
@@ -1,5 +1,9 @@
 2004-03-17  Ian Lance Taylor  <ian@wasabisystems.com>
 
+       * pex-unix.c (pexecute): Use vfork instead of fork, with
+       appropriate changes to make this safe.
+       * pex-common.h (STDERR_FILE_NO): Define.
+
        * Makefile.in: Clean up REQUIRED_OFILES and CONFIGURED_OFILES for
        an 80 column screen.  Run maint-deps.
 
index da2f71e1247aa1bf5f0fbc013033678c7d7c2e75..df3c0f6519c3329de93ed071623c201c1e6ae18b 100644 (file)
@@ -1,6 +1,6 @@
 /* Utilities to execute a program in a subprocess (possibly linked by pipes
    with other subprocesses), and wait for it.  Shared logic.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
    Free Software Foundation, Inc.
 
 This file is part of the libiberty library.
@@ -33,6 +33,9 @@ Boston, MA 02111-1307, USA.  */
 /* stdout file number.  */
 #define STDOUT_FILE_NO 1
 
+/* stderr file number.  */
+#define STDERR_FILE_NO 2
+
 /* value of `pipe': port index for reading.  */
 #define READ_PORT 0
 
index 14fe71ed09c0f1e46bcb93e6df3e80eb3ed3e00c..ddbed8f4a05cf175c4e2fbb9bf134f9a71e6cb15 100644 (file)
@@ -1,7 +1,7 @@
 /* Utilities to execute a program in a subprocess (possibly linked by pipes
    with other subprocesses), and wait for it.  Generic Unix version
    (also used for UWIN and VMS).
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
    Free Software Foundation, Inc.
 
 This file is part of the libiberty library.
@@ -44,28 +44,66 @@ extern int errno;
 #define waitpid(pid, status, flags) wait(status)
 #endif
 
-extern int execv ();
-extern int execvp ();
+#ifdef vfork /* Autoconf may define this to fork for us. */
+# define VFORK_STRING "fork"
+#else
+# define VFORK_STRING "vfork"
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+#ifdef VMS
+#define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \
+               lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1)
+#endif /* VMS */
+
+/* Execute a program, possibly setting up pipes to programs executed
+   via other calls to this function.
+
+   This version of the function uses vfork.  In general vfork is
+   similar to setjmp/longmp, in that any variable which is modified by
+   the child process has an indeterminate value in the parent process.
+   We follow a safe approach here by not modifying any variables at
+   all in the child process (with the possible exception of variables
+   modified by xstrerror if exec fails, but this is unlikely to be
+   detectable).
+
+   We work a little bit harder to avoid gcc warnings.  gcc will warn
+   about any automatic variable which is live at the time of the
+   vfork, which is non-volatile, and which is either set more than
+   once or is an argument to the function.  This warning isn't quite
+   right, since what we really care about is whether the variable is
+   live at the time of the vfork and set afterward by the child
+   process, but gcc only checks whether the variable is set more than
+   once.  To avoid this warning, we ensure that any variable which is
+   live at the time of the vfork (i.e., used after the vfork) is set
+   exactly once and is not an argument, or is marked volatile.  */
 
 int
-pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
+pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg,
+         flagsarg)
      const char *program;
      char * const *argv;
      const char *this_pname;
      const char *temp_base ATTRIBUTE_UNUSED;
      char **errmsg_fmt, **errmsg_arg;
-     int flags;
+     int flagsarg;
 {
-  int (*func)() = (flags & PEXECUTE_SEARCH ? execvp : execv);
   int pid;
   int pdes[2];
+  int out;
   int input_desc, output_desc;
-  int retries, sleep_interval;
+  int flags;
+  /* We declare these to be volatile to avoid warnings from gcc about
+     them being clobbered by vfork.  */
+  volatile int retries, sleep_interval;
   /* Pipe waiting from last process, to be used as input for the next one.
      Value is STDIN_FILE_NO if no pipe is waiting
      (i.e. the next command is the first of a group).  */
   static int last_pipe_input;
 
+  flags = flagsarg;
+
   /* If this is the first process, initialize.  */
   if (flags & PEXECUTE_FIRST)
     last_pipe_input = STDIN_FILE_NO;
@@ -82,22 +120,24 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
          *errmsg_arg = NULL;
          return -1;
        }
-      output_desc = pdes[WRITE_PORT];
+      out = pdes[WRITE_PORT];
       last_pipe_input = pdes[READ_PORT];
     }
   else
     {
       /* Last process.  */
-      output_desc = STDOUT_FILE_NO;
+      out = STDOUT_FILE_NO;
       last_pipe_input = STDIN_FILE_NO;
     }
 
+  output_desc = out;
+
   /* Fork a subprocess; wait and retry if it fails.  */
   sleep_interval = 1;
   pid = -1;
   for (retries = 0; retries < 4; retries++)
     {
-      pid = fork ();
+      pid = vfork ();
       if (pid >= 0)
        break;
       sleep (sleep_interval);
@@ -131,12 +171,21 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
        close (last_pipe_input);
 
       /* Exec the program.  */
-      (*func) (program, argv);
-
-      fprintf (stderr, "%s: ", this_pname);
-      fprintf (stderr, install_error_msg, program);
-      fprintf (stderr, ": %s\n", xstrerror (errno));
-      exit (-1);
+      if (flags & PEXECUTE_SEARCH)
+       execvp (program, argv);
+      else
+       execv (program, argv);
+
+      /* We don't want to call fprintf after vfork.  */
+#define writeerr(s) write (STDERR_FILE_NO, s, strlen (s))
+      writeerr (this_pname);
+      writeerr (": ");
+      writeerr ("installation problem, cannot exec '");
+      writeerr (program);
+      writeerr ("': ");
+      writeerr (xstrerror (errno));
+      writeerr ("\n");
+      _exit (-1);
       /* NOTREACHED */
       return 0;