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. */
36 #include "fatal-signal.h"
37 #include "wait-process.h"
40 #define _(str) gettext (str)
42 #if defined _MSC_VER || defined __MINGW32__
44 /* Native Woe32 API. */
46 # include "w32spawn.h"
51 # ifdef HAVE_POSIX_SPAWN
61 #ifndef HAVE_ENVIRON_DECL
62 extern char **environ;
66 # define STDIN_FILENO 0
69 # define STDOUT_FILENO 1
72 # define STDERR_FILENO 2
78 /* EINTR handling for close(), open().
79 These functions can return -1/EINTR even though we don't have any
80 signal handlers set up, namely when we get interrupted via SIGSTOP. */
83 nonintr_close (int fd)
89 while (retval < 0 && errno == EINTR);
93 #define close nonintr_close
96 nonintr_open (const char *pathname, int oflag, mode_t mode)
101 retval = open (pathname, oflag, mode);
102 while (retval < 0 && errno == EINTR);
106 #undef open /* avoid warning on VMS */
107 #define open nonintr_open
112 /* Execute a command, optionally redirecting any of the three standard file
113 descriptors to /dev/null. Return its exit code.
114 If it didn't terminate correctly, exit if exit_on_error is true, otherwise
116 If slave_process is true, the child process will be terminated when its
117 creator receives a catchable fatal signal. */
119 execute (const char *progname,
120 const char *prog_path, char **prog_argv,
122 bool null_stdin, bool null_stdout, bool null_stderr,
123 bool slave_process, bool exit_on_error)
125 #if defined _MSC_VER || defined __MINGW32__
127 /* Native Woe32 API. */
135 prog_argv = prepare_spawn (prog_argv);
137 /* Save standard file handles of parent process. */
139 orig_stdin = dup_noinherit (STDIN_FILENO);
141 orig_stdout = dup_noinherit (STDOUT_FILENO);
143 orig_stderr = dup_noinherit (STDERR_FILENO);
146 /* Create standard file handles of child process. */
150 || ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0
151 && (nullinfd == STDIN_FILENO
152 || (dup2 (nullinfd, STDIN_FILENO) >= 0
153 && close (nullinfd) >= 0))))
154 && (!(null_stdout || null_stderr)
155 || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
157 || nulloutfd == STDOUT_FILENO
158 || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
160 || nulloutfd == STDERR_FILENO
161 || dup2 (nulloutfd, STDERR_FILENO) >= 0)
162 && ((null_stdout && nulloutfd == STDOUT_FILENO)
163 || (null_stderr && nulloutfd == STDERR_FILENO)
164 || close (nulloutfd) >= 0))))
165 exitcode = spawnvp (P_WAIT, prog_path, prog_argv);
171 /* Restore standard file handles of parent process. */
173 dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr);
175 dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout);
177 dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin);
181 if (exit_on_error || !null_stderr)
182 error (exit_on_error ? EXIT_FAILURE : 0, errno,
183 _("%s subprocess failed"), progname);
192 /* Note about 127: Some errors during posix_spawnp() cause the function
193 posix_spawnp() to return an error code; some other errors cause the
194 subprocess to exit with return code 127. It is implementation
195 dependent which error is reported which way. We treat both cases as
198 sigset_t blocked_signals;
199 posix_spawn_file_actions_t actions;
200 bool actions_allocated;
201 posix_spawnattr_t attrs;
202 bool attrs_allocated;
212 sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
213 block_fatal_signals ();
215 actions_allocated = false;
216 attrs_allocated = false;
217 if ((err = posix_spawn_file_actions_init (&actions)) != 0
218 || (actions_allocated = true,
220 && (err = posix_spawn_file_actions_addopen (&actions,
222 "/dev/null", O_RDONLY,
226 && (err = posix_spawn_file_actions_addopen (&actions,
232 && (err = posix_spawn_file_actions_addopen (&actions,
238 && ((err = posix_spawnattr_init (&attrs)) != 0
239 || (attrs_allocated = true,
240 (err = posix_spawnattr_setsigmask (&attrs,
243 || (err = posix_spawnattr_setflags (&attrs,
244 POSIX_SPAWN_SETSIGMASK))
246 || (err = posix_spawnp (&child, prog_path, &actions,
247 attrs_allocated ? &attrs : NULL, prog_argv,
251 if (actions_allocated)
252 posix_spawn_file_actions_destroy (&actions);
254 posix_spawnattr_destroy (&attrs);
256 unblock_fatal_signals ();
257 if (exit_on_error || !null_stderr)
258 error (exit_on_error ? EXIT_FAILURE : 0, err,
259 _("%s subprocess failed"), progname);
262 posix_spawn_file_actions_destroy (&actions);
264 posix_spawnattr_destroy (&attrs);
267 block_fatal_signals ();
268 /* Use vfork() instead of fork() for efficiency. */
269 if ((child = vfork ()) == 0)
271 /* Child process code. */
276 || ((nullinfd = open ("/dev/null", O_RDONLY, 0)) >= 0
277 && (nullinfd == STDIN_FILENO
278 || (dup2 (nullinfd, STDIN_FILENO) >= 0
279 && close (nullinfd) >= 0))))
280 && (!(null_stdout || null_stderr)
281 || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
283 || nulloutfd == STDOUT_FILENO
284 || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
286 || nulloutfd == STDERR_FILENO
287 || dup2 (nulloutfd, STDERR_FILENO) >= 0)
288 && ((null_stdout && nulloutfd == STDOUT_FILENO)
289 || (null_stderr && nulloutfd == STDERR_FILENO)
290 || close (nulloutfd) >= 0)))
291 && (!slave_process || (unblock_fatal_signals (), true)))
292 execvp (prog_path, prog_argv);
298 unblock_fatal_signals ();
299 if (exit_on_error || !null_stderr)
300 error (exit_on_error ? EXIT_FAILURE : 0, errno,
301 _("%s subprocess failed"), progname);
307 register_slave_subprocess (child);
308 unblock_fatal_signals ();
311 return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
312 slave_process, exit_on_error);