Include <unistd.h> unconditionally.
[gnulib.git] / lib / execute.c
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.
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 2, or (at your option)
8    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, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 /* Specification.  */
25 #include "execute.h"
26
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdbool.h>
30 #include <stdlib.h>
31 #include <signal.h>
32 #include <unistd.h>
33
34 #include "error.h"
35 #include "exit.h"
36 #include "fatal-signal.h"
37 #include "wait-process.h"
38 #include "gettext.h"
39
40 #define _(str) gettext (str)
41
42 #if defined _MSC_VER || defined __MINGW32__
43
44 /* Native Woe32 API.  */
45 # include <process.h>
46 # include "w32spawn.h"
47
48 #else
49
50 /* Unix API.  */
51 # ifdef HAVE_POSIX_SPAWN
52 #  include <spawn.h>
53 # else
54 #  ifdef HAVE_VFORK_H
55 #   include <vfork.h>
56 #  endif
57 # endif
58
59 #endif
60
61 #ifndef HAVE_ENVIRON_DECL
62 extern char **environ;
63 #endif
64
65 #ifndef STDIN_FILENO
66 # define STDIN_FILENO 0
67 #endif
68 #ifndef STDOUT_FILENO
69 # define STDOUT_FILENO 1
70 #endif
71 #ifndef STDERR_FILENO
72 # define STDERR_FILENO 2
73 #endif
74
75
76 #ifdef EINTR
77
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.  */
81
82 static inline int
83 nonintr_close (int fd)
84 {
85   int retval;
86
87   do
88     retval = close (fd);
89   while (retval < 0 && errno == EINTR);
90
91   return retval;
92 }
93 #define close nonintr_close
94
95 static inline int
96 nonintr_open (const char *pathname, int oflag, mode_t mode)
97 {
98   int retval;
99
100   do
101     retval = open (pathname, oflag, mode);
102   while (retval < 0 && errno == EINTR);
103
104   return retval;
105 }
106 #undef open /* avoid warning on VMS */
107 #define open nonintr_open
108
109 #endif
110
111
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
115    return 127.
116    If slave_process is true, the child process will be terminated when its
117    creator receives a catchable fatal signal.  */
118 int
119 execute (const char *progname,
120          const char *prog_path, char **prog_argv,
121          bool ignore_sigpipe,
122          bool null_stdin, bool null_stdout, bool null_stderr,
123          bool slave_process, bool exit_on_error)
124 {
125 #if defined _MSC_VER || defined __MINGW32__
126
127   /* Native Woe32 API.  */
128   int orig_stdin;
129   int orig_stdout;
130   int orig_stderr;
131   int exitcode;
132   int nullinfd;
133   int nulloutfd;
134
135   prog_argv = prepare_spawn (prog_argv);
136
137   /* Save standard file handles of parent process.  */
138   if (null_stdin)
139     orig_stdin = dup_noinherit (STDIN_FILENO);
140   if (null_stdout)
141     orig_stdout = dup_noinherit (STDOUT_FILENO);
142   if (null_stderr)
143     orig_stderr = dup_noinherit (STDERR_FILENO);
144   exitcode = -1;
145
146   /* Create standard file handles of child process.  */
147   nullinfd = -1;
148   nulloutfd = -1;
149   if ((!null_stdin
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
156               && (!null_stdout
157                   || nulloutfd == STDOUT_FILENO
158                   || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
159               && (!null_stderr
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);
166   if (nulloutfd >= 0)
167     close (nulloutfd);
168   if (nullinfd >= 0)
169     close (nullinfd);
170
171   /* Restore standard file handles of parent process.  */
172   if (null_stderr)
173     dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr);
174   if (null_stdout)
175     dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout);
176   if (null_stdin)
177     dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin);
178
179   if (exitcode == -1)
180     {
181       if (exit_on_error || !null_stderr)
182         error (exit_on_error ? EXIT_FAILURE : 0, errno,
183                _("%s subprocess failed"), progname);
184       return 127;
185     }
186
187   return exitcode;
188
189 #else
190
191   /* Unix API.  */
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
196      equivalent.  */
197 #if HAVE_POSIX_SPAWN
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;
203   int err;
204   pid_t child;
205 #else
206   int child;
207 #endif
208
209 #if HAVE_POSIX_SPAWN
210   if (slave_process)
211     {
212       sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
213       block_fatal_signals ();
214     }
215   actions_allocated = false;
216   attrs_allocated = false;
217   if ((err = posix_spawn_file_actions_init (&actions)) != 0
218       || (actions_allocated = true,
219           (null_stdin
220             && (err = posix_spawn_file_actions_addopen (&actions,
221                                                         STDIN_FILENO,
222                                                         "/dev/null", O_RDONLY,
223                                                         0))
224                != 0)
225           || (null_stdout
226               && (err = posix_spawn_file_actions_addopen (&actions,
227                                                           STDOUT_FILENO,
228                                                           "/dev/null", O_RDWR,
229                                                           0))
230                  != 0)
231           || (null_stderr
232               && (err = posix_spawn_file_actions_addopen (&actions,
233                                                           STDERR_FILENO,
234                                                           "/dev/null", O_RDWR,
235                                                           0))
236                  != 0)
237           || (slave_process
238               && ((err = posix_spawnattr_init (&attrs)) != 0
239                   || (attrs_allocated = true,
240                       (err = posix_spawnattr_setsigmask (&attrs,
241                                                          &blocked_signals))
242                       != 0
243                       || (err = posix_spawnattr_setflags (&attrs,
244                                                         POSIX_SPAWN_SETSIGMASK))
245                          != 0)))
246           || (err = posix_spawnp (&child, prog_path, &actions,
247                                   attrs_allocated ? &attrs : NULL, prog_argv,
248                                   environ))
249              != 0))
250     {
251       if (actions_allocated)
252         posix_spawn_file_actions_destroy (&actions);
253       if (attrs_allocated)
254         posix_spawnattr_destroy (&attrs);
255       if (slave_process)
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);
260       return 127;
261     }
262   posix_spawn_file_actions_destroy (&actions);
263   if (attrs_allocated)
264     posix_spawnattr_destroy (&attrs);
265 #else
266   if (slave_process)
267     block_fatal_signals ();
268   /* Use vfork() instead of fork() for efficiency.  */
269   if ((child = vfork ()) == 0)
270     {
271       /* Child process code.  */
272       int nullinfd;
273       int nulloutfd;
274
275       if ((!null_stdin
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
282                   && (!null_stdout
283                       || nulloutfd == STDOUT_FILENO
284                       || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
285                   && (!null_stderr
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);
293       _exit (127);
294     }
295   if (child == -1)
296     {
297       if (slave_process)
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);
302       return 127;
303     }
304 #endif
305   if (slave_process)
306     {
307       register_slave_subprocess (child);
308       unblock_fatal_signals ();
309     }
310
311   return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
312                           slave_process, exit_on_error);
313
314 #endif
315 }