diff libiberty/pex-unix.c @ 55:77e2b8dfacca gcc-4.4.5

update it from 4.4.3 to 4.5.0
author ryoma <e075725@ie.u-ryukyu.ac.jp>
date Fri, 12 Feb 2010 23:39:51 +0900
parents a06113de4d67
children f6334be47118
line wrap: on
line diff
--- a/libiberty/pex-unix.c	Sun Feb 07 18:28:00 2010 +0900
+++ b/libiberty/pex-unix.c	Fri Feb 12 23:39:51 2010 +0900
@@ -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, 2004, 2005
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2009
    Free Software Foundation, Inc.
 
 This file is part of the libiberty library.
@@ -65,11 +65,40 @@
 #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 */
+#if defined(VMS) && defined (__LONG_POINTERS)
+#ifndef __CHAR_PTR32
+typedef char * __char_ptr32
+__attribute__ ((mode (SI)));
+#endif
+
+typedef __char_ptr32 *__char_ptr_char_ptr32
+__attribute__ ((mode (SI)));
+
+/* Return a 32 bit pointer to an array of 32 bit pointers 
+   given a 64 bit pointer to an array of 64 bit pointers.  */
 
+static __char_ptr_char_ptr32
+to_ptr32 (char **ptr64)
+{
+  int argc;
+  __char_ptr_char_ptr32 short_argv;
+
+  for (argc=0; ptr64[argc]; argc++);
+
+  /* Reallocate argv with 32 bit pointers.  */
+  short_argv = (__char_ptr_char_ptr32) decc$malloc
+    (sizeof (__char_ptr32) * (argc + 1));
+
+  for (argc=0; ptr64[argc]; argc++)
+    short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
+
+  short_argv[argc] = (__char_ptr32) 0;
+  return short_argv;
+
+}
+#else
+#define to_ptr32(argv) argv
+#endif
 
 /* File mode to use for private and world-readable files.  */
 
@@ -339,7 +368,8 @@
 pex_child_error (struct pex_obj *obj, const char *executable,
 		 const char *errmsg, int err)
 {
-#define writeerr(s) (void) write (STDERR_FILE_NO, s, strlen (s))
+  int retval = 0;
+#define writeerr(s) retval |= (write (STDERR_FILE_NO, s, strlen (s)) < 0)
   writeerr (obj->pname);
   writeerr (": error trying to exec '");
   writeerr (executable);
@@ -348,7 +378,9 @@
   writeerr (": ");
   writeerr (xstrerror (err));
   writeerr ("\n");
-  _exit (-1);
+#undef writeerr
+  /* Exit with -2 if the error output failed, too.  */
+  _exit (retval == 0 ? -1 : -2);
 }
 
 /* Execute a child.  */
@@ -368,6 +400,12 @@
   volatile int sleep_interval;
   volatile int retries;
 
+  /* We vfork and then set environ in the child before calling execvp.
+     This clobbers the parent's environ so we need to restore it.
+     It would be nice to use one of the exec* functions that takes an
+     environment as a parameter, but that may have portability issues.  */
+  char **save_environ = environ;
+
   sleep_interval = 1;
   pid = -1;
   for (retries = 0; retries < 4; ++retries)
@@ -421,16 +459,21 @@
 	}
 
       if (env)
-        environ = (char**) env;
+	{
+	  /* NOTE: In a standard vfork implementation this clobbers the
+	     parent's copy of environ "too" (in reality there's only one copy).
+	     This is ok as we restore it below.  */
+	  environ = (char**) env;
+	}
 
       if ((flags & PEX_SEARCH) != 0)
 	{
-	  execvp (executable, argv);
+	  execvp (executable, to_ptr32 (argv));
 	  pex_child_error (obj, executable, "execvp", errno);
 	}
       else
 	{
-	  execv (executable, argv);
+	  execv (executable, to_ptr32 (argv));
 	  pex_child_error (obj, executable, "execv", errno);
 	}
 
@@ -439,6 +482,14 @@
 
     default:
       /* Parent process.  */
+
+      /* Restore environ.
+	 Note that the parent either doesn't run until the child execs/exits
+	 (standard vfork behaviour), or if it does run then vfork is behaving
+	 more like fork.  In either case we needn't worry about clobbering
+	 the child's copy of environ.  */
+      environ = save_environ;
+
       if (in != STDIN_FILE_NO)
 	{
 	  if (close (in) < 0)