1 /* Creation of subprocesses, communicating via pipes.
2 Copyright (C) 2001-2004, 2006-2021 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 <https://www.gnu.org/licenses/>. */
17
18
19 /* Tell clang not to warn about the 'child' variable, below. */
20 #if defined __clang__
21 # pragma clang diagnostic ignored "-Wconditional-uninitialized"
22 #endif
23
24 #include <config.h>
25
26 /* Specification. */
27 #include "spawn-pipe.h"
28
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdlib.h>
32 #include <signal.h>
33 #include <unistd.h>
34
35 #include "canonicalize.h"
36 #include "error.h"
37 #include "fatal-signal.h"
38 #include "filename.h"
39 #include "findprog.h"
40 #include "unistd-safer.h"
41 #include "wait-process.h"
42 #include "xalloc.h"
43 #include "gettext.h"
44
45 #define _(str) gettext (str)
46
47
48 /* Choice of implementation for native Windows.
49 - Define to 0 to use the posix_spawn facility (modules 'posix_spawn' and
50 'posix_spawnp'), that is based on the module 'windows-spawn'.
51 - Define to 1 to use the older code, that uses the module 'windows-spawn'
52 directly.
53 You can set this macro from a Makefile or at configure time, from the
54 CPPFLAGS. */
55 #ifndef SPAWN_PIPE_IMPL_AVOID_POSIX_SPAWN
56 # define SPAWN_PIPE_IMPL_AVOID_POSIX_SPAWN 0
57 #endif
58
59
60 #if (defined _WIN32 && !defined __CYGWIN__) && SPAWN_PIPE_IMPL_AVOID_POSIX_SPAWN
61
62 /* Native Windows API. */
63 # if GNULIB_MSVC_NOTHROW
64 # include "msvc-nothrow.h"
65 # else
66 # include <io.h>
67 # endif
68 # include <process.h>
69 # include "windows-spawn.h"
70
71 #elif defined __KLIBC__
72
73 /* OS/2 kLIBC API. */
74 # include <process.h>
75 # include "os2-spawn.h"
76
77 #else
78
79 /* Unix API. */
80 # include <spawn.h>
81
82 #endif
83
84
85 #ifdef EINTR
86
87 /* EINTR handling for close().
88 These functions can return -1/EINTR even though we don't have any
89 signal handlers set up, namely when we get interrupted via SIGSTOP. */
90
91 static int
nonintr_close(int fd)92 nonintr_close (int fd)
93 {
94 int retval;
95
96 do
97 retval = close (fd);
98 while (retval < 0 && errno == EINTR);
99
100 return retval;
101 }
102 #undef close /* avoid warning related to gnulib module unistd */
103 #define close nonintr_close
104
105 #if (defined _WIN32 && !defined __CYGWIN__) && SPAWN_PIPE_IMPL_AVOID_POSIX_SPAWN
106 static int
nonintr_open(const char * pathname,int oflag,mode_t mode)107 nonintr_open (const char *pathname, int oflag, mode_t mode)
108 {
109 int retval;
110
111 do
112 retval = open (pathname, oflag, mode);
113 while (retval < 0 && errno == EINTR);
114
115 return retval;
116 }
117 # undef open /* avoid warning on VMS */
118 # define open nonintr_open
119 #endif
120
121 #endif
122
123
124 /* Open a pipe connected to a child process.
125 *
126 * write system read
127 * parent -> fd[1] -> STDIN_FILENO -> child if pipe_stdin
128 * parent <- fd[0] <- STDOUT_FILENO <- child if pipe_stdout
129 * read system write
130 *
131 * At least one of pipe_stdin, pipe_stdout must be true.
132 * pipe_stdin and prog_stdin together determine the child's standard input.
133 * pipe_stdout and prog_stdout together determine the child's standard output.
134 * If pipe_stdin is true, prog_stdin is ignored.
135 * If pipe_stdout is true, prog_stdout is ignored.
136 */
137 static pid_t
create_pipe(const char * progname,const char * prog_path,const char * const * prog_argv,const char * directory,bool pipe_stdin,bool pipe_stdout,const char * prog_stdin,const char * prog_stdout,bool null_stderr,bool slave_process,bool exit_on_error,int fd[2])138 create_pipe (const char *progname,
139 const char *prog_path,
140 const char * const *prog_argv,
141 const char *directory,
142 bool pipe_stdin, bool pipe_stdout,
143 const char *prog_stdin, const char *prog_stdout,
144 bool null_stderr,
145 bool slave_process, bool exit_on_error,
146 int fd[2])
147 {
148 int saved_errno;
149 char *prog_path_to_free = NULL;
150
151 if (directory != NULL)
152 {
153 /* If a change of directory is requested, make sure PROG_PATH is absolute
154 before we do so. This is needed because
155 - posix_spawn and posix_spawnp are required to resolve a relative
156 PROG_PATH *after* changing the directory. See
157 <https://www.austingroupbugs.net/view.php?id=1208>:
158 "if this pathname does not start with a <slash> it shall be
159 interpreted relative to the working directory of the child
160 process _after_ all file_actions have been performed."
161 But this would be a surprising application behaviour, possibly
162 even security relevant.
163 - For the Windows CreateProcess() function, it is unspecified whether
164 a relative file name is interpreted to the parent's current
165 directory or to the specified directory. See
166 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
167 if (! IS_ABSOLUTE_FILE_NAME (prog_path))
168 {
169 const char *resolved_prog =
170 find_in_given_path (prog_path, getenv ("PATH"), NULL, false);
171 if (resolved_prog == NULL)
172 goto fail_with_errno;
173 if (resolved_prog != prog_path)
174 prog_path_to_free = (char *) resolved_prog;
175 prog_path = resolved_prog;
176
177 if (! IS_ABSOLUTE_FILE_NAME (prog_path))
178 {
179 char *absolute_prog =
180 canonicalize_filename_mode (prog_path, CAN_MISSING | CAN_NOLINKS);
181 if (absolute_prog == NULL)
182 {
183 saved_errno = errno;
184 free (prog_path_to_free);
185 goto fail_with_saved_errno;
186 }
187 free (prog_path_to_free);
188 prog_path_to_free = absolute_prog;
189 prog_path = absolute_prog;
190
191 if (! IS_ABSOLUTE_FILE_NAME (prog_path))
192 abort ();
193 }
194 }
195 }
196
197 #if ((defined _WIN32 && !defined __CYGWIN__) && SPAWN_PIPE_IMPL_AVOID_POSIX_SPAWN) || defined __KLIBC__
198
199 /* Native Windows API.
200 This uses _pipe(), dup2(), and _spawnv(). It could also be implemented
201 using the low-level functions CreatePipe(), DuplicateHandle(),
202 CreateProcess() and _open_osfhandle(); see the GNU make and GNU clisp
203 and cvs source code. */
204 char *argv_mem_to_free;
205 int ifd[2];
206 int ofd[2];
207 int child;
208 int nulloutfd;
209 int stdinfd;
210 int stdoutfd;
211
212 const char **argv = prepare_spawn (prog_argv, &argv_mem_to_free);
213 if (argv == NULL)
214 xalloc_die ();
215
216 if (pipe_stdout)
217 if (pipe2_safer (ifd, O_BINARY | O_CLOEXEC) < 0)
218 error (EXIT_FAILURE, errno, _("cannot create pipe"));
219 if (pipe_stdin)
220 if (pipe2_safer (ofd, O_BINARY | O_CLOEXEC) < 0)
221 error (EXIT_FAILURE, errno, _("cannot create pipe"));
222 /* Data flow diagram:
223 *
224 * write system read
225 * parent -> ofd[1] -> ofd[0] -> child if pipe_stdin
226 * parent <- ifd[0] <- ifd[1] <- child if pipe_stdout
227 * read system write
228 *
229 */
230
231 child = -1;
232
233 # if (defined _WIN32 && !defined __CYGWIN__) && SPAWN_PIPE_IMPL_AVOID_POSIX_SPAWN
234 bool must_close_ifd1 = pipe_stdout;
235 bool must_close_ofd0 = pipe_stdin;
236
237 /* Create standard file handles of child process. */
238 HANDLE stdin_handle = INVALID_HANDLE_VALUE;
239 HANDLE stdout_handle = INVALID_HANDLE_VALUE;
240 nulloutfd = -1;
241 stdinfd = -1;
242 stdoutfd = -1;
243 if ((!null_stderr
244 || (nulloutfd = open ("NUL", O_RDWR, 0)) >= 0)
245 && (pipe_stdin
246 || prog_stdin == NULL
247 || (stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0)
248 && (pipe_stdout
249 || prog_stdout == NULL
250 || (stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0))
251 /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
252 but it inherits the three STD*_FILENO for which we pass the handles. */
253 /* Pass the environment explicitly. This is needed if the program has
254 modified the environment using putenv() or [un]setenv(). On Windows,
255 processes have two environments, one in the "environment block" of the
256 process and managed through SetEnvironmentVariable(), and one inside the
257 process, in the location retrieved by the 'environ' macro. If we were
258 to pass NULL, the child process would inherit a copy of the environment
259 block - ignoring the effects of putenv() and [un]setenv(). */
260 {
261 stdin_handle =
262 (HANDLE) _get_osfhandle (pipe_stdin ? ofd[0] :
263 prog_stdin == NULL ? STDIN_FILENO : stdinfd);
264 if (pipe_stdin)
265 {
266 HANDLE curr_process = GetCurrentProcess ();
267 HANDLE duplicate;
268 if (!DuplicateHandle (curr_process, stdin_handle,
269 curr_process, &duplicate,
270 0, TRUE, DUPLICATE_SAME_ACCESS))
271 {
272 errno = EBADF; /* arbitrary */
273 goto failed;
274 }
275 must_close_ofd0 = false;
276 close (ofd[0]); /* implies CloseHandle (stdin_handle); */
277 stdin_handle = duplicate;
278 }
279 stdout_handle =
280 (HANDLE) _get_osfhandle (pipe_stdout ? ifd[1] :
281 prog_stdout == NULL ? STDOUT_FILENO : stdoutfd);
282 if (pipe_stdout)
283 {
284 HANDLE curr_process = GetCurrentProcess ();
285 HANDLE duplicate;
286 if (!DuplicateHandle (curr_process, stdout_handle,
287 curr_process, &duplicate,
288 0, TRUE, DUPLICATE_SAME_ACCESS))
289 {
290 errno = EBADF; /* arbitrary */
291 goto failed;
292 }
293 must_close_ifd1 = false;
294 close (ifd[1]); /* implies CloseHandle (stdout_handle); */
295 stdout_handle = duplicate;
296 }
297 HANDLE stderr_handle =
298 (HANDLE) _get_osfhandle (null_stderr ? nulloutfd : STDERR_FILENO);
299
300 child = spawnpvech (P_NOWAIT, prog_path, argv + 1,
301 (const char * const *) environ, directory,
302 stdin_handle, stdout_handle, stderr_handle);
303 # if 0 /* Executing arbitrary files as shell scripts is unsecure. */
304 if (child == -1 && errno == ENOEXEC)
305 {
306 /* prog is not a native executable. Try to execute it as a
307 shell script. Note that prepare_spawn() has already prepended
308 a hidden element "sh.exe" to argv. */
309 argv[1] = prog_path;
310 child = spawnpvech (P_NOWAIT, argv[0], argv,
311 (const char * const *) environ, directory,
312 stdin_handle, stdout_handle, stderr_handle);
313 }
314 # endif
315 }
316 failed:
317 if (child == -1)
318 saved_errno = errno;
319 if (stdinfd >= 0)
320 close (stdinfd);
321 if (stdoutfd >= 0)
322 close (stdoutfd);
323 if (nulloutfd >= 0)
324 close (nulloutfd);
325
326 if (pipe_stdin)
327 {
328 if (must_close_ofd0)
329 close (ofd[0]);
330 else
331 if (stdin_handle != INVALID_HANDLE_VALUE)
332 CloseHandle (stdin_handle);
333 }
334 if (pipe_stdout)
335 {
336 if (must_close_ifd1)
337 close (ifd[1]);
338 else
339 if (stdout_handle != INVALID_HANDLE_VALUE)
340 CloseHandle (stdout_handle);
341 }
342
343 # else /* __KLIBC__ */
344 if (!(directory == NULL || strcmp (directory, ".") == 0))
345 {
346 /* A directory argument is not supported in this implementation. */
347 saved_errno = EINVAL;
348 goto fail_with_saved_errno;
349 }
350
351 int orig_stdin;
352 int orig_stdout;
353 int orig_stderr;
354
355 /* Save standard file handles of parent process. */
356 if (pipe_stdin || prog_stdin != NULL)
357 orig_stdin = dup_safer_noinherit (STDIN_FILENO);
358 if (pipe_stdout || prog_stdout != NULL)
359 orig_stdout = dup_safer_noinherit (STDOUT_FILENO);
360 if (null_stderr)
361 orig_stderr = dup_safer_noinherit (STDERR_FILENO);
362
363 /* Create standard file handles of child process. */
364 nulloutfd = -1;
365 stdinfd = -1;
366 stdoutfd = -1;
367 if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
368 && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
369 && (!null_stderr
370 || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
371 && (nulloutfd == STDERR_FILENO
372 || (dup2 (nulloutfd, STDERR_FILENO) >= 0
373 && close (nulloutfd) >= 0))))
374 && (pipe_stdin
375 || prog_stdin == NULL
376 || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
377 && (stdinfd == STDIN_FILENO
378 || (dup2 (stdinfd, STDIN_FILENO) >= 0
379 && close (stdinfd) >= 0))))
380 && (pipe_stdout
381 || prog_stdout == NULL
382 || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
383 && (stdoutfd == STDOUT_FILENO
384 || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
385 && close (stdoutfd) >= 0)))))
386 /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
387 but it inherits all open()ed or dup2()ed file handles (which is what
388 we want in the case of STD*_FILENO). */
389 {
390 child = _spawnvpe (P_NOWAIT, prog_path, argv + 1,
391 (const char **) environ);
392 # if 0 /* Executing arbitrary files as shell scripts is unsecure. */
393 if (child == -1 && errno == ENOEXEC)
394 {
395 /* prog is not a native executable. Try to execute it as a
396 shell script. Note that prepare_spawn() has already prepended
397 a hidden element "sh.exe" to argv. */
398 child = _spawnvpe (P_NOWAIT, argv[0], argv,
399 (const char **) environ);
400 }
401 # endif
402 }
403 if (child == -1)
404 saved_errno = errno;
405 if (stdinfd >= 0)
406 close (stdinfd);
407 if (stdoutfd >= 0)
408 close (stdoutfd);
409 if (nulloutfd >= 0)
410 close (nulloutfd);
411
412 /* Restore standard file handles of parent process. */
413 if (null_stderr)
414 undup_safer_noinherit (orig_stderr, STDERR_FILENO);
415 if (pipe_stdout || prog_stdout != NULL)
416 undup_safer_noinherit (orig_stdout, STDOUT_FILENO);
417 if (pipe_stdin || prog_stdin != NULL)
418 undup_safer_noinherit (orig_stdin, STDIN_FILENO);
419
420 if (pipe_stdin)
421 close (ofd[0]);
422 if (pipe_stdout)
423 close (ifd[1]);
424 # endif
425
426 free (argv);
427 free (argv_mem_to_free);
428 free (prog_path_to_free);
429
430 if (child == -1)
431 {
432 if (pipe_stdout)
433 close (ifd[0]);
434 if (pipe_stdin)
435 close (ofd[1]);
436 goto fail_with_saved_errno;
437 }
438
439 if (pipe_stdout)
440 fd[0] = ifd[0];
441 if (pipe_stdin)
442 fd[1] = ofd[1];
443 return child;
444
445 #else
446
447 /* Unix API. */
448 int ifd[2];
449 int ofd[2];
450 sigset_t blocked_signals;
451 posix_spawn_file_actions_t actions;
452 bool actions_allocated;
453 posix_spawnattr_t attrs;
454 bool attrs_allocated;
455 int err;
456 pid_t child;
457
458 if (pipe_stdout)
459 if (pipe_safer (ifd) < 0)
460 error (EXIT_FAILURE, errno, _("cannot create pipe"));
461 if (pipe_stdin)
462 if (pipe_safer (ofd) < 0)
463 error (EXIT_FAILURE, errno, _("cannot create pipe"));
464 /* Data flow diagram:
465 *
466 * write system read
467 * parent -> ofd[1] -> ofd[0] -> child if pipe_stdin
468 * parent <- ifd[0] <- ifd[1] <- child if pipe_stdout
469 * read system write
470 *
471 */
472
473 if (slave_process)
474 {
475 sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
476 block_fatal_signals ();
477 }
478 actions_allocated = false;
479 attrs_allocated = false;
480 if ((err = posix_spawn_file_actions_init (&actions)) != 0
481 || (actions_allocated = true,
482 (pipe_stdin
483 && (err = posix_spawn_file_actions_adddup2 (&actions,
484 ofd[0], STDIN_FILENO))
485 != 0)
486 || (pipe_stdout
487 && (err = posix_spawn_file_actions_adddup2 (&actions,
488 ifd[1], STDOUT_FILENO))
489 != 0)
490 || (pipe_stdin
491 && (err = posix_spawn_file_actions_addclose (&actions, ofd[0]))
492 != 0)
493 || (pipe_stdout
494 && (err = posix_spawn_file_actions_addclose (&actions, ifd[1]))
495 != 0)
496 || (pipe_stdin
497 && (err = posix_spawn_file_actions_addclose (&actions, ofd[1]))
498 != 0)
499 || (pipe_stdout
500 && (err = posix_spawn_file_actions_addclose (&actions, ifd[0]))
501 != 0)
502 || (null_stderr
503 && (err = posix_spawn_file_actions_addopen (&actions,
504 STDERR_FILENO,
505 "/dev/null", O_RDWR,
506 0))
507 != 0)
508 || (!pipe_stdin
509 && prog_stdin != NULL
510 && (err = posix_spawn_file_actions_addopen (&actions,
511 STDIN_FILENO,
512 prog_stdin, O_RDONLY,
513 0))
514 != 0)
515 || (!pipe_stdout
516 && prog_stdout != NULL
517 && (err = posix_spawn_file_actions_addopen (&actions,
518 STDOUT_FILENO,
519 prog_stdout, O_WRONLY,
520 0))
521 != 0)
522 || (directory != NULL
523 && (err = posix_spawn_file_actions_addchdir (&actions,
524 directory)))
525 || (slave_process
526 && ((err = posix_spawnattr_init (&attrs)) != 0
527 || (attrs_allocated = true,
528 # if defined _WIN32 && !defined __CYGWIN__
529 (err = posix_spawnattr_setpgroup (&attrs, 0)) != 0
530 || (err = posix_spawnattr_setflags (&attrs,
531 POSIX_SPAWN_SETPGROUP))
532 != 0
533 # else
534 (err = posix_spawnattr_setsigmask (&attrs,
535 &blocked_signals))
536 != 0
537 || (err = posix_spawnattr_setflags (&attrs,
538 POSIX_SPAWN_SETSIGMASK))
539 != 0
540 # endif
541 ) ) )
542 || (err = (directory != NULL
543 ? posix_spawn (&child, prog_path, &actions,
544 attrs_allocated ? &attrs : NULL,
545 (char * const *) prog_argv, environ)
546 : posix_spawnp (&child, prog_path, &actions,
547 attrs_allocated ? &attrs : NULL,
548 (char * const *) prog_argv, environ)))
549 != 0))
550 {
551 if (actions_allocated)
552 posix_spawn_file_actions_destroy (&actions);
553 if (attrs_allocated)
554 posix_spawnattr_destroy (&attrs);
555 if (slave_process)
556 unblock_fatal_signals ();
557 if (pipe_stdout)
558 {
559 close (ifd[0]);
560 close (ifd[1]);
561 }
562 if (pipe_stdin)
563 {
564 close (ofd[0]);
565 close (ofd[1]);
566 }
567 free (prog_path_to_free);
568 saved_errno = err;
569 goto fail_with_saved_errno;
570 }
571 posix_spawn_file_actions_destroy (&actions);
572 if (attrs_allocated)
573 posix_spawnattr_destroy (&attrs);
574 if (slave_process)
575 {
576 register_slave_subprocess (child);
577 unblock_fatal_signals ();
578 }
579 if (pipe_stdin)
580 close (ofd[0]);
581 if (pipe_stdout)
582 close (ifd[1]);
583 free (prog_path_to_free);
584
585 if (pipe_stdout)
586 fd[0] = ifd[0];
587 if (pipe_stdin)
588 fd[1] = ofd[1];
589 return child;
590
591 #endif
592
593 fail_with_errno:
594 saved_errno = errno;
595 fail_with_saved_errno:
596 if (exit_on_error || !null_stderr)
597 error (exit_on_error ? EXIT_FAILURE : 0, saved_errno,
598 _("%s subprocess failed"), progname);
599 errno = saved_errno;
600 return -1;
601 }
602
603 /* Open a bidirectional pipe.
604 *
605 * write system read
606 * parent -> fd[1] -> STDIN_FILENO -> child
607 * parent <- fd[0] <- STDOUT_FILENO <- child
608 * read system write
609 *
610 */
611 pid_t
create_pipe_bidi(const char * progname,const char * prog_path,const char * const * prog_argv,const char * directory,bool null_stderr,bool slave_process,bool exit_on_error,int fd[2])612 create_pipe_bidi (const char *progname,
613 const char *prog_path, const char * const *prog_argv,
614 const char *directory,
615 bool null_stderr,
616 bool slave_process, bool exit_on_error,
617 int fd[2])
618 {
619 pid_t result = create_pipe (progname, prog_path, prog_argv, directory,
620 true, true, NULL, NULL,
621 null_stderr, slave_process, exit_on_error,
622 fd);
623 return result;
624 }
625
626 /* Open a pipe for input from a child process.
627 * The child's stdin comes from a file.
628 *
629 * read system write
630 * parent <- fd[0] <- STDOUT_FILENO <- child
631 *
632 */
633 pid_t
create_pipe_in(const char * progname,const char * prog_path,const char * const * prog_argv,const char * directory,const char * prog_stdin,bool null_stderr,bool slave_process,bool exit_on_error,int fd[1])634 create_pipe_in (const char *progname,
635 const char *prog_path, const char * const *prog_argv,
636 const char *directory,
637 const char *prog_stdin, bool null_stderr,
638 bool slave_process, bool exit_on_error,
639 int fd[1])
640 {
641 int iofd[2];
642 pid_t result = create_pipe (progname, prog_path, prog_argv, directory,
643 false, true, prog_stdin, NULL,
644 null_stderr, slave_process, exit_on_error,
645 iofd);
646 if (result != -1)
647 fd[0] = iofd[0];
648 return result;
649 }
650
651 /* Open a pipe for output to a child process.
652 * The child's stdout goes to a file.
653 *
654 * write system read
655 * parent -> fd[0] -> STDIN_FILENO -> child
656 *
657 */
658 pid_t
create_pipe_out(const char * progname,const char * prog_path,const char * const * prog_argv,const char * directory,const char * prog_stdout,bool null_stderr,bool slave_process,bool exit_on_error,int fd[1])659 create_pipe_out (const char *progname,
660 const char *prog_path, const char * const *prog_argv,
661 const char *directory,
662 const char *prog_stdout, bool null_stderr,
663 bool slave_process, bool exit_on_error,
664 int fd[1])
665 {
666 int iofd[2];
667 pid_t result = create_pipe (progname, prog_path, prog_argv, directory,
668 true, false, NULL, prog_stdout,
669 null_stderr, slave_process, exit_on_error,
670 iofd);
671 if (result != -1)
672 fd[0] = iofd[1];
673 return result;
674 }
675