X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libiberty%2Fpex-unix.c;h=85733a669232975b4e333a27044da0eb64add0f8;hb=73834184cbf71b93df7eb27e02aa176e07d480f3;hp=e006e5992978b67591ff990c07ba57e15dad0f63;hpb=ee2abea27f8239583e8e271e253609083a37e3c4;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libiberty/pex-unix.c b/libiberty/pex-unix.c index e006e599297..85733a66923 100644 --- a/libiberty/pex-unix.c +++ b/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 #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. */ @@ -269,11 +298,12 @@ static void pex_child_error (struct pex_obj *, const char *, const char *, int) ATTRIBUTE_NORETURN; static int pex_unix_open_read (struct pex_obj *, const char *, int); static int pex_unix_open_write (struct pex_obj *, const char *, int); -static long pex_unix_exec_child (struct pex_obj *, int, const char *, +static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *, char * const *, char * const *, - int, int, int, const char **, int *); + int, int, int, int, + const char **, int *); static int pex_unix_close (struct pex_obj *, int); -static int pex_unix_wait (struct pex_obj *, long, int *, struct pex_time *, +static int pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *, int, const char **, int *); static int pex_unix_pipe (struct pex_obj *, int *, int); static FILE *pex_unix_fdopenr (struct pex_obj *, int, int); @@ -338,7 +368,8 @@ static void pex_child_error (struct pex_obj *obj, const char *executable, const char *errmsg, int err) { -#define writeerr(s) 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); @@ -347,18 +378,20 @@ 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. */ extern char **environ; -static long +static pid_t pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, char * const * argv, char * const * env, int in, int out, int errdes, - const char **errmsg, int *err) + int toclose, const char **errmsg, int *err) { pid_t pid; @@ -367,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) @@ -383,7 +422,7 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, case -1: *err = errno; *errmsg = VFORK_STRING; - return -1; + return (pid_t) -1; case 0: /* Child process. */ @@ -408,6 +447,11 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, if (close (errdes) < 0) pex_child_error (obj, executable, "close", errno); } + if (toclose >= 0) + { + if (close (toclose) < 0) + pex_child_error (obj, executable, "close", errno); + } if ((flags & PEX_STDERR_TO_STDOUT) != 0) { if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0) @@ -415,31 +459,44 @@ 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); } /* NOTREACHED */ - return -1; + return (pid_t) -1; 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) { *err = errno; *errmsg = "close"; - return -1; + return (pid_t) -1; } } if (out != STDOUT_FILE_NO) @@ -448,7 +505,7 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, { *err = errno; *errmsg = "close"; - return -1; + return (pid_t) -1; } } if (errdes != STDERR_FILE_NO) @@ -457,18 +514,18 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, { *err = errno; *errmsg = "close"; - return -1; + return (pid_t) -1; } } - return (long) pid; + return pid; } } /* Wait for a child process to complete. */ static int -pex_unix_wait (struct pex_obj *obj, long pid, int *status, +pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time, int done, const char **errmsg, int *err) {