X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=libiberty%2Fpex-unix.c;h=85733a669232975b4e333a27044da0eb64add0f8;hb=a192ba05083cb72a218e7c7722f30eadb9973833;hp=baf2bb4995be60b835eaf2fc057c794c86f2293b;hpb=9fef968a22987b67182642f1a1bf70aaaab7a6b2;p=deliverable%2Fbinutils-gdb.git diff --git a/libiberty/pex-unix.c b/libiberty/pex-unix.c index baf2bb4995..85733a6692 100644 --- a/libiberty/pex-unix.c +++ b/libiberty/pex-unix.c @@ -368,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); @@ -377,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. */ @@ -397,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) @@ -450,7 +459,12 @@ 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) { @@ -468,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)