1 /* Creation of autonomous subprocesses.
2 Copyright (C) 2001-2004, 2006-2007 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. */
33 #include "fatal-signal.h"
34 #include "wait-process.h"
37 #define _(str) gettext (str)
39 #if defined _MSC_VER || defined __MINGW32__
41 /* Native Woe32 API. */
43 # include "w32spawn.h"
58 #if ! HAVE_ENVIRON_DECL
59 extern char **environ;
63 # define STDIN_FILENO 0
66 # define STDOUT_FILENO 1
69 # define STDERR_FILENO 2
72 /* The results of open() in this file are not used with fchdir,
73 therefore save some unnecessary work in fchdir.c. */
80 /* EINTR handling for close(), open().
81 These functions can return -1/EINTR even though we don't have any
82 signal handlers set up, namely when we get interrupted via SIGSTOP. */
85 nonintr_close (int fd)
91 while (retval < 0 && errno == EINTR);
95 #define close nonintr_close
98 nonintr_open (const char *pathname, int oflag, mode_t mode)
103 retval = open (pathname, oflag, mode);
104 while (retval < 0 && errno == EINTR);
108 #undef open /* avoid warning on VMS */
109 #define open nonintr_open
114 /* Execute a command, optionally redirecting any of the three standard file
115 descriptors to /dev/null. Return its exit code.
116 If it didn't terminate correctly, exit if exit_on_error is true, otherwise
118 If slave_process is true, the child process will be terminated when its
119 creator receives a catchable fatal signal. */
121 execute (const char *progname,
122 const char *prog_path, char **prog_argv,
124 bool null_stdin, bool null_stdout, bool null_stderr,
125 bool slave_process, bool exit_on_error)
127 #if defined _MSC_VER || defined __MINGW32__
129 /* Native Woe32 API. */
137 prog_argv = prepare_spawn (prog_argv);
139 /* Save standard file handles of parent process. */
141 orig_stdin = dup_noinherit (STDIN_FILENO);
143 orig_stdout = dup_noinherit (STDOUT_FILENO);
145 orig_stderr = dup_noinherit (STDERR_FILENO);
148 /* Create standard file handles of child process. */
152 || ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0
153 && (nullinfd == STDIN_FILENO
154 || (dup2 (nullinfd, STDIN_FILENO) >= 0
155 && close (nullinfd) >= 0))))
156 && (!(null_stdout || null_stderr)
157 || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
159 || nulloutfd == STDOUT_FILENO
160 || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
162 || nulloutfd == STDERR_FILENO
163 || dup2 (nulloutfd, STDERR_FILENO) >= 0)
164 && ((null_stdout && nulloutfd == STDOUT_FILENO)
165 || (null_stderr && nulloutfd == STDERR_FILENO)
166 || close (nulloutfd) >= 0))))
167 exitcode = spawnvp (P_WAIT, prog_path, prog_argv);
173 /* Restore standard file handles of parent process. */
175 dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr);
177 dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout);
179 dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin);
183 if (exit_on_error || !null_stderr)
184 error (exit_on_error ? EXIT_FAILURE : 0, errno,
185 _("%s subprocess failed"), progname);
194 /* Note about 127: Some errors during posix_spawnp() cause the function
195 posix_spawnp() to return an error code; some other errors cause the
196 subprocess to exit with return code 127. It is implementation
197 dependent which error is reported which way. We treat both cases as
200 sigset_t blocked_signals;
201 posix_spawn_file_actions_t actions;
202 bool actions_allocated;
203 posix_spawnattr_t attrs;
204 bool attrs_allocated;
214 sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
215 block_fatal_signals ();
217 actions_allocated = false;
218 attrs_allocated = false;
219 if ((err = posix_spawn_file_actions_init (&actions)) != 0
220 || (actions_allocated = true,
222 && (err = posix_spawn_file_actions_addopen (&actions,
224 "/dev/null", O_RDONLY,
228 && (err = posix_spawn_file_actions_addopen (&actions,
234 && (err = posix_spawn_file_actions_addopen (&actions,
240 && ((err = posix_spawnattr_init (&attrs)) != 0
241 || (attrs_allocated = true,
242 (err = posix_spawnattr_setsigmask (&attrs,
245 || (err = posix_spawnattr_setflags (&attrs,
246 POSIX_SPAWN_SETSIGMASK))
248 || (err = posix_spawnp (&child, prog_path, &actions,
249 attrs_allocated ? &attrs : NULL, prog_argv,
253 if (actions_allocated)
254 posix_spawn_file_actions_destroy (&actions);
256 posix_spawnattr_destroy (&attrs);
258 unblock_fatal_signals ();
259 if (exit_on_error || !null_stderr)
260 error (exit_on_error ? EXIT_FAILURE : 0, err,
261 _("%s subprocess failed"), progname);
264 posix_spawn_file_actions_destroy (&actions);
266 posix_spawnattr_destroy (&attrs);
269 block_fatal_signals ();
270 /* Use vfork() instead of fork() for efficiency. */
271 if ((child = vfork ()) == 0)
273 /* Child process code. */
278 || ((nullinfd = open ("/dev/null", O_RDONLY, 0)) >= 0
279 && (nullinfd == STDIN_FILENO
280 || (dup2 (nullinfd, STDIN_FILENO) >= 0
281 && close (nullinfd) >= 0))))
282 && (!(null_stdout || null_stderr)
283 || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
285 || nulloutfd == STDOUT_FILENO
286 || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
288 || nulloutfd == STDERR_FILENO
289 || dup2 (nulloutfd, STDERR_FILENO) >= 0)
290 && ((null_stdout && nulloutfd == STDOUT_FILENO)
291 || (null_stderr && nulloutfd == STDERR_FILENO)
292 || close (nulloutfd) >= 0)))
293 && (!slave_process || (unblock_fatal_signals (), true)))
294 execvp (prog_path, prog_argv);
300 unblock_fatal_signals ();
301 if (exit_on_error || !null_stderr)
302 error (exit_on_error ? EXIT_FAILURE : 0, errno,
303 _("%s subprocess failed"), progname);
309 register_slave_subprocess (child);
310 unblock_fatal_signals ();
313 return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
314 slave_process, exit_on_error);