1 /* Creation of autonomous subprocesses.
2 Copyright (C) 2001-2004, 2006 Free Software Foundation, Inc.
3 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
34 #include "fatal-signal.h"
35 #include "wait-process.h"
38 #define _(str) gettext (str)
40 #if defined _MSC_VER || defined __MINGW32__
42 /* Native Woe32 API. */
44 # include "w32spawn.h"
49 # ifdef HAVE_POSIX_SPAWN
59 #ifndef HAVE_ENVIRON_DECL
60 extern char **environ;
64 # define STDIN_FILENO 0
67 # define STDOUT_FILENO 1
70 # define STDERR_FILENO 2
76 /* EINTR handling for close(), open().
77 These functions can return -1/EINTR even though we don't have any
78 signal handlers set up, namely when we get interrupted via SIGSTOP. */
81 nonintr_close (int fd)
87 while (retval < 0 && errno == EINTR);
91 #define close nonintr_close
94 nonintr_open (const char *pathname, int oflag, mode_t mode)
99 retval = open (pathname, oflag, mode);
100 while (retval < 0 && errno == EINTR);
104 #undef open /* avoid warning on VMS */
105 #define open nonintr_open
110 /* Execute a command, optionally redirecting any of the three standard file
111 descriptors to /dev/null. Return its exit code.
112 If it didn't terminate correctly, exit if exit_on_error is true, otherwise
114 If slave_process is true, the child process will be terminated when its
115 creator receives a catchable fatal signal. */
117 execute (const char *progname,
118 const char *prog_path, char **prog_argv,
120 bool null_stdin, bool null_stdout, bool null_stderr,
121 bool slave_process, bool exit_on_error)
123 #if defined _MSC_VER || defined __MINGW32__
125 /* Native Woe32 API. */
133 prog_argv = prepare_spawn (prog_argv);
135 /* Save standard file handles of parent process. */
137 orig_stdin = dup_noinherit (STDIN_FILENO);
139 orig_stdout = dup_noinherit (STDOUT_FILENO);
141 orig_stderr = dup_noinherit (STDERR_FILENO);
144 /* Create standard file handles of child process. */
148 || ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0
149 && (nullinfd == STDIN_FILENO
150 || (dup2 (nullinfd, STDIN_FILENO) >= 0
151 && close (nullinfd) >= 0))))
152 && (!(null_stdout || null_stderr)
153 || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
155 || nulloutfd == STDOUT_FILENO
156 || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
158 || nulloutfd == STDERR_FILENO
159 || dup2 (nulloutfd, STDERR_FILENO) >= 0)
160 && ((null_stdout && nulloutfd == STDOUT_FILENO)
161 || (null_stderr && nulloutfd == STDERR_FILENO)
162 || close (nulloutfd) >= 0))))
163 exitcode = spawnvp (P_WAIT, prog_path, prog_argv);
169 /* Restore standard file handles of parent process. */
171 dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr);
173 dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout);
175 dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin);
179 if (exit_on_error || !null_stderr)
180 error (exit_on_error ? EXIT_FAILURE : 0, errno,
181 _("%s subprocess failed"), progname);
190 /* Note about 127: Some errors during posix_spawnp() cause the function
191 posix_spawnp() to return an error code; some other errors cause the
192 subprocess to exit with return code 127. It is implementation
193 dependent which error is reported which way. We treat both cases as
196 sigset_t blocked_signals;
197 posix_spawn_file_actions_t actions;
198 bool actions_allocated;
199 posix_spawnattr_t attrs;
200 bool attrs_allocated;
210 sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
211 block_fatal_signals ();
213 actions_allocated = false;
214 attrs_allocated = false;
215 if ((err = posix_spawn_file_actions_init (&actions)) != 0
216 || (actions_allocated = true,
218 && (err = posix_spawn_file_actions_addopen (&actions,
220 "/dev/null", O_RDONLY,
224 && (err = posix_spawn_file_actions_addopen (&actions,
230 && (err = posix_spawn_file_actions_addopen (&actions,
236 && ((err = posix_spawnattr_init (&attrs)) != 0
237 || (attrs_allocated = true,
238 (err = posix_spawnattr_setsigmask (&attrs,
241 || (err = posix_spawnattr_setflags (&attrs,
242 POSIX_SPAWN_SETSIGMASK))
244 || (err = posix_spawnp (&child, prog_path, &actions,
245 attrs_allocated ? &attrs : NULL, prog_argv,
249 if (actions_allocated)
250 posix_spawn_file_actions_destroy (&actions);
252 posix_spawnattr_destroy (&attrs);
254 unblock_fatal_signals ();
255 if (exit_on_error || !null_stderr)
256 error (exit_on_error ? EXIT_FAILURE : 0, err,
257 _("%s subprocess failed"), progname);
260 posix_spawn_file_actions_destroy (&actions);
262 posix_spawnattr_destroy (&attrs);
265 block_fatal_signals ();
266 /* Use vfork() instead of fork() for efficiency. */
267 if ((child = vfork ()) == 0)
269 /* Child process code. */
274 || ((nullinfd = open ("/dev/null", O_RDONLY, 0)) >= 0
275 && (nullinfd == STDIN_FILENO
276 || (dup2 (nullinfd, STDIN_FILENO) >= 0
277 && close (nullinfd) >= 0))))
278 && (!(null_stdout || null_stderr)
279 || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
281 || nulloutfd == STDOUT_FILENO
282 || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
284 || nulloutfd == STDERR_FILENO
285 || dup2 (nulloutfd, STDERR_FILENO) >= 0)
286 && ((null_stdout && nulloutfd == STDOUT_FILENO)
287 || (null_stderr && nulloutfd == STDERR_FILENO)
288 || close (nulloutfd) >= 0)))
289 && (!slave_process || (unblock_fatal_signals (), true)))
290 execvp (prog_path, prog_argv);
296 unblock_fatal_signals ();
297 if (exit_on_error || !null_stderr)
298 error (exit_on_error ? EXIT_FAILURE : 0, errno,
299 _("%s subprocess failed"), progname);
305 register_slave_subprocess (child);
306 unblock_fatal_signals ();
309 return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
310 slave_process, exit_on_error);