root/maint/gnulib/lib/spawn-pipe.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nonintr_close
  2. nonintr_open
  3. create_pipe
  4. create_pipe_bidi
  5. create_pipe_in
  6. create_pipe_out

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */