Bump to m4 1.4.19
[platform/upstream/m4.git] / lib / spawn-pipe.c
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
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
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
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                   free (prog_path_to_free);
184                   goto fail_with_errno;
185                 }
186               free (prog_path_to_free);
187               prog_path_to_free = absolute_prog;
188               prog_path = absolute_prog;
189
190               if (! IS_ABSOLUTE_FILE_NAME (prog_path))
191                 abort ();
192             }
193         }
194     }
195
196 #if ((defined _WIN32 && !defined __CYGWIN__) && SPAWN_PIPE_IMPL_AVOID_POSIX_SPAWN) || defined __KLIBC__
197
198   /* Native Windows API.
199      This uses _pipe(), dup2(), and _spawnv().  It could also be implemented
200      using the low-level functions CreatePipe(), DuplicateHandle(),
201      CreateProcess() and _open_osfhandle(); see the GNU make and GNU clisp
202      and cvs source code.  */
203   char *argv_mem_to_free;
204   int ifd[2];
205   int ofd[2];
206   int child;
207   int nulloutfd;
208   int stdinfd;
209   int stdoutfd;
210
211   const char **argv = prepare_spawn (prog_argv, &argv_mem_to_free);
212   if (argv == NULL)
213     xalloc_die ();
214
215   if (pipe_stdout)
216     if (pipe2_safer (ifd, O_BINARY | O_CLOEXEC) < 0)
217       error (EXIT_FAILURE, errno, _("cannot create pipe"));
218   if (pipe_stdin)
219     if (pipe2_safer (ofd, O_BINARY | O_CLOEXEC) < 0)
220       error (EXIT_FAILURE, errno, _("cannot create pipe"));
221 /* Data flow diagram:
222  *
223  *           write        system         read
224  *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
225  *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
226  *           read         system         write
227  *
228  */
229
230   child = -1;
231
232 # if (defined _WIN32 && !defined __CYGWIN__) && SPAWN_PIPE_IMPL_AVOID_POSIX_SPAWN
233   bool must_close_ifd1 = pipe_stdout;
234   bool must_close_ofd0 = pipe_stdin;
235
236   /* Create standard file handles of child process.  */
237   HANDLE stdin_handle = INVALID_HANDLE_VALUE;
238   HANDLE stdout_handle = INVALID_HANDLE_VALUE;
239   nulloutfd = -1;
240   stdinfd = -1;
241   stdoutfd = -1;
242   if ((!null_stderr
243        || (nulloutfd = open ("NUL", O_RDWR, 0)) >= 0)
244       && (pipe_stdin
245           || prog_stdin == NULL
246           || (stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0)
247       && (pipe_stdout
248           || prog_stdout == NULL
249           || (stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0))
250     /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
251        but it inherits the three STD*_FILENO for which we pass the handles.  */
252     /* Pass the environment explicitly.  This is needed if the program has
253        modified the environment using putenv() or [un]setenv().  On Windows,
254        processes have two environments, one in the "environment block" of the
255        process and managed through SetEnvironmentVariable(), and one inside the
256        process, in the location retrieved by the 'environ' macro.  If we were
257        to pass NULL, the child process would inherit a copy of the environment
258        block - ignoring the effects of putenv() and [un]setenv().  */
259     {
260       stdin_handle =
261         (HANDLE) _get_osfhandle (pipe_stdin ? ofd[0] :
262                                  prog_stdin == NULL ? STDIN_FILENO : stdinfd);
263       if (pipe_stdin)
264         {
265           HANDLE curr_process = GetCurrentProcess ();
266           HANDLE duplicate;
267           if (!DuplicateHandle (curr_process, stdin_handle,
268                                 curr_process, &duplicate,
269                                 0, TRUE, DUPLICATE_SAME_ACCESS))
270             {
271               errno = EBADF; /* arbitrary */
272               goto failed;
273             }
274           must_close_ofd0 = false;
275           close (ofd[0]); /* implies CloseHandle (stdin_handle); */
276           stdin_handle = duplicate;
277         }
278       stdout_handle =
279         (HANDLE) _get_osfhandle (pipe_stdout ? ifd[1] :
280                                  prog_stdout == NULL ? STDOUT_FILENO : stdoutfd);
281       if (pipe_stdout)
282         {
283           HANDLE curr_process = GetCurrentProcess ();
284           HANDLE duplicate;
285           if (!DuplicateHandle (curr_process, stdout_handle,
286                                 curr_process, &duplicate,
287                                 0, TRUE, DUPLICATE_SAME_ACCESS))
288             {
289               errno = EBADF; /* arbitrary */
290               goto failed;
291             }
292           must_close_ifd1 = false;
293           close (ifd[1]); /* implies CloseHandle (stdout_handle); */
294           stdout_handle = duplicate;
295         }
296       HANDLE stderr_handle =
297         (HANDLE) _get_osfhandle (null_stderr ? nulloutfd : STDERR_FILENO);
298
299       child = spawnpvech (P_NOWAIT, prog_path, argv + 1,
300                           (const char * const *) environ, directory,
301                           stdin_handle, stdout_handle, stderr_handle);
302 #  if 0 /* Executing arbitrary files as shell scripts is unsecure.  */
303       if (child == -1 && errno == ENOEXEC)
304         {
305           /* prog is not a native executable.  Try to execute it as a
306              shell script.  Note that prepare_spawn() has already prepended
307              a hidden element "sh.exe" to argv.  */
308           argv[1] = prog_path;
309           child = spawnpvech (P_NOWAIT, argv[0], argv,
310                               (const char * const *) environ, directory,
311                               stdin_handle, stdout_handle, stderr_handle);
312         }
313 #  endif
314     }
315  failed:
316   if (child == -1)
317     saved_errno = errno;
318   if (stdinfd >= 0)
319     close (stdinfd);
320   if (stdoutfd >= 0)
321     close (stdoutfd);
322   if (nulloutfd >= 0)
323     close (nulloutfd);
324
325   if (pipe_stdin)
326     {
327       if (must_close_ofd0)
328         close (ofd[0]);
329       else
330         if (stdin_handle != INVALID_HANDLE_VALUE)
331           CloseHandle (stdin_handle);
332     }
333   if (pipe_stdout)
334     {
335       if (must_close_ifd1)
336         close (ifd[1]);
337       else
338         if (stdout_handle != INVALID_HANDLE_VALUE)
339           CloseHandle (stdout_handle);
340     }
341
342 # else /* __KLIBC__ */
343   if (!(directory == NULL || strcmp (directory, ".") == 0))
344     {
345       /* A directory argument is not supported in this implementation.  */
346       saved_errno = EINVAL;
347       goto fail_with_saved_errno;
348     }
349
350   int orig_stdin;
351   int orig_stdout;
352   int orig_stderr;
353
354   /* Save standard file handles of parent process.  */
355   if (pipe_stdin || prog_stdin != NULL)
356     orig_stdin = dup_safer_noinherit (STDIN_FILENO);
357   if (pipe_stdout || prog_stdout != NULL)
358     orig_stdout = dup_safer_noinherit (STDOUT_FILENO);
359   if (null_stderr)
360     orig_stderr = dup_safer_noinherit (STDERR_FILENO);
361
362   /* Create standard file handles of child process.  */
363   nulloutfd = -1;
364   stdinfd = -1;
365   stdoutfd = -1;
366   if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
367       && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
368       && (!null_stderr
369           || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
370               && (nulloutfd == STDERR_FILENO
371                   || (dup2 (nulloutfd, STDERR_FILENO) >= 0
372                       && close (nulloutfd) >= 0))))
373       && (pipe_stdin
374           || prog_stdin == NULL
375           || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
376               && (stdinfd == STDIN_FILENO
377                   || (dup2 (stdinfd, STDIN_FILENO) >= 0
378                       && close (stdinfd) >= 0))))
379       && (pipe_stdout
380           || prog_stdout == NULL
381           || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
382               && (stdoutfd == STDOUT_FILENO
383                   || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
384                       && close (stdoutfd) >= 0)))))
385     /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
386        but it inherits all open()ed or dup2()ed file handles (which is what
387        we want in the case of STD*_FILENO).  */
388     {
389       child = _spawnvpe (P_NOWAIT, prog_path, argv + 1,
390                          (const char **) environ);
391 #  if 0 /* Executing arbitrary files as shell scripts is unsecure.  */
392       if (child == -1 && errno == ENOEXEC)
393         {
394           /* prog is not a native executable.  Try to execute it as a
395              shell script.  Note that prepare_spawn() has already prepended
396              a hidden element "sh.exe" to argv.  */
397           child = _spawnvpe (P_NOWAIT, argv[0], argv,
398                              (const char **) environ);
399         }
400 #  endif
401     }
402   if (child == -1)
403     saved_errno = errno;
404   if (stdinfd >= 0)
405     close (stdinfd);
406   if (stdoutfd >= 0)
407     close (stdoutfd);
408   if (nulloutfd >= 0)
409     close (nulloutfd);
410
411   /* Restore standard file handles of parent process.  */
412   if (null_stderr)
413     undup_safer_noinherit (orig_stderr, STDERR_FILENO);
414   if (pipe_stdout || prog_stdout != NULL)
415     undup_safer_noinherit (orig_stdout, STDOUT_FILENO);
416   if (pipe_stdin || prog_stdin != NULL)
417     undup_safer_noinherit (orig_stdin, STDIN_FILENO);
418
419   if (pipe_stdin)
420     close (ofd[0]);
421   if (pipe_stdout)
422     close (ifd[1]);
423 # endif
424
425   free (argv);
426   free (argv_mem_to_free);
427   free (prog_path_to_free);
428
429   if (child == -1)
430     {
431       if (pipe_stdout)
432         close (ifd[0]);
433       if (pipe_stdin)
434         close (ofd[1]);
435       goto fail_with_saved_errno;
436     }
437
438   if (pipe_stdout)
439     fd[0] = ifd[0];
440   if (pipe_stdin)
441     fd[1] = ofd[1];
442   return child;
443
444 #else
445
446   /* Unix API.  */
447   int ifd[2];
448   int ofd[2];
449   sigset_t blocked_signals;
450   posix_spawn_file_actions_t actions;
451   bool actions_allocated;
452   posix_spawnattr_t attrs;
453   bool attrs_allocated;
454   int err;
455   pid_t child;
456
457   if (pipe_stdout)
458     if (pipe_safer (ifd) < 0)
459       error (EXIT_FAILURE, errno, _("cannot create pipe"));
460   if (pipe_stdin)
461     if (pipe_safer (ofd) < 0)
462       error (EXIT_FAILURE, errno, _("cannot create pipe"));
463 /* Data flow diagram:
464  *
465  *           write        system         read
466  *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
467  *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
468  *           read         system         write
469  *
470  */
471
472   if (slave_process)
473     {
474       sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
475       block_fatal_signals ();
476     }
477   actions_allocated = false;
478   attrs_allocated = false;
479   if ((err = posix_spawn_file_actions_init (&actions)) != 0
480       || (actions_allocated = true,
481           (pipe_stdin
482            && (err = posix_spawn_file_actions_adddup2 (&actions,
483                                                        ofd[0], STDIN_FILENO))
484               != 0)
485           || (pipe_stdout
486               && (err = posix_spawn_file_actions_adddup2 (&actions,
487                                                           ifd[1], STDOUT_FILENO))
488                  != 0)
489           || (pipe_stdin
490               && (err = posix_spawn_file_actions_addclose (&actions, ofd[0]))
491                  != 0)
492           || (pipe_stdout
493               && (err = posix_spawn_file_actions_addclose (&actions, ifd[1]))
494                  != 0)
495           || (pipe_stdin
496               && (err = posix_spawn_file_actions_addclose (&actions, ofd[1]))
497                  != 0)
498           || (pipe_stdout
499               && (err = posix_spawn_file_actions_addclose (&actions, ifd[0]))
500                  != 0)
501           || (null_stderr
502               && (err = posix_spawn_file_actions_addopen (&actions,
503                                                           STDERR_FILENO,
504                                                           "/dev/null", O_RDWR,
505                                                           0))
506                  != 0)
507           || (!pipe_stdin
508               && prog_stdin != NULL
509               && (err = posix_spawn_file_actions_addopen (&actions,
510                                                           STDIN_FILENO,
511                                                           prog_stdin, O_RDONLY,
512                                                           0))
513                  != 0)
514           || (!pipe_stdout
515               && prog_stdout != NULL
516               && (err = posix_spawn_file_actions_addopen (&actions,
517                                                           STDOUT_FILENO,
518                                                           prog_stdout, O_WRONLY,
519                                                           0))
520                  != 0)
521           || (directory != NULL
522               && (err = posix_spawn_file_actions_addchdir (&actions,
523                                                            directory)))
524           || (slave_process
525               && ((err = posix_spawnattr_init (&attrs)) != 0
526                   || (attrs_allocated = true,
527 # if defined _WIN32 && !defined __CYGWIN__
528                       (err = posix_spawnattr_setpgroup (&attrs, 0)) != 0
529                       || (err = posix_spawnattr_setflags (&attrs,
530                                                          POSIX_SPAWN_SETPGROUP))
531                          != 0
532 # else
533                       (err = posix_spawnattr_setsigmask (&attrs,
534                                                          &blocked_signals))
535                       != 0
536                       || (err = posix_spawnattr_setflags (&attrs,
537                                                         POSIX_SPAWN_SETSIGMASK))
538                          != 0
539 # endif
540              )   )   )
541           || (err = (directory != NULL
542                      ? posix_spawn (&child, prog_path, &actions,
543                                     attrs_allocated ? &attrs : NULL,
544                                     (char * const *) prog_argv, environ)
545                      : posix_spawnp (&child, prog_path, &actions,
546                                      attrs_allocated ? &attrs : NULL,
547                                      (char * const *) prog_argv, environ)))
548              != 0))
549     {
550       if (actions_allocated)
551         posix_spawn_file_actions_destroy (&actions);
552       if (attrs_allocated)
553         posix_spawnattr_destroy (&attrs);
554       if (slave_process)
555         unblock_fatal_signals ();
556       if (pipe_stdout)
557         {
558           close (ifd[0]);
559           close (ifd[1]);
560         }
561       if (pipe_stdin)
562         {
563           close (ofd[0]);
564           close (ofd[1]);
565         }
566       free (prog_path_to_free);
567       saved_errno = err;
568       goto fail_with_saved_errno;
569     }
570   posix_spawn_file_actions_destroy (&actions);
571   if (attrs_allocated)
572     posix_spawnattr_destroy (&attrs);
573   if (slave_process)
574     {
575       register_slave_subprocess (child);
576       unblock_fatal_signals ();
577     }
578   if (pipe_stdin)
579     close (ofd[0]);
580   if (pipe_stdout)
581     close (ifd[1]);
582   free (prog_path_to_free);
583
584   if (pipe_stdout)
585     fd[0] = ifd[0];
586   if (pipe_stdin)
587     fd[1] = ofd[1];
588   return child;
589
590 #endif
591
592  fail_with_errno:
593   saved_errno = errno;
594  fail_with_saved_errno:
595   if (exit_on_error || !null_stderr)
596     error (exit_on_error ? EXIT_FAILURE : 0, saved_errno,
597            _("%s subprocess failed"), progname);
598   errno = saved_errno;
599   return -1;
600 }
601
602 /* Open a bidirectional pipe.
603  *
604  *           write       system                read
605  *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child
606  *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
607  *           read        system                write
608  *
609  */
610 pid_t
611 create_pipe_bidi (const char *progname,
612                   const char *prog_path, const char * const *prog_argv,
613                   const char *directory,
614                   bool null_stderr,
615                   bool slave_process, bool exit_on_error,
616                   int fd[2])
617 {
618   pid_t result = create_pipe (progname, prog_path, prog_argv, directory,
619                               true, true, NULL, NULL,
620                               null_stderr, slave_process, exit_on_error,
621                               fd);
622   return result;
623 }
624
625 /* Open a pipe for input from a child process.
626  * The child's stdin comes from a file.
627  *
628  *           read        system                write
629  *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
630  *
631  */
632 pid_t
633 create_pipe_in (const char *progname,
634                 const char *prog_path, const char * const *prog_argv,
635                 const char *directory,
636                 const char *prog_stdin, bool null_stderr,
637                 bool slave_process, bool exit_on_error,
638                 int fd[1])
639 {
640   int iofd[2];
641   pid_t result = create_pipe (progname, prog_path, prog_argv, directory,
642                               false, true, prog_stdin, NULL,
643                               null_stderr, slave_process, exit_on_error,
644                               iofd);
645   if (result != -1)
646     fd[0] = iofd[0];
647   return result;
648 }
649
650 /* Open a pipe for output to a child process.
651  * The child's stdout goes to a file.
652  *
653  *           write       system                read
654  *    parent  ->   fd[0]   ->   STDIN_FILENO    ->   child
655  *
656  */
657 pid_t
658 create_pipe_out (const char *progname,
659                  const char *prog_path, const char * const *prog_argv,
660                  const char *directory,
661                  const char *prog_stdout, bool null_stderr,
662                  bool slave_process, bool exit_on_error,
663                  int fd[1])
664 {
665   int iofd[2];
666   pid_t result = create_pipe (progname, prog_path, prog_argv, directory,
667                               true, false, NULL, prog_stdout,
668                               null_stderr, slave_process, exit_on_error,
669                               iofd);
670   if (result != -1)
671     fd[0] = iofd[1];
672   return result;
673 }