105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Creation of subprocesses, communicating via pipes.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2001-2004, 2006-2012 Free Software Foundation, Inc.
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software: you can redistribute it and/or modify
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   it under the terms of the GNU General Public License as published by
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation; either version 3 of the License, or
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   (at your option) any later version.
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   but WITHOUT ANY WARRANTY; without even the implied warranty of
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   GNU General Public License for more details.
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h>
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification.  */
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "spawn-pipe.h"
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <errno.h>
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <fcntl.h>
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdlib.h>
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <signal.h>
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <unistd.h>
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "error.h"
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "fatal-signal.h"
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "unistd-safer.h"
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "wait-process.h"
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "gettext.h"
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define _(str) gettext (str)
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Native Windows API.  */
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <process.h>
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include "w32spawn.h"
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Unix API.  */
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <spawn.h>
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* The results of open() in this file are not used with fchdir,
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   therefore save some unnecessary work in fchdir.c.  */
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#undef open
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#undef close
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifdef EINTR
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* EINTR handling for close().
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   These functions can return -1/EINTR even though we don't have any
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   signal handlers set up, namely when we get interrupted via SIGSTOP.  */
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic int
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wangnonintr_close (int fd)
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int retval;
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  do
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    retval = close (fd);
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  while (retval < 0 && errno == EINTR);
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return retval;
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define close nonintr_close
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic int
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wangnonintr_open (const char *pathname, int oflag, mode_t mode)
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int retval;
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  do
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    retval = open (pathname, oflag, mode);
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  while (retval < 0 && errno == EINTR);
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return retval;
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# undef open /* avoid warning on VMS */
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define open nonintr_open
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Open a pipe connected to a child process.
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang *           write       system                read
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child       if pipe_stdin
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child       if pipe_stdout
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang *           read        system                write
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang * At least one of pipe_stdin, pipe_stdout must be true.
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang * pipe_stdin and prog_stdin together determine the child's standard input.
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang * pipe_stdout and prog_stdout together determine the child's standard output.
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang * If pipe_stdin is true, prog_stdin is ignored.
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang * If pipe_stdout is true, prog_stdout is ignored.
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang */
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic pid_t
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wangcreate_pipe (const char *progname,
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang             const char *prog_path, char **prog_argv,
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang             bool pipe_stdin, bool pipe_stdout,
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang             const char *prog_stdin, const char *prog_stdout,
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang             bool null_stderr,
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang             bool slave_process, bool exit_on_error,
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang             int fd[2])
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Native Windows API.
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang     This uses _pipe(), dup2(), and spawnv().  It could also be implemented
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     using the low-level functions CreatePipe(), DuplicateHandle(),
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang     CreateProcess() and _open_osfhandle(); see the GNU make and GNU clisp
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang     and cvs source code.  */
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int ifd[2];
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int ofd[2];
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int orig_stdin;
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int orig_stdout;
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int orig_stderr;
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int child;
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int nulloutfd;
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int stdinfd;
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int stdoutfd;
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int saved_errno;
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* FIXME: Need to free memory allocated by prepare_spawn.  */
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  prog_argv = prepare_spawn (prog_argv);
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdout)
13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (pipe2_safer (ifd, O_BINARY | O_CLOEXEC) < 0)
14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      error (EXIT_FAILURE, errno, _("cannot create pipe"));
14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdin)
14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (pipe2_safer (ofd, O_BINARY | O_CLOEXEC) < 0)
14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      error (EXIT_FAILURE, errno, _("cannot create pipe"));
14405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Data flow diagram:
14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
14605436638acc7c010349a69c3395f1a57c642dc62Ying Wang *           write        system         read
14705436638acc7c010349a69c3395f1a57c642dc62Ying Wang *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
14905436638acc7c010349a69c3395f1a57c642dc62Ying Wang *           read         system         write
15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
15105436638acc7c010349a69c3395f1a57c642dc62Ying Wang */
15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Save standard file handles of parent process.  */
15405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdin || prog_stdin != NULL)
15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    orig_stdin = dup_safer_noinherit (STDIN_FILENO);
15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdout || prog_stdout != NULL)
15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    orig_stdout = dup_safer_noinherit (STDOUT_FILENO);
15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (null_stderr)
15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    orig_stderr = dup_safer_noinherit (STDERR_FILENO);
16005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  child = -1;
16105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Create standard file handles of child process.  */
16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  nulloutfd = -1;
16405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  stdinfd = -1;
16505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  stdoutfd = -1;
16605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
16705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
16805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      && (!null_stderr
16905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
17005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (nulloutfd == STDERR_FILENO
17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  || (dup2 (nulloutfd, STDERR_FILENO) >= 0
17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      && close (nulloutfd) >= 0))))
17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      && (pipe_stdin
17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || prog_stdin == NULL
17505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
17605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (stdinfd == STDIN_FILENO
17705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  || (dup2 (stdinfd, STDIN_FILENO) >= 0
17805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      && close (stdinfd) >= 0))))
17905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      && (pipe_stdout
18005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || prog_stdout == NULL
18105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
18205436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (stdoutfd == STDOUT_FILENO
18305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
18405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      && close (stdoutfd) >= 0)))))
18505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
18605436638acc7c010349a69c3395f1a57c642dc62Ying Wang       but it inherits all open()ed or dup2()ed file handles (which is what
18705436638acc7c010349a69c3395f1a57c642dc62Ying Wang       we want in the case of STD*_FILENO).  */
18805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* Use spawnvpe and pass the environment explicitly.  This is needed if
18905436638acc7c010349a69c3395f1a57c642dc62Ying Wang       the program has modified the environment using putenv() or [un]setenv().
19005436638acc7c010349a69c3395f1a57c642dc62Ying Wang       On Windows, programs have two environments, one in the "environment
19105436638acc7c010349a69c3395f1a57c642dc62Ying Wang       block" of the process and managed through SetEnvironmentVariable(), and
19205436638acc7c010349a69c3395f1a57c642dc62Ying Wang       one inside the process, in the location retrieved by the 'environ'
19305436638acc7c010349a69c3395f1a57c642dc62Ying Wang       macro.  When using spawnvp() without 'e', the child process inherits a
19405436638acc7c010349a69c3395f1a57c642dc62Ying Wang       copy of the environment block - ignoring the effects of putenv() and
19505436638acc7c010349a69c3395f1a57c642dc62Ying Wang       [un]setenv().  */
19605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
19705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      child = spawnvpe (P_NOWAIT, prog_path, (const char **) prog_argv,
19805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        (const char **) environ);
19905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (child < 0 && errno == ENOEXEC)
20005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
20105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* prog is not a native executable.  Try to execute it as a
20205436638acc7c010349a69c3395f1a57c642dc62Ying Wang             shell script.  Note that prepare_spawn() has already prepended
20305436638acc7c010349a69c3395f1a57c642dc62Ying Wang             a hidden element "sh.exe" to prog_argv.  */
20405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          --prog_argv;
20505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          child = spawnvpe (P_NOWAIT, prog_argv[0], (const char **) prog_argv,
20605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            (const char **) environ);
20705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
20805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
20905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (child == -1)
21005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    saved_errno = errno;
21105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (stdinfd >= 0)
21205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    close (stdinfd);
21305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (stdoutfd >= 0)
21405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    close (stdoutfd);
21505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (nulloutfd >= 0)
21605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    close (nulloutfd);
21705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
21805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Restore standard file handles of parent process.  */
21905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (null_stderr)
22005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    undup_safer_noinherit (orig_stderr, STDERR_FILENO);
22105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdout || prog_stdout != NULL)
22205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    undup_safer_noinherit (orig_stdout, STDOUT_FILENO);
22305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdin || prog_stdin != NULL)
22405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    undup_safer_noinherit (orig_stdin, STDIN_FILENO);
22505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
22605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdin)
22705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    close (ofd[0]);
22805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdout)
22905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    close (ifd[1]);
23005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (child == -1)
23105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
23205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (exit_on_error || !null_stderr)
23305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        error (exit_on_error ? EXIT_FAILURE : 0, saved_errno,
23405436638acc7c010349a69c3395f1a57c642dc62Ying Wang               _("%s subprocess failed"), progname);
23505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (pipe_stdout)
23605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        close (ifd[0]);
23705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (pipe_stdin)
23805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        close (ofd[1]);
23905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      errno = saved_errno;
24005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return -1;
24105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
24205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
24305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdout)
24405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    fd[0] = ifd[0];
24505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdin)
24605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    fd[1] = ofd[1];
24705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return child;
24805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
24905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
25005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
25105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Unix API.  */
25205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int ifd[2];
25305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int ofd[2];
25405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  sigset_t blocked_signals;
25505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  posix_spawn_file_actions_t actions;
25605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  bool actions_allocated;
25705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  posix_spawnattr_t attrs;
25805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  bool attrs_allocated;
25905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
26005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  pid_t child;
26105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
26205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdout)
26305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (pipe_safer (ifd) < 0)
26405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      error (EXIT_FAILURE, errno, _("cannot create pipe"));
26505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdin)
26605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (pipe_safer (ofd) < 0)
26705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      error (EXIT_FAILURE, errno, _("cannot create pipe"));
26805436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Data flow diagram:
26905436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
27005436638acc7c010349a69c3395f1a57c642dc62Ying Wang *           write        system         read
27105436638acc7c010349a69c3395f1a57c642dc62Ying Wang *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
27205436638acc7c010349a69c3395f1a57c642dc62Ying Wang *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
27305436638acc7c010349a69c3395f1a57c642dc62Ying Wang *           read         system         write
27405436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
27505436638acc7c010349a69c3395f1a57c642dc62Ying Wang */
27605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
27705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (slave_process)
27805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
27905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
28005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      block_fatal_signals ();
28105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
28205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  actions_allocated = false;
28305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  attrs_allocated = false;
28405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if ((err = posix_spawn_file_actions_init (&actions)) != 0
28505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      || (actions_allocated = true,
28605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          (pipe_stdin
28705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           && (err = posix_spawn_file_actions_adddup2 (&actions,
28805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                       ofd[0], STDIN_FILENO))
28905436638acc7c010349a69c3395f1a57c642dc62Ying Wang              != 0)
29005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || (pipe_stdout
29105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (err = posix_spawn_file_actions_adddup2 (&actions,
29205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                          ifd[1], STDOUT_FILENO))
29305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 != 0)
29405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || (pipe_stdin
29505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (err = posix_spawn_file_actions_addclose (&actions, ofd[0]))
29605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 != 0)
29705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || (pipe_stdout
29805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (err = posix_spawn_file_actions_addclose (&actions, ifd[1]))
29905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 != 0)
30005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || (pipe_stdin
30105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (err = posix_spawn_file_actions_addclose (&actions, ofd[1]))
30205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 != 0)
30305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || (pipe_stdout
30405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (err = posix_spawn_file_actions_addclose (&actions, ifd[0]))
30505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 != 0)
30605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || (null_stderr
30705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (err = posix_spawn_file_actions_addopen (&actions,
30805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                          STDERR_FILENO,
30905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                          "/dev/null", O_RDWR,
31005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                          0))
31105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 != 0)
31205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || (!pipe_stdin
31305436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && prog_stdin != NULL
31405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (err = posix_spawn_file_actions_addopen (&actions,
31505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                          STDIN_FILENO,
31605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                          prog_stdin, O_RDONLY,
31705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                          0))
31805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 != 0)
31905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || (!pipe_stdout
32005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && prog_stdout != NULL
32105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && (err = posix_spawn_file_actions_addopen (&actions,
32205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                          STDOUT_FILENO,
32305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                          prog_stdout, O_WRONLY,
32405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                          0))
32505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 != 0)
32605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || (slave_process
32705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              && ((err = posix_spawnattr_init (&attrs)) != 0
32805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  || (attrs_allocated = true,
32905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      (err = posix_spawnattr_setsigmask (&attrs,
33005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                         &blocked_signals))
33105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      != 0
33205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      || (err = posix_spawnattr_setflags (&attrs,
33305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                        POSIX_SPAWN_SETSIGMASK))
33405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                         != 0)))
33505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || (err = posix_spawnp (&child, prog_path, &actions,
33605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                  attrs_allocated ? &attrs : NULL, prog_argv,
33705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                  environ))
33805436638acc7c010349a69c3395f1a57c642dc62Ying Wang             != 0))
33905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
34005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (actions_allocated)
34105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        posix_spawn_file_actions_destroy (&actions);
34205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (attrs_allocated)
34305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        posix_spawnattr_destroy (&attrs);
34405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (slave_process)
34505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        unblock_fatal_signals ();
34605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (exit_on_error || !null_stderr)
34705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        error (exit_on_error ? EXIT_FAILURE : 0, err,
34805436638acc7c010349a69c3395f1a57c642dc62Ying Wang               _("%s subprocess failed"), progname);
34905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (pipe_stdout)
35005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
35105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          close (ifd[0]);
35205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          close (ifd[1]);
35305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
35405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (pipe_stdin)
35505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
35605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          close (ofd[0]);
35705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          close (ofd[1]);
35805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
35905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      errno = err;
36005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return -1;
36105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
36205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  posix_spawn_file_actions_destroy (&actions);
36305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (attrs_allocated)
36405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    posix_spawnattr_destroy (&attrs);
36505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (slave_process)
36605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
36705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      register_slave_subprocess (child);
36805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      unblock_fatal_signals ();
36905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
37005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdin)
37105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    close (ofd[0]);
37205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdout)
37305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    close (ifd[1]);
37405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
37505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdout)
37605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    fd[0] = ifd[0];
37705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (pipe_stdin)
37805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    fd[1] = ofd[1];
37905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return child;
38005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
38105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
38205436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
38305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
38405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Open a bidirectional pipe.
38505436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
38605436638acc7c010349a69c3395f1a57c642dc62Ying Wang *           write       system                read
38705436638acc7c010349a69c3395f1a57c642dc62Ying Wang *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child
38805436638acc7c010349a69c3395f1a57c642dc62Ying Wang *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
38905436638acc7c010349a69c3395f1a57c642dc62Ying Wang *           read        system                write
39005436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
39105436638acc7c010349a69c3395f1a57c642dc62Ying Wang */
39205436638acc7c010349a69c3395f1a57c642dc62Ying Wangpid_t
39305436638acc7c010349a69c3395f1a57c642dc62Ying Wangcreate_pipe_bidi (const char *progname,
39405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  const char *prog_path, char **prog_argv,
39505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  bool null_stderr,
39605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  bool slave_process, bool exit_on_error,
39705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  int fd[2])
39805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
39905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  pid_t result = create_pipe (progname, prog_path, prog_argv,
40005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              true, true, NULL, NULL,
40105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              null_stderr, slave_process, exit_on_error,
40205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              fd);
40305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return result;
40405436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
40505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
40605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Open a pipe for input from a child process.
40705436638acc7c010349a69c3395f1a57c642dc62Ying Wang * The child's stdin comes from a file.
40805436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
40905436638acc7c010349a69c3395f1a57c642dc62Ying Wang *           read        system                write
41005436638acc7c010349a69c3395f1a57c642dc62Ying Wang *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
41105436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
41205436638acc7c010349a69c3395f1a57c642dc62Ying Wang */
41305436638acc7c010349a69c3395f1a57c642dc62Ying Wangpid_t
41405436638acc7c010349a69c3395f1a57c642dc62Ying Wangcreate_pipe_in (const char *progname,
41505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                const char *prog_path, char **prog_argv,
41605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                const char *prog_stdin, bool null_stderr,
41705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                bool slave_process, bool exit_on_error,
41805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                int fd[1])
41905436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
42005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int iofd[2];
42105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  pid_t result = create_pipe (progname, prog_path, prog_argv,
42205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              false, true, prog_stdin, NULL,
42305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              null_stderr, slave_process, exit_on_error,
42405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              iofd);
42505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (result != -1)
42605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    fd[0] = iofd[0];
42705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return result;
42805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
42905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
43005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Open a pipe for output to a child process.
43105436638acc7c010349a69c3395f1a57c642dc62Ying Wang * The child's stdout goes to a file.
43205436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
43305436638acc7c010349a69c3395f1a57c642dc62Ying Wang *           write       system                read
43405436638acc7c010349a69c3395f1a57c642dc62Ying Wang *    parent  ->   fd[0]   ->   STDIN_FILENO    ->   child
43505436638acc7c010349a69c3395f1a57c642dc62Ying Wang *
43605436638acc7c010349a69c3395f1a57c642dc62Ying Wang */
43705436638acc7c010349a69c3395f1a57c642dc62Ying Wangpid_t
43805436638acc7c010349a69c3395f1a57c642dc62Ying Wangcreate_pipe_out (const char *progname,
43905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 const char *prog_path, char **prog_argv,
44005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 const char *prog_stdout, bool null_stderr,
44105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 bool slave_process, bool exit_on_error,
44205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 int fd[1])
44305436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
44405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int iofd[2];
44505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  pid_t result = create_pipe (progname, prog_path, prog_argv,
44605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              true, false, NULL, prog_stdout,
44705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              null_stderr, slave_process, exit_on_error,
44805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              iofd);
44905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (result != -1)
45005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    fd[0] = iofd[1];
45105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return result;
45205436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
453