1 /* Creation of autonomous subprocesses.
2 Copyright (C) 2001-2004 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
64 #ifndef HAVE_ENVIRON_DECL
65 extern char **environ
;
69 # define STDIN_FILENO 0
72 # define STDOUT_FILENO 1
75 # define STDERR_FILENO 2
81 /* EINTR handling for close(), open().
82 These functions can return -1/EINTR even though we don't have any
83 signal handlers set up, namely when we get interrupted via SIGSTOP. */
86 nonintr_close (int fd
)
92 while (retval
< 0 && errno
== EINTR
);
96 #define close nonintr_close
99 nonintr_open (const char *pathname
, int oflag
, mode_t mode
)
104 retval
= open (pathname
, oflag
, mode
);
105 while (retval
< 0 && errno
== EINTR
);
109 #undef open /* avoid warning on VMS */
110 #define open nonintr_open
115 /* Execute a command, optionally redirecting any of the three standard file
116 descriptors to /dev/null. Return its exit code.
117 If it didn't terminate correctly, exit if exit_on_error is true, otherwise
119 If slave_process is true, the child process will be terminated when its
120 creator receives a catchable fatal signal. */
122 execute (const char *progname
,
123 const char *prog_path
, char **prog_argv
,
125 bool null_stdin
, bool null_stdout
, bool null_stderr
,
126 bool slave_process
, bool exit_on_error
)
128 #if defined _MSC_VER || defined __MINGW32__
130 /* Native Woe32 API. */
138 prog_argv
= prepare_spawn (prog_argv
);
140 /* Save standard file handles of parent process. */
142 orig_stdin
= dup_noinherit (STDIN_FILENO
);
144 orig_stdout
= dup_noinherit (STDOUT_FILENO
);
146 orig_stderr
= dup_noinherit (STDERR_FILENO
);
149 /* Create standard file handles of child process. */
153 || ((nullinfd
= open ("NUL", O_RDONLY
, 0)) >= 0
154 && (nullinfd
== STDIN_FILENO
155 || (dup2 (nullinfd
, STDIN_FILENO
) >= 0
156 && close (nullinfd
) >= 0))))
157 && (!(null_stdout
|| null_stderr
)
158 || ((nulloutfd
= open ("NUL", O_RDWR
, 0)) >= 0
160 || nulloutfd
== STDOUT_FILENO
161 || dup2 (nulloutfd
, STDOUT_FILENO
) >= 0)
163 || nulloutfd
== STDERR_FILENO
164 || dup2 (nulloutfd
, STDERR_FILENO
) >= 0)
165 && ((null_stdout
&& nulloutfd
== STDOUT_FILENO
)
166 || (null_stderr
&& nulloutfd
== STDERR_FILENO
)
167 || close (nulloutfd
) >= 0))))
168 exitcode
= spawnvp (P_WAIT
, prog_path
, prog_argv
);
174 /* Restore standard file handles of parent process. */
176 dup2 (orig_stderr
, STDERR_FILENO
), close (orig_stderr
);
178 dup2 (orig_stdout
, STDOUT_FILENO
), close (orig_stdout
);
180 dup2 (orig_stdin
, STDIN_FILENO
), close (orig_stdin
);
184 if (exit_on_error
|| !null_stderr
)
185 error (exit_on_error
? EXIT_FAILURE
: 0, errno
,
186 _("%s subprocess failed"), progname
);
195 /* Note about 127: Some errors during posix_spawnp() cause the function
196 posix_spawnp() to return an error code; some other errors cause the
197 subprocess to exit with return code 127. It is implementation
198 dependent which error is reported which way. We treat both cases as
201 sigset_t blocked_signals
;
202 posix_spawn_file_actions_t actions
;
203 bool actions_allocated
;
204 posix_spawnattr_t attrs
;
205 bool attrs_allocated
;
215 sigprocmask (SIG_SETMASK
, NULL
, &blocked_signals
);
216 block_fatal_signals ();
218 actions_allocated
= false;
219 attrs_allocated
= false;
220 if ((err
= posix_spawn_file_actions_init (&actions
)) != 0
221 || (actions_allocated
= true,
223 && (err
= posix_spawn_file_actions_addopen (&actions
,
225 "/dev/null", O_RDONLY
,
229 && (err
= posix_spawn_file_actions_addopen (&actions
,
235 && (err
= posix_spawn_file_actions_addopen (&actions
,
241 && ((err
= posix_spawnattr_init (&attrs
)) != 0
242 || (attrs_allocated
= true,
243 (err
= posix_spawnattr_setsigmask (&attrs
,
246 || (err
= posix_spawnattr_setflags (&attrs
,
247 POSIX_SPAWN_SETSIGMASK
))
249 || (err
= posix_spawnp (&child
, prog_path
, &actions
,
250 attrs_allocated
? &attrs
: NULL
, prog_argv
,
254 if (actions_allocated
)
255 posix_spawn_file_actions_destroy (&actions
);
257 posix_spawnattr_destroy (&attrs
);
259 unblock_fatal_signals ();
260 if (exit_on_error
|| !null_stderr
)
261 error (exit_on_error
? EXIT_FAILURE
: 0, err
,
262 _("%s subprocess failed"), progname
);
265 posix_spawn_file_actions_destroy (&actions
);
267 posix_spawnattr_destroy (&attrs
);
270 block_fatal_signals ();
271 /* Use vfork() instead of fork() for efficiency. */
272 if ((child
= vfork ()) == 0)
274 /* Child process code. */
279 || ((nullinfd
= open ("/dev/null", O_RDONLY
, 0)) >= 0
280 && (nullinfd
== STDIN_FILENO
281 || (dup2 (nullinfd
, STDIN_FILENO
) >= 0
282 && close (nullinfd
) >= 0))))
283 && (!(null_stdout
|| null_stderr
)
284 || ((nulloutfd
= open ("/dev/null", O_RDWR
, 0)) >= 0
286 || nulloutfd
== STDOUT_FILENO
287 || dup2 (nulloutfd
, STDOUT_FILENO
) >= 0)
289 || nulloutfd
== STDERR_FILENO
290 || dup2 (nulloutfd
, STDERR_FILENO
) >= 0)
291 && ((null_stdout
&& nulloutfd
== STDOUT_FILENO
)
292 || (null_stderr
&& nulloutfd
== STDERR_FILENO
)
293 || close (nulloutfd
) >= 0)))
294 && (!slave_process
|| (unblock_fatal_signals (), true)))
295 execvp (prog_path
, prog_argv
);
301 unblock_fatal_signals ();
302 if (exit_on_error
|| !null_stderr
)
303 error (exit_on_error
? EXIT_FAILURE
: 0, errno
,
304 _("%s subprocess failed"), progname
);
310 register_slave_subprocess (child
);
311 unblock_fatal_signals ();
314 return wait_subprocess (child
, progname
, ignore_sigpipe
, null_stderr
,
315 slave_process
, exit_on_error
);