(root)/
m4-1.4.19/
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  }