Mercurial > hg > octave-nkf > gnulib-hg
annotate lib/pipe.c @ 7292:17785d5bede0
Fix docstrings
author | Sergey Poznyakoff <gray@gnu.org.ua> |
---|---|
date | Sun, 10 Sep 2006 11:52:44 +0000 |
parents | 1b0092424a44 |
children | 1c4ed7637c24 |
rev | line source |
---|---|
4940 | 1 /* Creation of subprocesses, communicating via pipes. |
6751
1b0092424a44
Include <unistd.h> unconditionally.
Bruno Haible <bruno@clisp.org>
parents:
6259
diff
changeset
|
2 Copyright (C) 2001-2004, 2006 Free Software Foundation, Inc. |
4940 | 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, | |
5848
a48fb0e98c8c
*** empty log message ***
Paul Eggert <eggert@cs.ucla.edu>
parents:
5580
diff
changeset
|
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ |
4940 | 18 |
19 | |
20 #ifdef HAVE_CONFIG_H | |
6259
96c32553b4c6
Use a consistent style for including <config.h>.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
21 # include <config.h> |
4940 | 22 #endif |
23 | |
24 /* Specification. */ | |
25 #include "pipe.h" | |
26 | |
27 #include <errno.h> | |
28 #include <fcntl.h> | |
29 #include <stdlib.h> | |
30 #include <signal.h> | |
6751
1b0092424a44
Include <unistd.h> unconditionally.
Bruno Haible <bruno@clisp.org>
parents:
6259
diff
changeset
|
31 #include <unistd.h> |
4940 | 32 |
33 #include "error.h" | |
34 #include "exit.h" | |
35 #include "fatal-signal.h" | |
36 #include "wait-process.h" | |
37 #include "gettext.h" | |
38 | |
39 #define _(str) gettext (str) | |
40 | |
41 #if defined _MSC_VER || defined __MINGW32__ | |
42 | |
43 /* Native Woe32 API. */ | |
44 # include <process.h> | |
45 # include "w32spawn.h" | |
46 | |
47 #else | |
48 | |
49 /* Unix API. */ | |
50 # ifdef HAVE_POSIX_SPAWN | |
51 # include <spawn.h> | |
52 # else | |
53 # ifdef HAVE_VFORK_H | |
54 # include <vfork.h> | |
55 # endif | |
56 # endif | |
57 | |
58 #endif | |
59 | |
5580
19f7545b3c2b
Declare environ; not all systems declare it.
Bruno Haible <bruno@clisp.org>
parents:
4940
diff
changeset
|
60 #ifndef HAVE_ENVIRON_DECL |
19f7545b3c2b
Declare environ; not all systems declare it.
Bruno Haible <bruno@clisp.org>
parents:
4940
diff
changeset
|
61 extern char **environ; |
19f7545b3c2b
Declare environ; not all systems declare it.
Bruno Haible <bruno@clisp.org>
parents:
4940
diff
changeset
|
62 #endif |
19f7545b3c2b
Declare environ; not all systems declare it.
Bruno Haible <bruno@clisp.org>
parents:
4940
diff
changeset
|
63 |
4940 | 64 #ifndef STDIN_FILENO |
65 # define STDIN_FILENO 0 | |
66 #endif | |
67 #ifndef STDOUT_FILENO | |
68 # define STDOUT_FILENO 1 | |
69 #endif | |
70 #ifndef STDERR_FILENO | |
71 # define STDERR_FILENO 2 | |
72 #endif | |
73 | |
74 | |
75 #ifdef EINTR | |
76 | |
77 /* EINTR handling for close(). | |
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. */ | |
80 | |
81 static inline int | |
82 nonintr_close (int fd) | |
83 { | |
84 int retval; | |
85 | |
86 do | |
87 retval = close (fd); | |
88 while (retval < 0 && errno == EINTR); | |
89 | |
90 return retval; | |
91 } | |
92 #define close nonintr_close | |
93 | |
94 static inline int | |
95 nonintr_open (const char *pathname, int oflag, mode_t mode) | |
96 { | |
97 int retval; | |
98 | |
99 do | |
100 retval = open (pathname, oflag, mode); | |
101 while (retval < 0 && errno == EINTR); | |
102 | |
103 return retval; | |
104 } | |
105 #undef open /* avoid warning on VMS */ | |
106 #define open nonintr_open | |
107 | |
108 #endif | |
109 | |
110 | |
111 /* Open a pipe connected to a child process. | |
112 * | |
113 * write system read | |
114 * parent -> fd[1] -> STDIN_FILENO -> child if pipe_stdin | |
115 * parent <- fd[0] <- STDOUT_FILENO <- child if pipe_stdout | |
116 * read system write | |
117 * | |
118 * At least one of pipe_stdin, pipe_stdout must be true. | |
119 * pipe_stdin and prog_stdin together determine the child's standard input. | |
120 * pipe_stdout and prog_stdout together determine the child's standard output. | |
121 * If pipe_stdin is true, prog_stdin is ignored. | |
122 * If pipe_stdout is true, prog_stdout is ignored. | |
123 */ | |
124 static pid_t | |
125 create_pipe (const char *progname, | |
126 const char *prog_path, char **prog_argv, | |
127 bool pipe_stdin, bool pipe_stdout, | |
128 const char *prog_stdin, const char *prog_stdout, | |
129 bool null_stderr, | |
130 bool slave_process, bool exit_on_error, | |
131 int fd[2]) | |
132 { | |
133 #if defined _MSC_VER || defined __MINGW32__ | |
134 | |
135 /* Native Woe32 API. | |
136 This uses _pipe(), dup2(), and spawnv(). It could also be implemented | |
137 using the low-level functions CreatePipe(), DuplicateHandle(), | |
138 CreateProcess() and _open_osfhandle(); see the GNU make and GNU clisp | |
139 and cvs source code. */ | |
140 int ifd[2]; | |
141 int ofd[2]; | |
142 int orig_stdin; | |
143 int orig_stdout; | |
144 int orig_stderr; | |
145 int child; | |
146 int nulloutfd; | |
147 int stdinfd; | |
148 int stdoutfd; | |
149 | |
150 prog_argv = prepare_spawn (prog_argv); | |
151 | |
152 if (pipe_stdout) | |
153 if (_pipe (ifd, 4096, O_BINARY | O_NOINHERIT) < 0) | |
154 error (EXIT_FAILURE, errno, _("cannot create pipe")); | |
155 if (pipe_stdin) | |
156 if (_pipe (ofd, 4096, O_BINARY | O_NOINHERIT) < 0) | |
157 error (EXIT_FAILURE, errno, _("cannot create pipe")); | |
158 /* Data flow diagram: | |
159 * | |
160 * write system read | |
161 * parent -> ofd[1] -> ofd[0] -> child if pipe_stdin | |
162 * parent <- ifd[0] <- ifd[1] <- child if pipe_stdout | |
163 * read system write | |
164 * | |
165 */ | |
166 | |
167 /* Save standard file handles of parent process. */ | |
168 if (pipe_stdin || prog_stdin != NULL) | |
169 orig_stdin = dup_noinherit (STDIN_FILENO); | |
170 if (pipe_stdout || prog_stdout != NULL) | |
171 orig_stdout = dup_noinherit (STDOUT_FILENO); | |
172 if (null_stderr) | |
173 orig_stderr = dup_noinherit (STDERR_FILENO); | |
174 child = -1; | |
175 | |
176 /* Create standard file handles of child process. */ | |
177 nulloutfd = -1; | |
178 stdinfd = -1; | |
179 stdoutfd = -1; | |
180 if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0) | |
181 && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0) | |
182 && (!null_stderr | |
183 || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0 | |
184 && (nulloutfd == STDERR_FILENO | |
185 || (dup2 (nulloutfd, STDERR_FILENO) >= 0 | |
186 && close (nulloutfd) >= 0)))) | |
187 && (pipe_stdin | |
188 || prog_stdin == NULL | |
189 || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0 | |
190 && (stdinfd == STDIN_FILENO | |
191 || (dup2 (stdinfd, STDIN_FILENO) >= 0 | |
192 && close (stdinfd) >= 0)))) | |
193 && (pipe_stdout | |
194 || prog_stdout == NULL | |
195 || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0 | |
196 && (stdoutfd == STDOUT_FILENO | |
197 || (dup2 (stdoutfd, STDOUT_FILENO) >= 0 | |
198 && close (stdoutfd) >= 0))))) | |
199 /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1], | |
200 but it inherits all open()ed or dup2()ed file handles (which is what | |
201 we want in the case of STD*_FILENO) and also orig_stdin, | |
202 orig_stdout, orig_stderr (which is not explicitly wanted but | |
203 harmless). */ | |
204 child = spawnvp (P_NOWAIT, prog_path, prog_argv); | |
205 if (stdinfd >= 0) | |
206 close (stdinfd); | |
207 if (stdoutfd >= 0) | |
208 close (stdoutfd); | |
209 if (nulloutfd >= 0) | |
210 close (nulloutfd); | |
211 | |
212 /* Restore standard file handles of parent process. */ | |
213 if (null_stderr) | |
214 dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr); | |
215 if (pipe_stdout || prog_stdout != NULL) | |
216 dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout); | |
217 if (pipe_stdin || prog_stdin != NULL) | |
218 dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin); | |
219 | |
220 if (pipe_stdin) | |
221 close (ofd[0]); | |
222 if (pipe_stdout) | |
223 close (ifd[1]); | |
224 if (child == -1) | |
225 { | |
226 if (exit_on_error || !null_stderr) | |
227 error (exit_on_error ? EXIT_FAILURE : 0, errno, | |
228 _("%s subprocess failed"), progname); | |
229 if (pipe_stdout) | |
230 close (ifd[0]); | |
231 if (pipe_stdin) | |
232 close (ofd[1]); | |
233 return -1; | |
234 } | |
235 | |
236 if (pipe_stdout) | |
237 fd[0] = ifd[0]; | |
238 if (pipe_stdin) | |
239 fd[1] = ofd[1]; | |
240 return child; | |
241 | |
242 #else | |
243 | |
244 /* Unix API. */ | |
245 int ifd[2]; | |
246 int ofd[2]; | |
247 # if HAVE_POSIX_SPAWN | |
248 sigset_t blocked_signals; | |
249 posix_spawn_file_actions_t actions; | |
250 bool actions_allocated; | |
251 posix_spawnattr_t attrs; | |
252 bool attrs_allocated; | |
253 int err; | |
254 pid_t child; | |
255 # else | |
256 int child; | |
257 # endif | |
258 | |
259 if (pipe_stdout) | |
260 if (pipe (ifd) < 0) | |
261 error (EXIT_FAILURE, errno, _("cannot create pipe")); | |
262 if (pipe_stdin) | |
263 if (pipe (ofd) < 0) | |
264 error (EXIT_FAILURE, errno, _("cannot create pipe")); | |
265 /* Data flow diagram: | |
266 * | |
267 * write system read | |
268 * parent -> ofd[1] -> ofd[0] -> child if pipe_stdin | |
269 * parent <- ifd[0] <- ifd[1] <- child if pipe_stdout | |
270 * read system write | |
271 * | |
272 */ | |
273 | |
274 # if HAVE_POSIX_SPAWN | |
275 if (slave_process) | |
276 { | |
277 sigprocmask (SIG_SETMASK, NULL, &blocked_signals); | |
278 block_fatal_signals (); | |
279 } | |
280 actions_allocated = false; | |
281 attrs_allocated = false; | |
282 if ((err = posix_spawn_file_actions_init (&actions)) != 0 | |
283 || (actions_allocated = true, | |
284 (pipe_stdin | |
285 && (err = posix_spawn_file_actions_adddup2 (&actions, | |
286 ofd[0], STDIN_FILENO)) | |
287 != 0) | |
288 || (pipe_stdout | |
289 && (err = posix_spawn_file_actions_adddup2 (&actions, | |
290 ifd[1], STDOUT_FILENO)) | |
291 != 0) | |
292 || (pipe_stdin | |
293 && (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) | |
294 != 0) | |
295 || (pipe_stdout | |
296 && (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) | |
297 != 0) | |
298 || (pipe_stdin | |
299 && (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) | |
300 != 0) | |
301 || (pipe_stdout | |
302 && (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) | |
303 != 0) | |
304 || (null_stderr | |
305 && (err = posix_spawn_file_actions_addopen (&actions, | |
306 STDERR_FILENO, | |
307 "/dev/null", O_RDWR, | |
308 0)) | |
309 != 0) | |
310 || (!pipe_stdin | |
311 && prog_stdin != NULL | |
312 && (err = posix_spawn_file_actions_addopen (&actions, | |
313 STDIN_FILENO, | |
314 prog_stdin, O_RDONLY, | |
315 0)) | |
316 != 0) | |
317 || (!pipe_stdout | |
318 && prog_stdout != NULL | |
319 && (err = posix_spawn_file_actions_addopen (&actions, | |
320 STDOUT_FILENO, | |
321 prog_stdout, O_WRONLY, | |
322 0)) | |
323 != 0) | |
324 || (slave_process | |
325 && ((err = posix_spawnattr_init (&attrs)) != 0 | |
326 || (attrs_allocated = true, | |
327 (err = posix_spawnattr_setsigmask (&attrs, | |
328 &blocked_signals)) | |
329 != 0 | |
330 || (err = posix_spawnattr_setflags (&attrs, | |
331 POSIX_SPAWN_SETSIGMASK)) | |
332 != 0))) | |
333 || (err = posix_spawnp (&child, prog_path, &actions, | |
334 attrs_allocated ? &attrs : NULL, prog_argv, | |
335 environ)) | |
336 != 0)) | |
337 { | |
338 if (actions_allocated) | |
339 posix_spawn_file_actions_destroy (&actions); | |
340 if (attrs_allocated) | |
341 posix_spawnattr_destroy (&attrs); | |
342 if (slave_process) | |
343 unblock_fatal_signals (); | |
344 if (exit_on_error || !null_stderr) | |
345 error (exit_on_error ? EXIT_FAILURE : 0, err, | |
346 _("%s subprocess failed"), progname); | |
347 if (pipe_stdout) | |
348 { | |
349 close (ifd[0]); | |
350 close (ifd[1]); | |
351 } | |
352 if (pipe_stdin) | |
353 { | |
354 close (ofd[0]); | |
355 close (ofd[1]); | |
356 } | |
357 return -1; | |
358 } | |
359 posix_spawn_file_actions_destroy (&actions); | |
360 if (attrs_allocated) | |
361 posix_spawnattr_destroy (&attrs); | |
362 # else | |
363 if (slave_process) | |
364 block_fatal_signals (); | |
365 /* Use vfork() instead of fork() for efficiency. */ | |
366 if ((child = vfork ()) == 0) | |
367 { | |
368 /* Child process code. */ | |
369 int nulloutfd; | |
370 int stdinfd; | |
371 int stdoutfd; | |
372 | |
373 if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0) | |
374 && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0) | |
375 && (!pipe_stdin || close (ofd[0]) >= 0) | |
376 && (!pipe_stdout || close (ifd[1]) >= 0) | |
377 && (!pipe_stdin || close (ofd[1]) >= 0) | |
378 && (!pipe_stdout || close (ifd[0]) >= 0) | |
379 && (!null_stderr | |
380 || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0 | |
381 && (nulloutfd == STDERR_FILENO | |
382 || (dup2 (nulloutfd, STDERR_FILENO) >= 0 | |
383 && close (nulloutfd) >= 0)))) | |
384 && (pipe_stdin | |
385 || prog_stdin == NULL | |
386 || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0 | |
387 && (stdinfd == STDIN_FILENO | |
388 || (dup2 (stdinfd, STDIN_FILENO) >= 0 | |
389 && close (stdinfd) >= 0)))) | |
390 && (pipe_stdout | |
391 || prog_stdout == NULL | |
392 || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0 | |
393 && (stdoutfd == STDOUT_FILENO | |
394 || (dup2 (stdoutfd, STDOUT_FILENO) >= 0 | |
395 && close (stdoutfd) >= 0)))) | |
396 && (!slave_process || (unblock_fatal_signals (), true))) | |
397 execvp (prog_path, prog_argv); | |
398 _exit (127); | |
399 } | |
400 if (child == -1) | |
401 { | |
402 if (slave_process) | |
403 unblock_fatal_signals (); | |
404 if (exit_on_error || !null_stderr) | |
405 error (exit_on_error ? EXIT_FAILURE : 0, errno, | |
406 _("%s subprocess failed"), progname); | |
407 if (pipe_stdout) | |
408 { | |
409 close (ifd[0]); | |
410 close (ifd[1]); | |
411 } | |
412 if (pipe_stdin) | |
413 { | |
414 close (ofd[0]); | |
415 close (ofd[1]); | |
416 } | |
417 return -1; | |
418 } | |
419 # endif | |
420 if (slave_process) | |
421 { | |
422 register_slave_subprocess (child); | |
423 unblock_fatal_signals (); | |
424 } | |
425 if (pipe_stdin) | |
426 close (ofd[0]); | |
427 if (pipe_stdout) | |
428 close (ifd[1]); | |
429 | |
430 if (pipe_stdout) | |
431 fd[0] = ifd[0]; | |
432 if (pipe_stdin) | |
433 fd[1] = ofd[1]; | |
434 return child; | |
435 | |
436 #endif | |
437 } | |
438 | |
439 /* Open a bidirectional pipe. | |
440 * | |
441 * write system read | |
442 * parent -> fd[1] -> STDIN_FILENO -> child | |
443 * parent <- fd[0] <- STDOUT_FILENO <- child | |
444 * read system write | |
445 * | |
446 */ | |
447 pid_t | |
448 create_pipe_bidi (const char *progname, | |
449 const char *prog_path, char **prog_argv, | |
450 bool null_stderr, | |
451 bool slave_process, bool exit_on_error, | |
452 int fd[2]) | |
453 { | |
454 pid_t result = create_pipe (progname, prog_path, prog_argv, | |
455 true, true, NULL, NULL, | |
456 null_stderr, slave_process, exit_on_error, | |
457 fd); | |
458 return result; | |
459 } | |
460 | |
461 /* Open a pipe for input from a child process. | |
462 * The child's stdin comes from a file. | |
463 * | |
464 * read system write | |
465 * parent <- fd[0] <- STDOUT_FILENO <- child | |
466 * | |
467 */ | |
468 pid_t | |
469 create_pipe_in (const char *progname, | |
470 const char *prog_path, char **prog_argv, | |
471 const char *prog_stdin, bool null_stderr, | |
472 bool slave_process, bool exit_on_error, | |
473 int fd[1]) | |
474 { | |
475 int iofd[2]; | |
476 pid_t result = create_pipe (progname, prog_path, prog_argv, | |
477 false, true, prog_stdin, NULL, | |
478 null_stderr, slave_process, exit_on_error, | |
479 iofd); | |
480 if (result != -1) | |
481 fd[0] = iofd[0]; | |
482 return result; | |
483 } | |
484 | |
485 /* Open a pipe for output to a child process. | |
486 * The child's stdout goes to a file. | |
487 * | |
488 * write system read | |
489 * parent -> fd[0] -> STDIN_FILENO -> child | |
490 * | |
491 */ | |
492 pid_t | |
493 create_pipe_out (const char *progname, | |
494 const char *prog_path, char **prog_argv, | |
495 const char *prog_stdout, bool null_stderr, | |
496 bool slave_process, bool exit_on_error, | |
497 int fd[1]) | |
498 { | |
499 int iofd[2]; | |
500 pid_t result = create_pipe (progname, prog_path, prog_argv, | |
501 true, false, NULL, prog_stdout, | |
502 null_stderr, slave_process, exit_on_error, | |
503 iofd); | |
504 if (result != -1) | |
505 fd[0] = iofd[1]; | |
506 return result; | |
507 } |