X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fpipe.c;h=1c81d14523c6a41f61d65f6075d1d40426b7c04f;hb=fa8d786628cd8a1dbd2194e7776bea07f97cca99;hp=521872be6d8c1ca516daf196ae1b5116bbb6b1b6;hpb=854ebf64dc7dae95a43a4e139e075156d2add805;p=gnulib.git diff --git a/lib/pipe.c b/lib/pipe.c index 521872be6..1c81d1452 100644 --- a/lib/pipe.c +++ b/lib/pipe.c @@ -1,11 +1,11 @@ /* Creation of subprocesses, communicating via pipes. - Copyright (C) 2001-2004, 2006 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2010 Free Software Foundation, Inc. Written by Bruno Haible , 2001. - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,8 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include @@ -29,14 +28,14 @@ #include #include "error.h" -#include "exit.h" #include "fatal-signal.h" +#include "unistd-safer.h" #include "wait-process.h" #include "gettext.h" #define _(str) gettext (str) -#if defined _MSC_VER || defined __MINGW32__ +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ /* Native Woe32 API. */ # include @@ -45,30 +44,10 @@ #else /* Unix API. */ -# ifdef HAVE_POSIX_SPAWN -# include -# else -# ifdef HAVE_VFORK_H -# include -# endif -# endif +# include #endif -#ifndef HAVE_ENVIRON_DECL -extern char **environ; -#endif - -#ifndef STDIN_FILENO -# define STDIN_FILENO 0 -#endif -#ifndef STDOUT_FILENO -# define STDOUT_FILENO 1 -#endif -#ifndef STDERR_FILENO -# define STDERR_FILENO 2 -#endif - /* The results of open() in this file are not used with fchdir, therefore save some unnecessary work in fchdir.c. */ #undef open @@ -126,14 +105,14 @@ nonintr_open (const char *pathname, int oflag, mode_t mode) */ static pid_t create_pipe (const char *progname, - const char *prog_path, char **prog_argv, - bool pipe_stdin, bool pipe_stdout, - const char *prog_stdin, const char *prog_stdout, - bool null_stderr, - bool slave_process, bool exit_on_error, - int fd[2]) + const char *prog_path, char **prog_argv, + bool pipe_stdin, bool pipe_stdout, + const char *prog_stdin, const char *prog_stdout, + bool null_stderr, + bool slave_process, bool exit_on_error, + int fd[2]) { -#if defined _MSC_VER || defined __MINGW32__ +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ /* Native Woe32 API. This uses _pipe(), dup2(), and spawnv(). It could also be implemented @@ -149,14 +128,16 @@ create_pipe (const char *progname, int nulloutfd; int stdinfd; int stdoutfd; + int saved_errno; + /* FIXME: Need to free memory allocated by prepare_spawn. */ prog_argv = prepare_spawn (prog_argv); if (pipe_stdout) - if (_pipe (ifd, 4096, O_BINARY | O_NOINHERIT) < 0) + if (pipe2_safer (ifd, O_BINARY | O_CLOEXEC) < 0) error (EXIT_FAILURE, errno, _("cannot create pipe")); if (pipe_stdin) - if (_pipe (ofd, 4096, O_BINARY | O_NOINHERIT) < 0) + if (pipe2_safer (ofd, O_BINARY | O_CLOEXEC) < 0) error (EXIT_FAILURE, errno, _("cannot create pipe")); /* Data flow diagram: * @@ -169,11 +150,11 @@ create_pipe (const char *progname, /* Save standard file handles of parent process. */ if (pipe_stdin || prog_stdin != NULL) - orig_stdin = dup_noinherit (STDIN_FILENO); + orig_stdin = dup_safer_noinherit (STDIN_FILENO); if (pipe_stdout || prog_stdout != NULL) - orig_stdout = dup_noinherit (STDOUT_FILENO); + orig_stdout = dup_safer_noinherit (STDOUT_FILENO); if (null_stderr) - orig_stderr = dup_noinherit (STDERR_FILENO); + orig_stderr = dup_safer_noinherit (STDERR_FILENO); child = -1; /* Create standard file handles of child process. */ @@ -183,28 +164,48 @@ create_pipe (const char *progname, if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0) && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0) && (!null_stderr - || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0 - && (nulloutfd == STDERR_FILENO - || (dup2 (nulloutfd, STDERR_FILENO) >= 0 - && close (nulloutfd) >= 0)))) + || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0 + && (nulloutfd == STDERR_FILENO + || (dup2 (nulloutfd, STDERR_FILENO) >= 0 + && close (nulloutfd) >= 0)))) && (pipe_stdin - || prog_stdin == NULL - || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0 - && (stdinfd == STDIN_FILENO - || (dup2 (stdinfd, STDIN_FILENO) >= 0 - && close (stdinfd) >= 0)))) + || prog_stdin == NULL + || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0 + && (stdinfd == STDIN_FILENO + || (dup2 (stdinfd, STDIN_FILENO) >= 0 + && close (stdinfd) >= 0)))) && (pipe_stdout - || prog_stdout == NULL - || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0 - && (stdoutfd == STDOUT_FILENO - || (dup2 (stdoutfd, STDOUT_FILENO) >= 0 - && close (stdoutfd) >= 0))))) + || prog_stdout == NULL + || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0 + && (stdoutfd == STDOUT_FILENO + || (dup2 (stdoutfd, STDOUT_FILENO) >= 0 + && close (stdoutfd) >= 0))))) /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1], but it inherits all open()ed or dup2()ed file handles (which is what - we want in the case of STD*_FILENO) and also orig_stdin, - orig_stdout, orig_stderr (which is not explicitly wanted but - harmless). */ - child = spawnvp (P_NOWAIT, prog_path, prog_argv); + we want in the case of STD*_FILENO). */ + /* Use spawnvpe and pass the environment explicitly. This is needed if + the program has modified the environment using putenv() or [un]setenv(). + On Windows, programs have two environments, one in the "environment + block" of the process and managed through SetEnvironmentVariable(), and + one inside the process, in the location retrieved by the 'environ' + macro. When using spawnvp() without 'e', the child process inherits a + copy of the environment block - ignoring the effects of putenv() and + [un]setenv(). */ + { + child = spawnvpe (P_NOWAIT, prog_path, (const char **) prog_argv, + (const char **) environ); + if (child < 0 && errno == ENOEXEC) + { + /* prog is not an native executable. Try to execute it as a + shell script. Note that prepare_spawn() has already prepended + a hidden element "sh.exe" to prog_argv. */ + --prog_argv; + child = spawnvpe (P_NOWAIT, prog_argv[0], (const char **) prog_argv, + (const char **) environ); + } + } + if (child == -1) + saved_errno = errno; if (stdinfd >= 0) close (stdinfd); if (stdoutfd >= 0) @@ -214,11 +215,11 @@ create_pipe (const char *progname, /* Restore standard file handles of parent process. */ if (null_stderr) - dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr); + undup_safer_noinherit (orig_stderr, STDERR_FILENO); if (pipe_stdout || prog_stdout != NULL) - dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout); + undup_safer_noinherit (orig_stdout, STDOUT_FILENO); if (pipe_stdin || prog_stdin != NULL) - dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin); + undup_safer_noinherit (orig_stdin, STDIN_FILENO); if (pipe_stdin) close (ofd[0]); @@ -227,12 +228,13 @@ create_pipe (const char *progname, if (child == -1) { if (exit_on_error || !null_stderr) - error (exit_on_error ? EXIT_FAILURE : 0, errno, - _("%s subprocess failed"), progname); + error (exit_on_error ? EXIT_FAILURE : 0, saved_errno, + _("%s subprocess failed"), progname); if (pipe_stdout) - close (ifd[0]); + close (ifd[0]); if (pipe_stdin) - close (ofd[1]); + close (ofd[1]); + errno = saved_errno; return -1; } @@ -247,7 +249,6 @@ create_pipe (const char *progname, /* Unix API. */ int ifd[2]; int ofd[2]; -# if HAVE_POSIX_SPAWN sigset_t blocked_signals; posix_spawn_file_actions_t actions; bool actions_allocated; @@ -255,15 +256,12 @@ create_pipe (const char *progname, bool attrs_allocated; int err; pid_t child; -# else - int child; -# endif if (pipe_stdout) - if (pipe (ifd) < 0) + if (pipe_safer (ifd) < 0) error (EXIT_FAILURE, errno, _("cannot create pipe")); if (pipe_stdin) - if (pipe (ofd) < 0) + if (pipe_safer (ofd) < 0) error (EXIT_FAILURE, errno, _("cannot create pipe")); /* Data flow diagram: * @@ -274,7 +272,6 @@ create_pipe (const char *progname, * */ -# if HAVE_POSIX_SPAWN if (slave_process) { sigprocmask (SIG_SETMASK, NULL, &blocked_signals); @@ -284,142 +281,85 @@ create_pipe (const char *progname, attrs_allocated = false; if ((err = posix_spawn_file_actions_init (&actions)) != 0 || (actions_allocated = true, - (pipe_stdin - && (err = posix_spawn_file_actions_adddup2 (&actions, - ofd[0], STDIN_FILENO)) - != 0) - || (pipe_stdout - && (err = posix_spawn_file_actions_adddup2 (&actions, - ifd[1], STDOUT_FILENO)) - != 0) - || (pipe_stdin - && (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) - != 0) - || (pipe_stdout - && (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) - != 0) - || (pipe_stdin - && (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) - != 0) - || (pipe_stdout - && (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) - != 0) - || (null_stderr - && (err = posix_spawn_file_actions_addopen (&actions, - STDERR_FILENO, - "/dev/null", O_RDWR, - 0)) - != 0) - || (!pipe_stdin - && prog_stdin != NULL - && (err = posix_spawn_file_actions_addopen (&actions, - STDIN_FILENO, - prog_stdin, O_RDONLY, - 0)) - != 0) - || (!pipe_stdout - && prog_stdout != NULL - && (err = posix_spawn_file_actions_addopen (&actions, - STDOUT_FILENO, - prog_stdout, O_WRONLY, - 0)) - != 0) - || (slave_process - && ((err = posix_spawnattr_init (&attrs)) != 0 - || (attrs_allocated = true, - (err = posix_spawnattr_setsigmask (&attrs, - &blocked_signals)) - != 0 - || (err = posix_spawnattr_setflags (&attrs, - POSIX_SPAWN_SETSIGMASK)) - != 0))) - || (err = posix_spawnp (&child, prog_path, &actions, - attrs_allocated ? &attrs : NULL, prog_argv, - environ)) - != 0)) + (pipe_stdin + && (err = posix_spawn_file_actions_adddup2 (&actions, + ofd[0], STDIN_FILENO)) + != 0) + || (pipe_stdout + && (err = posix_spawn_file_actions_adddup2 (&actions, + ifd[1], STDOUT_FILENO)) + != 0) + || (pipe_stdin + && (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) + != 0) + || (pipe_stdout + && (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) + != 0) + || (pipe_stdin + && (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) + != 0) + || (pipe_stdout + && (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) + != 0) + || (null_stderr + && (err = posix_spawn_file_actions_addopen (&actions, + STDERR_FILENO, + "/dev/null", O_RDWR, + 0)) + != 0) + || (!pipe_stdin + && prog_stdin != NULL + && (err = posix_spawn_file_actions_addopen (&actions, + STDIN_FILENO, + prog_stdin, O_RDONLY, + 0)) + != 0) + || (!pipe_stdout + && prog_stdout != NULL + && (err = posix_spawn_file_actions_addopen (&actions, + STDOUT_FILENO, + prog_stdout, O_WRONLY, + 0)) + != 0) + || (slave_process + && ((err = posix_spawnattr_init (&attrs)) != 0 + || (attrs_allocated = true, + (err = posix_spawnattr_setsigmask (&attrs, + &blocked_signals)) + != 0 + || (err = posix_spawnattr_setflags (&attrs, + POSIX_SPAWN_SETSIGMASK)) + != 0))) + || (err = posix_spawnp (&child, prog_path, &actions, + attrs_allocated ? &attrs : NULL, prog_argv, + environ)) + != 0)) { if (actions_allocated) - posix_spawn_file_actions_destroy (&actions); + posix_spawn_file_actions_destroy (&actions); if (attrs_allocated) - posix_spawnattr_destroy (&attrs); + posix_spawnattr_destroy (&attrs); if (slave_process) - unblock_fatal_signals (); + unblock_fatal_signals (); if (exit_on_error || !null_stderr) - error (exit_on_error ? EXIT_FAILURE : 0, err, - _("%s subprocess failed"), progname); + error (exit_on_error ? EXIT_FAILURE : 0, err, + _("%s subprocess failed"), progname); if (pipe_stdout) - { - close (ifd[0]); - close (ifd[1]); - } + { + close (ifd[0]); + close (ifd[1]); + } if (pipe_stdin) - { - close (ofd[0]); - close (ofd[1]); - } + { + close (ofd[0]); + close (ofd[1]); + } + errno = err; return -1; } posix_spawn_file_actions_destroy (&actions); if (attrs_allocated) posix_spawnattr_destroy (&attrs); -# else - if (slave_process) - block_fatal_signals (); - /* Use vfork() instead of fork() for efficiency. */ - if ((child = vfork ()) == 0) - { - /* Child process code. */ - int nulloutfd; - int stdinfd; - int stdoutfd; - - if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0) - && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0) - && (!pipe_stdin || close (ofd[0]) >= 0) - && (!pipe_stdout || close (ifd[1]) >= 0) - && (!pipe_stdin || close (ofd[1]) >= 0) - && (!pipe_stdout || close (ifd[0]) >= 0) - && (!null_stderr - || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0 - && (nulloutfd == STDERR_FILENO - || (dup2 (nulloutfd, STDERR_FILENO) >= 0 - && close (nulloutfd) >= 0)))) - && (pipe_stdin - || prog_stdin == NULL - || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0 - && (stdinfd == STDIN_FILENO - || (dup2 (stdinfd, STDIN_FILENO) >= 0 - && close (stdinfd) >= 0)))) - && (pipe_stdout - || prog_stdout == NULL - || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0 - && (stdoutfd == STDOUT_FILENO - || (dup2 (stdoutfd, STDOUT_FILENO) >= 0 - && close (stdoutfd) >= 0)))) - && (!slave_process || (unblock_fatal_signals (), true))) - execvp (prog_path, prog_argv); - _exit (127); - } - if (child == -1) - { - if (slave_process) - unblock_fatal_signals (); - if (exit_on_error || !null_stderr) - error (exit_on_error ? EXIT_FAILURE : 0, errno, - _("%s subprocess failed"), progname); - if (pipe_stdout) - { - close (ifd[0]); - close (ifd[1]); - } - if (pipe_stdin) - { - close (ofd[0]); - close (ofd[1]); - } - return -1; - } -# endif if (slave_process) { register_slave_subprocess (child); @@ -449,15 +389,15 @@ create_pipe (const char *progname, */ pid_t create_pipe_bidi (const char *progname, - const char *prog_path, char **prog_argv, - bool null_stderr, - bool slave_process, bool exit_on_error, - int fd[2]) + const char *prog_path, char **prog_argv, + bool null_stderr, + bool slave_process, bool exit_on_error, + int fd[2]) { pid_t result = create_pipe (progname, prog_path, prog_argv, - true, true, NULL, NULL, - null_stderr, slave_process, exit_on_error, - fd); + true, true, NULL, NULL, + null_stderr, slave_process, exit_on_error, + fd); return result; } @@ -470,16 +410,16 @@ create_pipe_bidi (const char *progname, */ pid_t create_pipe_in (const char *progname, - const char *prog_path, char **prog_argv, - const char *prog_stdin, bool null_stderr, - bool slave_process, bool exit_on_error, - int fd[1]) + const char *prog_path, char **prog_argv, + const char *prog_stdin, bool null_stderr, + bool slave_process, bool exit_on_error, + int fd[1]) { int iofd[2]; pid_t result = create_pipe (progname, prog_path, prog_argv, - false, true, prog_stdin, NULL, - null_stderr, slave_process, exit_on_error, - iofd); + false, true, prog_stdin, NULL, + null_stderr, slave_process, exit_on_error, + iofd); if (result != -1) fd[0] = iofd[0]; return result; @@ -494,16 +434,16 @@ create_pipe_in (const char *progname, */ pid_t create_pipe_out (const char *progname, - const char *prog_path, char **prog_argv, - const char *prog_stdout, bool null_stderr, - bool slave_process, bool exit_on_error, - int fd[1]) + const char *prog_path, char **prog_argv, + const char *prog_stdout, bool null_stderr, + bool slave_process, bool exit_on_error, + int fd[1]) { int iofd[2]; pid_t result = create_pipe (progname, prog_path, prog_argv, - true, false, NULL, prog_stdout, - null_stderr, slave_process, exit_on_error, - iofd); + true, false, NULL, prog_stdout, + null_stderr, slave_process, exit_on_error, + iofd); if (result != -1) fd[0] = iofd[1]; return result;