| Index: gcc/libiberty/pex-unix.c
|
| diff --git a/gcc/libiberty/pex-unix.c b/gcc/libiberty/pex-unix.c
|
| index 366e96ef8d23243234f0b47793642b45d2850c11..85733a669232975b4e333a27044da0eb64add0f8 100644
|
| --- a/gcc/libiberty/pex-unix.c
|
| +++ b/gcc/libiberty/pex-unix.c
|
| @@ -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 @@ extern int errno;
|
| #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 @@ static void
|
| 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 @@ pex_child_error (struct pex_obj *obj, const char *executable,
|
| 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 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
| 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 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
| }
|
|
|
| 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 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
|
|
|
| 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)
|
|
|