Mercurial > gnulib
annotate lib/execute.c @ 10197:d079dd7b69bc
Add termsigp argument to execute() and wait_process().
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Tue, 10 Jun 2008 17:38:39 +0200 |
parents | 1d443a80afc4 |
children | cb17877a6ccd |
rev | line source |
---|---|
4936 | 1 /* Creation of autonomous subprocesses. |
9721 | 2 Copyright (C) 2001-2004, 2006-2008 Free Software Foundation, Inc. |
4936 | 3 Written by Bruno Haible <haible@clisp.cons.org>, 2001. |
4 | |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8196
diff
changeset
|
5 This program is free software: you can redistribute it and/or modify |
4936 | 6 it under the terms of the GNU General Public License as published by |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8196
diff
changeset
|
7 the Free Software Foundation; either version 3 of the License, or |
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8196
diff
changeset
|
8 (at your option) any later version. |
4936 | 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 | |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8196
diff
changeset
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
4936 | 17 |
18 | |
7304
1c4ed7637c24
Include <config.h> unconditionally.
Bruno Haible <bruno@clisp.org>
parents:
6761
diff
changeset
|
19 #include <config.h> |
4936 | 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> | |
6751
1b0092424a44
Include <unistd.h> unconditionally.
Bruno Haible <bruno@clisp.org>
parents:
5848
diff
changeset
|
29 #include <unistd.h> |
4936 | 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. */ | |
8051
9c2b0396b27c
Stylistic change: Use '#if HAVE_*' instead of '#ifdef HAVE_*'.
Bruno Haible <bruno@clisp.org>
parents:
7863
diff
changeset
|
47 # if HAVE_POSIX_SPAWN |
4936 | 48 # include <spawn.h> |
49 # else | |
8051
9c2b0396b27c
Stylistic change: Use '#if HAVE_*' instead of '#ifdef HAVE_*'.
Bruno Haible <bruno@clisp.org>
parents:
7863
diff
changeset
|
50 # if HAVE_VFORK_H |
4936 | 51 # include <vfork.h> |
52 # endif | |
53 # endif | |
54 | |
55 #endif | |
56 | |
57 #ifndef STDIN_FILENO | |
58 # define STDIN_FILENO 0 | |
59 #endif | |
60 #ifndef STDOUT_FILENO | |
61 # define STDOUT_FILENO 1 | |
62 #endif | |
63 #ifndef STDERR_FILENO | |
64 # define STDERR_FILENO 2 | |
65 #endif | |
66 | |
7863 | 67 /* The results of open() in this file are not used with fchdir, |
68 therefore save some unnecessary work in fchdir.c. */ | |
69 #undef open | |
70 #undef close | |
71 | |
4936 | 72 |
73 #ifdef EINTR | |
74 | |
75 /* EINTR handling for close(), open(). | |
76 These functions can return -1/EINTR even though we don't have any | |
77 signal handlers set up, namely when we get interrupted via SIGSTOP. */ | |
78 | |
79 static inline int | |
80 nonintr_close (int fd) | |
81 { | |
82 int retval; | |
83 | |
84 do | |
85 retval = close (fd); | |
86 while (retval < 0 && errno == EINTR); | |
87 | |
88 return retval; | |
89 } | |
90 #define close nonintr_close | |
91 | |
92 static inline int | |
93 nonintr_open (const char *pathname, int oflag, mode_t mode) | |
94 { | |
95 int retval; | |
96 | |
97 do | |
98 retval = open (pathname, oflag, mode); | |
99 while (retval < 0 && errno == EINTR); | |
100 | |
101 return retval; | |
102 } | |
103 #undef open /* avoid warning on VMS */ | |
104 #define open nonintr_open | |
105 | |
106 #endif | |
107 | |
108 | |
109 /* Execute a command, optionally redirecting any of the three standard file | |
110 descriptors to /dev/null. Return its exit code. | |
111 If it didn't terminate correctly, exit if exit_on_error is true, otherwise | |
112 return 127. | |
113 If slave_process is true, the child process will be terminated when its | |
114 creator receives a catchable fatal signal. */ | |
115 int | |
116 execute (const char *progname, | |
117 const char *prog_path, char **prog_argv, | |
118 bool ignore_sigpipe, | |
119 bool null_stdin, bool null_stdout, bool null_stderr, | |
10197
d079dd7b69bc
Add termsigp argument to execute() and wait_process().
Bruno Haible <bruno@clisp.org>
parents:
9721
diff
changeset
|
120 bool slave_process, bool exit_on_error, |
d079dd7b69bc
Add termsigp argument to execute() and wait_process().
Bruno Haible <bruno@clisp.org>
parents:
9721
diff
changeset
|
121 int *termsigp) |
4936 | 122 { |
123 #if defined _MSC_VER || defined __MINGW32__ | |
124 | |
125 /* Native Woe32 API. */ | |
126 int orig_stdin; | |
127 int orig_stdout; | |
128 int orig_stderr; | |
129 int exitcode; | |
130 int nullinfd; | |
131 int nulloutfd; | |
132 | |
133 prog_argv = prepare_spawn (prog_argv); | |
134 | |
135 /* Save standard file handles of parent process. */ | |
136 if (null_stdin) | |
137 orig_stdin = dup_noinherit (STDIN_FILENO); | |
138 if (null_stdout) | |
139 orig_stdout = dup_noinherit (STDOUT_FILENO); | |
140 if (null_stderr) | |
141 orig_stderr = dup_noinherit (STDERR_FILENO); | |
142 exitcode = -1; | |
143 | |
144 /* Create standard file handles of child process. */ | |
145 nullinfd = -1; | |
146 nulloutfd = -1; | |
147 if ((!null_stdin | |
148 || ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0 | |
149 && (nullinfd == STDIN_FILENO | |
150 || (dup2 (nullinfd, STDIN_FILENO) >= 0 | |
151 && close (nullinfd) >= 0)))) | |
152 && (!(null_stdout || null_stderr) | |
153 || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0 | |
154 && (!null_stdout | |
155 || nulloutfd == STDOUT_FILENO | |
156 || dup2 (nulloutfd, STDOUT_FILENO) >= 0) | |
157 && (!null_stderr | |
158 || nulloutfd == STDERR_FILENO | |
159 || dup2 (nulloutfd, STDERR_FILENO) >= 0) | |
160 && ((null_stdout && nulloutfd == STDOUT_FILENO) | |
161 || (null_stderr && nulloutfd == STDERR_FILENO) | |
162 || close (nulloutfd) >= 0)))) | |
163 exitcode = spawnvp (P_WAIT, prog_path, prog_argv); | |
164 if (nulloutfd >= 0) | |
165 close (nulloutfd); | |
166 if (nullinfd >= 0) | |
167 close (nullinfd); | |
168 | |
169 /* Restore standard file handles of parent process. */ | |
170 if (null_stderr) | |
171 dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr); | |
172 if (null_stdout) | |
173 dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout); | |
174 if (null_stdin) | |
175 dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin); | |
176 | |
10197
d079dd7b69bc
Add termsigp argument to execute() and wait_process().
Bruno Haible <bruno@clisp.org>
parents:
9721
diff
changeset
|
177 if (termsigp != NULL) |
d079dd7b69bc
Add termsigp argument to execute() and wait_process().
Bruno Haible <bruno@clisp.org>
parents:
9721
diff
changeset
|
178 *termsigp = 0; |
d079dd7b69bc
Add termsigp argument to execute() and wait_process().
Bruno Haible <bruno@clisp.org>
parents:
9721
diff
changeset
|
179 |
4936 | 180 if (exitcode == -1) |
181 { | |
182 if (exit_on_error || !null_stderr) | |
183 error (exit_on_error ? EXIT_FAILURE : 0, errno, | |
184 _("%s subprocess failed"), progname); | |
185 return 127; | |
186 } | |
187 | |
188 return exitcode; | |
189 | |
190 #else | |
191 | |
192 /* Unix API. */ | |
193 /* Note about 127: Some errors during posix_spawnp() cause the function | |
194 posix_spawnp() to return an error code; some other errors cause the | |
195 subprocess to exit with return code 127. It is implementation | |
196 dependent which error is reported which way. We treat both cases as | |
197 equivalent. */ | |
198 #if HAVE_POSIX_SPAWN | |
199 sigset_t blocked_signals; | |
200 posix_spawn_file_actions_t actions; | |
201 bool actions_allocated; | |
202 posix_spawnattr_t attrs; | |
203 bool attrs_allocated; | |
204 int err; | |
205 pid_t child; | |
206 #else | |
207 int child; | |
208 #endif | |
209 | |
210 #if HAVE_POSIX_SPAWN | |
211 if (slave_process) | |
212 { | |
213 sigprocmask (SIG_SETMASK, NULL, &blocked_signals); | |
214 block_fatal_signals (); | |
215 } | |
216 actions_allocated = false; | |
217 attrs_allocated = false; | |
218 if ((err = posix_spawn_file_actions_init (&actions)) != 0 | |
219 || (actions_allocated = true, | |
220 (null_stdin | |
221 && (err = posix_spawn_file_actions_addopen (&actions, | |
222 STDIN_FILENO, | |
223 "/dev/null", O_RDONLY, | |
224 0)) | |
225 != 0) | |
226 || (null_stdout | |
227 && (err = posix_spawn_file_actions_addopen (&actions, | |
228 STDOUT_FILENO, | |
229 "/dev/null", O_RDWR, | |
230 0)) | |
231 != 0) | |
232 || (null_stderr | |
233 && (err = posix_spawn_file_actions_addopen (&actions, | |
234 STDERR_FILENO, | |
235 "/dev/null", O_RDWR, | |
236 0)) | |
237 != 0) | |
238 || (slave_process | |
239 && ((err = posix_spawnattr_init (&attrs)) != 0 | |
240 || (attrs_allocated = true, | |
241 (err = posix_spawnattr_setsigmask (&attrs, | |
242 &blocked_signals)) | |
243 != 0 | |
244 || (err = posix_spawnattr_setflags (&attrs, | |
245 POSIX_SPAWN_SETSIGMASK)) | |
246 != 0))) | |
247 || (err = posix_spawnp (&child, prog_path, &actions, | |
248 attrs_allocated ? &attrs : NULL, prog_argv, | |
249 environ)) | |
250 != 0)) | |
251 { | |
252 if (actions_allocated) | |
253 posix_spawn_file_actions_destroy (&actions); | |
254 if (attrs_allocated) | |
255 posix_spawnattr_destroy (&attrs); | |
256 if (slave_process) | |
257 unblock_fatal_signals (); | |
10197
d079dd7b69bc
Add termsigp argument to execute() and wait_process().
Bruno Haible <bruno@clisp.org>
parents:
9721
diff
changeset
|
258 if (termsigp != NULL) |
d079dd7b69bc
Add termsigp argument to execute() and wait_process().
Bruno Haible <bruno@clisp.org>
parents:
9721
diff
changeset
|
259 *termsigp = 0; |
4936 | 260 if (exit_on_error || !null_stderr) |
261 error (exit_on_error ? EXIT_FAILURE : 0, err, | |
262 _("%s subprocess failed"), progname); | |
263 return 127; | |
264 } | |
265 posix_spawn_file_actions_destroy (&actions); | |
266 if (attrs_allocated) | |
267 posix_spawnattr_destroy (&attrs); | |
268 #else | |
269 if (slave_process) | |
270 block_fatal_signals (); | |
271 /* Use vfork() instead of fork() for efficiency. */ | |
272 if ((child = vfork ()) == 0) | |
273 { | |
274 /* Child process code. */ | |
275 int nullinfd; | |
276 int nulloutfd; | |
277 | |
278 if ((!null_stdin | |
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 | |
285 && (!null_stdout | |
286 || nulloutfd == STDOUT_FILENO | |
287 || dup2 (nulloutfd, STDOUT_FILENO) >= 0) | |
288 && (!null_stderr | |
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); | |
296 _exit (127); | |
297 } | |
298 if (child == -1) | |
299 { | |
300 if (slave_process) | |
301 unblock_fatal_signals (); | |
10197
d079dd7b69bc
Add termsigp argument to execute() and wait_process().
Bruno Haible <bruno@clisp.org>
parents:
9721
diff
changeset
|
302 if (termsigp != NULL) |
d079dd7b69bc
Add termsigp argument to execute() and wait_process().
Bruno Haible <bruno@clisp.org>
parents:
9721
diff
changeset
|
303 *termsigp = 0; |
4936 | 304 if (exit_on_error || !null_stderr) |
305 error (exit_on_error ? EXIT_FAILURE : 0, errno, | |
306 _("%s subprocess failed"), progname); | |
307 return 127; | |
308 } | |
309 #endif | |
310 if (slave_process) | |
311 { | |
312 register_slave_subprocess (child); | |
313 unblock_fatal_signals (); | |
314 } | |
315 | |
6761
14eb5491c867
* lib/wait-process.c, lib/wait-process.h, lib/csharpcomp.c,
Derek R. Price <derek@ximbiot.com>
parents:
6759
diff
changeset
|
316 return wait_subprocess (child, progname, ignore_sigpipe, null_stderr, |
10197
d079dd7b69bc
Add termsigp argument to execute() and wait_process().
Bruno Haible <bruno@clisp.org>
parents:
9721
diff
changeset
|
317 slave_process, exit_on_error, termsigp); |
4936 | 318 |
319 #endif | |
320 } |