X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=libiberty%2Fpex-unix.c;h=0715115747826d510a960ae772cccc052012ee5a;hb=5ecffcbbd49639b83e574a0411f8a3088093f4aa;hp=85733a669232975b4e333a27044da0eb64add0f8;hpb=16b8170d502e4d6339d466b51ee0d64ee35a1d2b;p=platform%2Fupstream%2Fbinutils.git diff --git a/libiberty/pex-unix.c b/libiberty/pex-unix.c index 85733a6..0715115 100644 --- a/libiberty/pex-unix.c +++ b/libiberty/pex-unix.c @@ -1,8 +1,8 @@ /* 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, 2009 - Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2009, + 2010 Free Software Foundation, Inc. This file is part of the libiberty library. Libiberty is free software; you can redistribute it and/or @@ -55,7 +55,9 @@ extern int errno; #ifdef HAVE_SYS_STAT_H #include #endif - +#ifdef HAVE_PROCESS_H +#include +#endif #ifdef vfork /* Autoconf may define this to fork for us. */ # define VFORK_STRING "fork" @@ -83,13 +85,15 @@ to_ptr32 (char **ptr64) int argc; __char_ptr_char_ptr32 short_argv; - for (argc=0; ptr64[argc]; argc++); + /* Count number of arguments. */ + for (argc = 0; ptr64[argc] != NULL; 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++) + for (argc = 0; ptr64[argc] != NULL; argc++) short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]); short_argv[argc] = (__char_ptr32) 0; @@ -297,7 +301,7 @@ pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time) 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 int pex_unix_open_write (struct pex_obj *, const char *, int, int); static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *, char * const *, char * const *, int, int, int, int, @@ -346,11 +350,12 @@ pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, static int pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, - int binary ATTRIBUTE_UNUSED) + int binary ATTRIBUTE_UNUSED, int append) { /* Note that we can't use O_EXCL here because gcc may have already created the temporary file via make_temp_file. */ - return open (name, O_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE); + return open (name, O_WRONLY | O_CREAT + | (append ? O_APPEND : O_TRUNC), PUBLIC_MODE); } /* Close a file. */ @@ -387,6 +392,202 @@ pex_child_error (struct pex_obj *obj, const char *executable, extern char **environ; +#if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE) +/* Implementation of pex->exec_child using the Cygwin spawn operation. */ + +/* Subroutine of pex_unix_exec_child. Move OLD_FD to a new file descriptor + to be stored in *PNEW_FD, save the flags in *PFLAGS, and arrange for the + saved copy to be close-on-exec. Move CHILD_FD into OLD_FD. If CHILD_FD + is -1, OLD_FD is to be closed. Return -1 on error. */ + +static int +save_and_install_fd(int *pnew_fd, int *pflags, int old_fd, int child_fd) +{ + int new_fd, flags; + + flags = fcntl (old_fd, F_GETFD); + + /* If we could not retrieve the flags, then OLD_FD was not open. */ + if (flags < 0) + { + new_fd = -1, flags = 0; + if (child_fd >= 0 && dup2 (child_fd, old_fd) < 0) + return -1; + } + /* If we wish to close OLD_FD, just mark it CLOEXEC. */ + else if (child_fd == -1) + { + new_fd = old_fd; + if ((flags & FD_CLOEXEC) == 0 && fcntl (old_fd, F_SETFD, FD_CLOEXEC) < 0) + return -1; + } + /* Otherwise we need to save a copy of OLD_FD before installing CHILD_FD. */ + else + { +#ifdef F_DUPFD_CLOEXEC + new_fd = fcntl (old_fd, F_DUPFD_CLOEXEC, 3); + if (new_fd < 0) + return -1; +#else + /* Prefer F_DUPFD over dup in order to avoid getting a new fd + in the range 0-2, right where a new stderr fd might get put. */ + new_fd = fcntl (old_fd, F_DUPFD, 3); + if (new_fd < 0) + return -1; + if (fcntl (new_fd, F_SETFD, FD_CLOEXEC) < 0) + return -1; +#endif + if (dup2 (child_fd, old_fd) < 0) + return -1; + } + + *pflags = flags; + if (pnew_fd) + *pnew_fd = new_fd; + else if (new_fd != old_fd) + abort (); + + return 0; +} + +/* Subroutine of pex_unix_exec_child. Move SAVE_FD back to OLD_FD + restoring FLAGS. If SAVE_FD < 0, OLD_FD is to be closed. */ + +static int +restore_fd(int old_fd, int save_fd, int flags) +{ + /* For SAVE_FD < 0, all we have to do is restore the + "closed-ness" of the original. */ + if (save_fd < 0) + return close (old_fd); + + /* For SAVE_FD == OLD_FD, all we have to do is restore the + original setting of the CLOEXEC flag. */ + if (save_fd == old_fd) + { + if (flags & FD_CLOEXEC) + return 0; + return fcntl (old_fd, F_SETFD, flags); + } + + /* Otherwise we have to move the descriptor back, restore the flags, + and close the saved copy. */ +#ifdef HAVE_DUP3 + if (flags == FD_CLOEXEC) + { + if (dup3 (save_fd, old_fd, O_CLOEXEC) < 0) + return -1; + } + else +#endif + { + if (dup2 (save_fd, old_fd) < 0) + return -1; + if (flags != 0 && fcntl (old_fd, F_SETFD, flags) < 0) + return -1; + } + return close (save_fd); +} + +static pid_t +pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, + int flags, const char *executable, + char * const * argv, char * const * env, + int in, int out, int errdes, int toclose, + const char **errmsg, int *err) +{ + int fl_in = 0, fl_out = 0, fl_err = 0, fl_tc = 0; + int save_in = -1, save_out = -1, save_err = -1; + int max, retries; + pid_t pid; + + if (flags & PEX_STDERR_TO_STDOUT) + errdes = out; + + /* We need the three standard file descriptors to be set up as for + the child before we perform the spawn. The file descriptors for + the parent need to be moved and marked for close-on-exec. */ + if (in != STDIN_FILE_NO + && save_and_install_fd (&save_in, &fl_in, STDIN_FILE_NO, in) < 0) + goto error_dup2; + if (out != STDOUT_FILE_NO + && save_and_install_fd (&save_out, &fl_out, STDOUT_FILE_NO, out) < 0) + goto error_dup2; + if (errdes != STDERR_FILE_NO + && save_and_install_fd (&save_err, &fl_err, STDERR_FILE_NO, errdes) < 0) + goto error_dup2; + if (toclose >= 0 + && save_and_install_fd (NULL, &fl_tc, toclose, -1) < 0) + goto error_dup2; + + /* Now that we've moved the file descriptors for the child into place, + close the originals. Be careful not to close any of the standard + file descriptors that we just set up. */ + max = -1; + if (errdes >= 0) + max = STDERR_FILE_NO; + else if (out >= 0) + max = STDOUT_FILE_NO; + else if (in >= 0) + max = STDIN_FILE_NO; + if (in > max) + close (in); + if (out > max) + close (out); + if (errdes > max && errdes != out) + close (errdes); + + /* If we were not given an environment, use the global environment. */ + if (env == NULL) + env = environ; + + /* Launch the program. If we get EAGAIN (normally out of pid's), try + again a few times with increasing backoff times. */ + retries = 0; + while (1) + { + typedef const char * const *cc_cp; + + if (flags & PEX_SEARCH) + pid = spawnvpe (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env); + else + pid = spawnve (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env); + + if (pid > 0) + break; + + *err = errno; + *errmsg = "spawn"; + if (errno != EAGAIN || ++retries == 4) + return (pid_t) -1; + sleep (1 << retries); + } + + /* Success. Restore the parent's file descriptors that we saved above. */ + if (toclose >= 0 + && restore_fd (toclose, toclose, fl_tc) < 0) + goto error_dup2; + if (in != STDIN_FILE_NO + && restore_fd (STDIN_FILE_NO, save_in, fl_in) < 0) + goto error_dup2; + if (out != STDOUT_FILE_NO + && restore_fd (STDOUT_FILE_NO, save_out, fl_out) < 0) + goto error_dup2; + if (errdes != STDERR_FILE_NO + && restore_fd (STDERR_FILE_NO, save_err, fl_err) < 0) + goto error_dup2; + + return pid; + + error_dup2: + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; +} + +#else +/* Implementation of pex->exec_child using standard vfork + exec. */ + static pid_t pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, char * const * argv, char * const * env, @@ -521,6 +722,7 @@ pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, return pid; } } +#endif /* SPAWN */ /* Wait for a child process to complete. */