unistd: guarantee STDIN_FILENO here, for OS/2 EMX
[gnulib.git] / lib / execute.c
1 /* Creation of autonomous subprocesses.
2    Copyright (C) 2001-2004, 2006-2009 Free Software Foundation, Inc.
3    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
4
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 3 of the License, or
8    (at your option) any later version.
9
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.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18
19 #include <config.h>
20
21 /* Specification.  */
22 #include "execute.h"
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stdbool.h>
27 #include <stdlib.h>
28 #include <signal.h>
29 #include <unistd.h>
30
31 #include "error.h"
32 #include "fatal-signal.h"
33 #include "wait-process.h"
34 #include "gettext.h"
35
36 #define _(str) gettext (str)
37
38 #if defined _MSC_VER || defined __MINGW32__
39
40 /* Native Woe32 API.  */
41 # include <process.h>
42 # include "w32spawn.h"
43
44 #else
45
46 /* Unix API.  */
47 # if HAVE_POSIX_SPAWN
48 #  include <spawn.h>
49 # else
50 #  if HAVE_VFORK_H
51 #   include <vfork.h>
52 #  endif
53 # endif
54
55 #endif
56
57 /* The results of open() in this file are not used with fchdir,
58    therefore save some unnecessary work in fchdir.c.  */
59 #undef open
60 #undef close
61
62
63 #ifdef EINTR
64
65 /* EINTR handling for close(), open().
66    These functions can return -1/EINTR even though we don't have any
67    signal handlers set up, namely when we get interrupted via SIGSTOP.  */
68
69 static inline int
70 nonintr_close (int fd)
71 {
72   int retval;
73
74   do
75     retval = close (fd);
76   while (retval < 0 && errno == EINTR);
77
78   return retval;
79 }
80 #define close nonintr_close
81
82 static inline int
83 nonintr_open (const char *pathname, int oflag, mode_t mode)
84 {
85   int retval;
86
87   do
88     retval = open (pathname, oflag, mode);
89   while (retval < 0 && errno == EINTR);
90
91   return retval;
92 }
93 #undef open /* avoid warning on VMS */
94 #define open nonintr_open
95
96 #endif
97
98
99 /* Execute a command, optionally redirecting any of the three standard file
100    descriptors to /dev/null.  Return its exit code.
101    If it didn't terminate correctly, exit if exit_on_error is true, otherwise
102    return 127.
103    If slave_process is true, the child process will be terminated when its
104    creator receives a catchable fatal signal.  */
105 int
106 execute (const char *progname,
107          const char *prog_path, char **prog_argv,
108          bool ignore_sigpipe,
109          bool null_stdin, bool null_stdout, bool null_stderr,
110          bool slave_process, bool exit_on_error,
111          int *termsigp)
112 {
113 #if defined _MSC_VER || defined __MINGW32__
114
115   /* Native Woe32 API.  */
116   int orig_stdin;
117   int orig_stdout;
118   int orig_stderr;
119   int exitcode;
120   int nullinfd;
121   int nulloutfd;
122
123   /* FIXME: Need to free memory allocated by prepare_spawn.  */
124   prog_argv = prepare_spawn (prog_argv);
125
126   /* Save standard file handles of parent process.  */
127   if (null_stdin)
128     orig_stdin = dup_noinherit (STDIN_FILENO);
129   if (null_stdout)
130     orig_stdout = dup_noinherit (STDOUT_FILENO);
131   if (null_stderr)
132     orig_stderr = dup_noinherit (STDERR_FILENO);
133   exitcode = -1;
134
135   /* Create standard file handles of child process.  */
136   nullinfd = -1;
137   nulloutfd = -1;
138   if ((!null_stdin
139        || ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0
140            && (nullinfd == STDIN_FILENO
141                || (dup2 (nullinfd, STDIN_FILENO) >= 0
142                    && close (nullinfd) >= 0))))
143       && (!(null_stdout || null_stderr)
144           || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
145               && (!null_stdout
146                   || nulloutfd == STDOUT_FILENO
147                   || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
148               && (!null_stderr
149                   || nulloutfd == STDERR_FILENO
150                   || dup2 (nulloutfd, STDERR_FILENO) >= 0)
151               && ((null_stdout && nulloutfd == STDOUT_FILENO)
152                   || (null_stderr && nulloutfd == STDERR_FILENO)
153                   || close (nulloutfd) >= 0))))
154     /* Use spawnvpe and pass the environment explicitly.  This is needed if
155        the program has modified the environment using putenv() or [un]setenv().
156        On Windows, programs have two environments, one in the "environment
157        block" of the process and managed through SetEnvironmentVariable(), and
158        one inside the process, in the location retrieved by the 'environ'
159        macro.  When using spawnvp() without 'e', the child process inherits a
160        copy of the environment block - ignoring the effects of putenv() and
161        [un]setenv().  */
162     {
163       exitcode = spawnvpe (P_WAIT, prog_path, prog_argv, environ);
164       if (exitcode < 0 && errno == ENOEXEC)
165         {
166           /* prog is not an native executable.  Try to execute it as a
167              shell script.  Note that prepare_spawn() has already prepended
168              a hidden element "sh.exe" to prog_argv.  */
169           --prog_argv;
170           exitcode = spawnvpe (P_WAIT, prog_argv[0], prog_argv, environ);
171         }
172     }
173   if (nulloutfd >= 0)
174     close (nulloutfd);
175   if (nullinfd >= 0)
176     close (nullinfd);
177
178   /* Restore standard file handles of parent process.  */
179   if (null_stderr)
180     dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr);
181   if (null_stdout)
182     dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout);
183   if (null_stdin)
184     dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin);
185
186   if (termsigp != NULL)
187     *termsigp = 0;
188
189   if (exitcode == -1)
190     {
191       if (exit_on_error || !null_stderr)
192         error (exit_on_error ? EXIT_FAILURE : 0, errno,
193                _("%s subprocess failed"), progname);
194       return 127;
195     }
196
197   return exitcode;
198
199 #else
200
201   /* Unix API.  */
202   /* Note about 127: Some errors during posix_spawnp() cause the function
203      posix_spawnp() to return an error code; some other errors cause the
204      subprocess to exit with return code 127.  It is implementation
205      dependent which error is reported which way.  We treat both cases as
206      equivalent.  */
207 #if HAVE_POSIX_SPAWN
208   sigset_t blocked_signals;
209   posix_spawn_file_actions_t actions;
210   bool actions_allocated;
211   posix_spawnattr_t attrs;
212   bool attrs_allocated;
213   int err;
214   pid_t child;
215 #else
216   int child;
217 #endif
218
219 #if HAVE_POSIX_SPAWN
220   if (slave_process)
221     {
222       sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
223       block_fatal_signals ();
224     }
225   actions_allocated = false;
226   attrs_allocated = false;
227   if ((err = posix_spawn_file_actions_init (&actions)) != 0
228       || (actions_allocated = true,
229           (null_stdin
230             && (err = posix_spawn_file_actions_addopen (&actions,
231                                                         STDIN_FILENO,
232                                                         "/dev/null", O_RDONLY,
233                                                         0))
234                != 0)
235           || (null_stdout
236               && (err = posix_spawn_file_actions_addopen (&actions,
237                                                           STDOUT_FILENO,
238                                                           "/dev/null", O_RDWR,
239                                                           0))
240                  != 0)
241           || (null_stderr
242               && (err = posix_spawn_file_actions_addopen (&actions,
243                                                           STDERR_FILENO,
244                                                           "/dev/null", O_RDWR,
245                                                           0))
246                  != 0)
247           || (slave_process
248               && ((err = posix_spawnattr_init (&attrs)) != 0
249                   || (attrs_allocated = true,
250                       (err = posix_spawnattr_setsigmask (&attrs,
251                                                          &blocked_signals))
252                       != 0
253                       || (err = posix_spawnattr_setflags (&attrs,
254                                                         POSIX_SPAWN_SETSIGMASK))
255                          != 0)))
256           || (err = posix_spawnp (&child, prog_path, &actions,
257                                   attrs_allocated ? &attrs : NULL, prog_argv,
258                                   environ))
259              != 0))
260     {
261       if (actions_allocated)
262         posix_spawn_file_actions_destroy (&actions);
263       if (attrs_allocated)
264         posix_spawnattr_destroy (&attrs);
265       if (slave_process)
266         unblock_fatal_signals ();
267       if (termsigp != NULL)
268         *termsigp = 0;
269       if (exit_on_error || !null_stderr)
270         error (exit_on_error ? EXIT_FAILURE : 0, err,
271                _("%s subprocess failed"), progname);
272       return 127;
273     }
274   posix_spawn_file_actions_destroy (&actions);
275   if (attrs_allocated)
276     posix_spawnattr_destroy (&attrs);
277 #else
278   if (slave_process)
279     block_fatal_signals ();
280   /* Use vfork() instead of fork() for efficiency.  */
281   if ((child = vfork ()) == 0)
282     {
283       /* Child process code.  */
284       int nullinfd;
285       int nulloutfd;
286
287       if ((!null_stdin
288            || ((nullinfd = open ("/dev/null", O_RDONLY, 0)) >= 0
289                && (nullinfd == STDIN_FILENO
290                    || (dup2 (nullinfd, STDIN_FILENO) >= 0
291                        && close (nullinfd) >= 0))))
292           && (!(null_stdout || null_stderr)
293               || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
294                   && (!null_stdout
295                       || nulloutfd == STDOUT_FILENO
296                       || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
297                   && (!null_stderr
298                       || nulloutfd == STDERR_FILENO
299                       || dup2 (nulloutfd, STDERR_FILENO) >= 0)
300                   && ((null_stdout && nulloutfd == STDOUT_FILENO)
301                       || (null_stderr && nulloutfd == STDERR_FILENO)
302                       || close (nulloutfd) >= 0)))
303           && (!slave_process || (unblock_fatal_signals (), true)))
304         execvp (prog_path, prog_argv);
305       _exit (127);
306     }
307   if (child == -1)
308     {
309       if (slave_process)
310         unblock_fatal_signals ();
311       if (termsigp != NULL)
312         *termsigp = 0;
313       if (exit_on_error || !null_stderr)
314         error (exit_on_error ? EXIT_FAILURE : 0, errno,
315                _("%s subprocess failed"), progname);
316       return 127;
317     }
318 #endif
319   if (slave_process)
320     {
321       register_slave_subprocess (child);
322       unblock_fatal_signals ();
323     }
324
325   return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
326                           slave_process, exit_on_error, termsigp);
327
328 #endif
329 }