1
/* Creation of autonomous subprocesses.
2
Copyright (C) 2001-2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
39
#include "fatal-signal.h"
40
#include "wait-process.h"
43
#define _(str) gettext (str)
45
#if defined _MSC_VER || defined __MINGW32__
47
/* Native Woe32 API. */
49
# include "w32spawn.h"
54
# ifdef HAVE_POSIX_SPAWN
65
# define STDIN_FILENO 0
68
# define STDOUT_FILENO 1
71
# define STDERR_FILENO 2
77
/* EINTR handling for close(), open().
78
These functions can return -1/EINTR even though we don't have any
79
signal handlers set up, namely when we get interrupted via SIGSTOP. */
82
nonintr_close (int fd)
88
while (retval < 0 && errno == EINTR);
92
#define close nonintr_close
95
nonintr_open (const char *pathname, int oflag, mode_t mode)
100
retval = open (pathname, oflag, mode);
101
while (retval < 0 && errno == EINTR);
105
#undef open /* avoid warning on VMS */
106
#define open nonintr_open
111
/* Execute a command, optionally redirecting any of the three standard file
112
descriptors to /dev/null. Return its exit code.
113
If it didn't terminate correctly, exit if exit_on_error is true, otherwise
115
If slave_process is true, the child process will be terminated when its
116
creator receives a catchable fatal signal. */
118
execute (const char *progname,
119
const char *prog_path, char **prog_argv,
121
bool null_stdin, bool null_stdout, bool null_stderr,
122
bool slave_process, bool exit_on_error)
124
#if defined _MSC_VER || defined __MINGW32__
126
/* Native Woe32 API. */
134
prog_argv = prepare_spawn (prog_argv);
136
/* Save standard file handles of parent process. */
138
orig_stdin = dup_noinherit (STDIN_FILENO);
140
orig_stdout = dup_noinherit (STDOUT_FILENO);
142
orig_stderr = dup_noinherit (STDERR_FILENO);
145
/* Create standard file handles of child process. */
149
|| ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0
150
&& (nullinfd == STDIN_FILENO
151
|| (dup2 (nullinfd, STDIN_FILENO) >= 0
152
&& close (nullinfd) >= 0))))
153
&& (!(null_stdout || null_stderr)
154
|| ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
156
|| nulloutfd == STDOUT_FILENO
157
|| dup2 (nulloutfd, STDOUT_FILENO) >= 0)
159
|| nulloutfd == STDERR_FILENO
160
|| dup2 (nulloutfd, STDERR_FILENO) >= 0)
161
&& ((null_stdout && nulloutfd == STDOUT_FILENO)
162
|| (null_stderr && nulloutfd == STDERR_FILENO)
163
|| close (nulloutfd) >= 0))))
164
exitcode = spawnvp (P_WAIT, prog_path, prog_argv);
170
/* Restore standard file handles of parent process. */
172
dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr);
174
dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout);
176
dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin);
180
if (exit_on_error || !null_stderr)
181
error (exit_on_error ? EXIT_FAILURE : 0, errno,
182
_("%s subprocess failed"), progname);
191
/* Note about 127: Some errors during posix_spawnp() cause the function
192
posix_spawnp() to return an error code; some other errors cause the
193
subprocess to exit with return code 127. It is implementation
194
dependent which error is reported which way. We treat both cases as
197
sigset_t blocked_signals;
198
posix_spawn_file_actions_t actions;
199
bool actions_allocated;
200
posix_spawnattr_t attrs;
201
bool attrs_allocated;
211
sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
212
block_fatal_signals ();
214
actions_allocated = false;
215
attrs_allocated = false;
216
if ((err = posix_spawn_file_actions_init (&actions)) != 0
217
|| (actions_allocated = true,
219
&& (err = posix_spawn_file_actions_addopen (&actions,
221
"/dev/null", O_RDONLY,
225
&& (err = posix_spawn_file_actions_addopen (&actions,
231
&& (err = posix_spawn_file_actions_addopen (&actions,
237
&& ((err = posix_spawnattr_init (&attrs)) != 0
238
|| (attrs_allocated = true,
239
(err = posix_spawnattr_setsigmask (&attrs,
242
|| (err = posix_spawnattr_setflags (&attrs,
243
POSIX_SPAWN_SETSIGMASK))
245
|| (err = posix_spawnp (&child, prog_path, &actions,
246
attrs_allocated ? &attrs : NULL, prog_argv,
250
if (actions_allocated)
251
posix_spawn_file_actions_destroy (&actions);
253
posix_spawnattr_destroy (&attrs);
255
unblock_fatal_signals ();
256
if (exit_on_error || !null_stderr)
257
error (exit_on_error ? EXIT_FAILURE : 0, err,
258
_("%s subprocess failed"), progname);
261
posix_spawn_file_actions_destroy (&actions);
263
posix_spawnattr_destroy (&attrs);
266
block_fatal_signals ();
267
/* Use vfork() instead of fork() for efficiency. */
268
if ((child = vfork ()) == 0)
270
/* Child process code. */
275
|| ((nullinfd = open ("/dev/null", O_RDONLY, 0)) >= 0
276
&& (nullinfd == STDIN_FILENO
277
|| (dup2 (nullinfd, STDIN_FILENO) >= 0
278
&& close (nullinfd) >= 0))))
279
&& (!(null_stdout || null_stderr)
280
|| ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
282
|| nulloutfd == STDOUT_FILENO
283
|| dup2 (nulloutfd, STDOUT_FILENO) >= 0)
285
|| nulloutfd == STDERR_FILENO
286
|| dup2 (nulloutfd, STDERR_FILENO) >= 0)
287
&& ((null_stdout && nulloutfd == STDOUT_FILENO)
288
|| (null_stderr && nulloutfd == STDERR_FILENO)
289
|| close (nulloutfd) >= 0)))
290
&& (!slave_process || (unblock_fatal_signals (), true)))
291
execvp (prog_path, prog_argv);
297
unblock_fatal_signals ();
298
if (exit_on_error || !null_stderr)
299
error (exit_on_error ? EXIT_FAILURE : 0, errno,
300
_("%s subprocess failed"), progname);
306
register_slave_subprocess (child);
307
unblock_fatal_signals ();
310
return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
311
slave_process, exit_on_error);