Rename module 'pipe' to 'spawn-pipe'.
authorBruno Haible <bruno@clisp.org>
Sat, 11 Dec 2010 01:00:44 +0000 (02:00 +0100)
committerBruno Haible <bruno@clisp.org>
Sat, 11 Dec 2010 01:00:44 +0000 (02:00 +0100)
* modules/spawn-pipe: New file, renamed from modules/pipe.
(Files, configure.ac, Makefile.am): Update.
(Include): Mention "spawn-pipe.h" instead of "pipe.h".
* modules/pipe: Reduce to an obsolete indirection to 'spawn-pipe'.
* lib/spawn-pipe.h: New file, renamed from lib/pipe.h.
* lib/spawn-pipe.c: New file, renamed from lib/pipe.c. Include
"spawn-pipe.h" instead of "pipe.h".
* m4/spawn-pipe.m4: New file, renamed from m4/pipe.m4. Rename gl_PIPE
to gl_SPAWN_PIPE.
* modules/spawn-pipe-tests: New file, renamed from modules/pipe-tests.
(Files, Makefile.am): Update.
* tests/test-spawn-pipe.sh: New file, renamed from tests/test-pipe.sh.
Update.
* tests/test-spawn-pipe.c: New file, renamed from tests/test-pipe.c.
Include "spawn-pipe.h" instead of "pipe.h".
* lib/csharpcomp.c: Include "spawn-pipe.h" instead of "pipe.h".
* lib/javacomp.c: Likewise.
* lib/javaversion.c: Likewise.
* lib/pipe-filter-gi.c: Likewise.
* lib/pipe-filter-ii.c: Likewise.
* modules/csharpcomp (Depends-on): Add 'spawn-pipe', remove 'pipe'.
* modules/javacomp (Depends-on): Likewise.
* modules/javaversion (Depends-on): Likewise.
* modules/pipe-filter-gi (Depends-on): Likewise.
* modules/pipe-filter-ii (Depends-on): Likewise.
* MODULES.html.sh (Executing programs): Update.
* NEWS: Mention the change.

27 files changed:
ChangeLog
MODULES.html.sh
NEWS
lib/csharpcomp.c
lib/javacomp.c
lib/javaversion.c
lib/pipe-filter-gi.c
lib/pipe-filter-ii.c
lib/pipe.c [deleted file]
lib/pipe.h [deleted file]
lib/spawn-pipe.c [new file with mode: 0644]
lib/spawn-pipe.h [new file with mode: 0644]
m4/pipe.m4 [deleted file]
m4/spawn-pipe.m4 [new file with mode: 0644]
modules/csharpcomp
modules/javacomp
modules/javaversion
modules/pipe
modules/pipe-filter-gi
modules/pipe-filter-ii
modules/pipe-tests [deleted file]
modules/spawn-pipe [new file with mode: 0644]
modules/spawn-pipe-tests [new file with mode: 0644]
tests/test-pipe.c [deleted file]
tests/test-pipe.sh [deleted file]
tests/test-spawn-pipe.c [new file with mode: 0644]
tests/test-spawn-pipe.sh [new file with mode: 0755]

index 29849ba..137fc34 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+2010-12-10  Bruno Haible  <bruno@clisp.org>
+
+       Rename module 'pipe' to 'spawn-pipe'.
+       * modules/spawn-pipe: New file, renamed from modules/pipe.
+       (Files, configure.ac, Makefile.am): Update.
+       (Include): Mention "spawn-pipe.h" instead of "pipe.h".
+       * modules/pipe: Reduce to an obsolete indirection to 'spawn-pipe'.
+       * lib/spawn-pipe.h: New file, renamed from lib/pipe.h.
+       * lib/spawn-pipe.c: New file, renamed from lib/pipe.c. Include
+       "spawn-pipe.h" instead of "pipe.h".
+       * m4/spawn-pipe.m4: New file, renamed from m4/pipe.m4. Rename gl_PIPE
+       to gl_SPAWN_PIPE.
+       * modules/spawn-pipe-tests: New file, renamed from modules/pipe-tests.
+       (Files, Makefile.am): Update.
+       * tests/test-spawn-pipe.sh: New file, renamed from tests/test-pipe.sh.
+       Update.
+       * tests/test-spawn-pipe.c: New file, renamed from tests/test-pipe.c.
+       Include "spawn-pipe.h" instead of "pipe.h".
+       * lib/csharpcomp.c: Include "spawn-pipe.h" instead of "pipe.h".
+       * lib/javacomp.c: Likewise.
+       * lib/javaversion.c: Likewise.
+       * lib/pipe-filter-gi.c: Likewise.
+       * lib/pipe-filter-ii.c: Likewise.
+       * modules/csharpcomp (Depends-on): Add 'spawn-pipe', remove 'pipe'.
+       * modules/javacomp (Depends-on): Likewise.
+       * modules/javaversion (Depends-on): Likewise.
+       * modules/pipe-filter-gi (Depends-on): Likewise.
+       * modules/pipe-filter-ii (Depends-on): Likewise.
+       * MODULES.html.sh (Executing programs): Update.
+       * NEWS: Mention the change.
+
 2010-12-10  Eric Blake  <eblake@redhat.com>
 
        pipe-posix: new module
index 456497f..aee5c24 100755 (executable)
@@ -3324,7 +3324,7 @@ func_all_modules ()
   func_module findprog-lgpl
   func_module wait-process
   func_module execute
-  func_module pipe
+  func_module spawn-pipe
   func_module pipe-filter-gi
   func_module pipe-filter-ii
   func_module sh-quote
diff --git a/NEWS b/NEWS
index 76239dd..49a44ec 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,9 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2010-12-10  pipe            This module is renamed to spawn-pipe. The include
+                            file is renamed to "spawn-pipe.h".
+
 2010-10-05  getdate         This module is deprecated. Please use the new
                             parse-datetime module for the replacement
                             function parse_datetime(), or help us write
index 8f79151..b4d6590 100644 (file)
@@ -27,7 +27,7 @@
 #include <string.h>
 
 #include "execute.h"
-#include "pipe.h"
+#include "spawn-pipe.h"
 #include "wait-process.h"
 #include "sh-quote.h"
 #include "safe-read.h"
index 0bd5ec5..fc33652 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "javaversion.h"
 #include "execute.h"
-#include "pipe.h"
+#include "spawn-pipe.h"
 #include "wait-process.h"
 #include "classpath.h"
 #include "xsetenv.h"
index 7d76539..b7fc4ac 100644 (file)
@@ -31,7 +31,7 @@
 #endif
 
 #include "javaexec.h"
-#include "pipe.h"
+#include "spawn-pipe.h"
 #include "wait-process.h"
 #include "error.h"
 #include "gettext.h"
index 1952183..85a8d33 100644 (file)
@@ -34,7 +34,7 @@
 #endif
 
 #include "error.h"
-#include "pipe.h"
+#include "spawn-pipe.h"
 #include "wait-process.h"
 #include "xalloc.h"
 #include "gettext.h"
index b25662d..93dfbc1 100644 (file)
@@ -33,7 +33,7 @@
 #endif
 
 #include "error.h"
-#include "pipe.h"
+#include "spawn-pipe.h"
 #include "wait-process.h"
 #include "gettext.h"
 
diff --git a/lib/pipe.c b/lib/pipe.c
deleted file mode 100644 (file)
index 1c81d14..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-/* Creation of subprocesses, communicating via pipes.
-   Copyright (C) 2001-2004, 2006-2010 Free Software Foundation, Inc.
-   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-
-#include <config.h>
-
-/* Specification.  */
-#include "pipe.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-
-#include "error.h"
-#include "fatal-signal.h"
-#include "unistd-safer.h"
-#include "wait-process.h"
-#include "gettext.h"
-
-#define _(str) gettext (str)
-
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-
-/* Native Woe32 API.  */
-# include <process.h>
-# include "w32spawn.h"
-
-#else
-
-/* Unix API.  */
-# include <spawn.h>
-
-#endif
-
-/* The results of open() in this file are not used with fchdir,
-   therefore save some unnecessary work in fchdir.c.  */
-#undef open
-#undef close
-
-
-#ifdef EINTR
-
-/* EINTR handling for close().
-   These functions can return -1/EINTR even though we don't have any
-   signal handlers set up, namely when we get interrupted via SIGSTOP.  */
-
-static inline int
-nonintr_close (int fd)
-{
-  int retval;
-
-  do
-    retval = close (fd);
-  while (retval < 0 && errno == EINTR);
-
-  return retval;
-}
-#define close nonintr_close
-
-static inline int
-nonintr_open (const char *pathname, int oflag, mode_t mode)
-{
-  int retval;
-
-  do
-    retval = open (pathname, oflag, mode);
-  while (retval < 0 && errno == EINTR);
-
-  return retval;
-}
-#undef open /* avoid warning on VMS */
-#define open nonintr_open
-
-#endif
-
-
-/* Open a pipe connected to a child process.
- *
- *           write       system                read
- *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child       if pipe_stdin
- *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child       if pipe_stdout
- *           read        system                write
- *
- * At least one of pipe_stdin, pipe_stdout must be true.
- * pipe_stdin and prog_stdin together determine the child's standard input.
- * pipe_stdout and prog_stdout together determine the child's standard output.
- * If pipe_stdin is true, prog_stdin is ignored.
- * If pipe_stdout is true, prog_stdout is ignored.
- */
-static pid_t
-create_pipe (const char *progname,
-             const char *prog_path, char **prog_argv,
-             bool pipe_stdin, bool pipe_stdout,
-             const char *prog_stdin, const char *prog_stdout,
-             bool null_stderr,
-             bool slave_process, bool exit_on_error,
-             int fd[2])
-{
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-
-  /* Native Woe32 API.
-     This uses _pipe(), dup2(), and spawnv().  It could also be implemented
-     using the low-level functions CreatePipe(), DuplicateHandle(),
-     CreateProcess() and _open_osfhandle(); see the GNU make and GNU clisp
-     and cvs source code.  */
-  int ifd[2];
-  int ofd[2];
-  int orig_stdin;
-  int orig_stdout;
-  int orig_stderr;
-  int child;
-  int nulloutfd;
-  int stdinfd;
-  int stdoutfd;
-  int saved_errno;
-
-  /* FIXME: Need to free memory allocated by prepare_spawn.  */
-  prog_argv = prepare_spawn (prog_argv);
-
-  if (pipe_stdout)
-    if (pipe2_safer (ifd, O_BINARY | O_CLOEXEC) < 0)
-      error (EXIT_FAILURE, errno, _("cannot create pipe"));
-  if (pipe_stdin)
-    if (pipe2_safer (ofd, O_BINARY | O_CLOEXEC) < 0)
-      error (EXIT_FAILURE, errno, _("cannot create pipe"));
-/* Data flow diagram:
- *
- *           write        system         read
- *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
- *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
- *           read         system         write
- *
- */
-
-  /* Save standard file handles of parent process.  */
-  if (pipe_stdin || prog_stdin != NULL)
-    orig_stdin = dup_safer_noinherit (STDIN_FILENO);
-  if (pipe_stdout || prog_stdout != NULL)
-    orig_stdout = dup_safer_noinherit (STDOUT_FILENO);
-  if (null_stderr)
-    orig_stderr = dup_safer_noinherit (STDERR_FILENO);
-  child = -1;
-
-  /* Create standard file handles of child process.  */
-  nulloutfd = -1;
-  stdinfd = -1;
-  stdoutfd = -1;
-  if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
-      && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
-      && (!null_stderr
-          || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
-              && (nulloutfd == STDERR_FILENO
-                  || (dup2 (nulloutfd, STDERR_FILENO) >= 0
-                      && close (nulloutfd) >= 0))))
-      && (pipe_stdin
-          || prog_stdin == NULL
-          || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
-              && (stdinfd == STDIN_FILENO
-                  || (dup2 (stdinfd, STDIN_FILENO) >= 0
-                      && close (stdinfd) >= 0))))
-      && (pipe_stdout
-          || prog_stdout == NULL
-          || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
-              && (stdoutfd == STDOUT_FILENO
-                  || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
-                      && close (stdoutfd) >= 0)))))
-    /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
-       but it inherits all open()ed or dup2()ed file handles (which is what
-       we want in the case of STD*_FILENO).  */
-    /* Use spawnvpe and pass the environment explicitly.  This is needed if
-       the program has modified the environment using putenv() or [un]setenv().
-       On Windows, programs have two environments, one in the "environment
-       block" of the process and managed through SetEnvironmentVariable(), and
-       one inside the process, in the location retrieved by the 'environ'
-       macro.  When using spawnvp() without 'e', the child process inherits a
-       copy of the environment block - ignoring the effects of putenv() and
-       [un]setenv().  */
-    {
-      child = spawnvpe (P_NOWAIT, prog_path, (const char **) prog_argv,
-                        (const char **) environ);
-      if (child < 0 && errno == ENOEXEC)
-        {
-          /* prog is not an native executable.  Try to execute it as a
-             shell script.  Note that prepare_spawn() has already prepended
-             a hidden element "sh.exe" to prog_argv.  */
-          --prog_argv;
-          child = spawnvpe (P_NOWAIT, prog_argv[0], (const char **) prog_argv,
-                            (const char **) environ);
-        }
-    }
-  if (child == -1)
-    saved_errno = errno;
-  if (stdinfd >= 0)
-    close (stdinfd);
-  if (stdoutfd >= 0)
-    close (stdoutfd);
-  if (nulloutfd >= 0)
-    close (nulloutfd);
-
-  /* Restore standard file handles of parent process.  */
-  if (null_stderr)
-    undup_safer_noinherit (orig_stderr, STDERR_FILENO);
-  if (pipe_stdout || prog_stdout != NULL)
-    undup_safer_noinherit (orig_stdout, STDOUT_FILENO);
-  if (pipe_stdin || prog_stdin != NULL)
-    undup_safer_noinherit (orig_stdin, STDIN_FILENO);
-
-  if (pipe_stdin)
-    close (ofd[0]);
-  if (pipe_stdout)
-    close (ifd[1]);
-  if (child == -1)
-    {
-      if (exit_on_error || !null_stderr)
-        error (exit_on_error ? EXIT_FAILURE : 0, saved_errno,
-               _("%s subprocess failed"), progname);
-      if (pipe_stdout)
-        close (ifd[0]);
-      if (pipe_stdin)
-        close (ofd[1]);
-      errno = saved_errno;
-      return -1;
-    }
-
-  if (pipe_stdout)
-    fd[0] = ifd[0];
-  if (pipe_stdin)
-    fd[1] = ofd[1];
-  return child;
-
-#else
-
-  /* Unix API.  */
-  int ifd[2];
-  int ofd[2];
-  sigset_t blocked_signals;
-  posix_spawn_file_actions_t actions;
-  bool actions_allocated;
-  posix_spawnattr_t attrs;
-  bool attrs_allocated;
-  int err;
-  pid_t child;
-
-  if (pipe_stdout)
-    if (pipe_safer (ifd) < 0)
-      error (EXIT_FAILURE, errno, _("cannot create pipe"));
-  if (pipe_stdin)
-    if (pipe_safer (ofd) < 0)
-      error (EXIT_FAILURE, errno, _("cannot create pipe"));
-/* Data flow diagram:
- *
- *           write        system         read
- *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
- *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
- *           read         system         write
- *
- */
-
-  if (slave_process)
-    {
-      sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
-      block_fatal_signals ();
-    }
-  actions_allocated = false;
-  attrs_allocated = false;
-  if ((err = posix_spawn_file_actions_init (&actions)) != 0
-      || (actions_allocated = true,
-          (pipe_stdin
-           && (err = posix_spawn_file_actions_adddup2 (&actions,
-                                                       ofd[0], STDIN_FILENO))
-              != 0)
-          || (pipe_stdout
-              && (err = posix_spawn_file_actions_adddup2 (&actions,
-                                                          ifd[1], STDOUT_FILENO))
-                 != 0)
-          || (pipe_stdin
-              && (err = posix_spawn_file_actions_addclose (&actions, ofd[0]))
-                 != 0)
-          || (pipe_stdout
-              && (err = posix_spawn_file_actions_addclose (&actions, ifd[1]))
-                 != 0)
-          || (pipe_stdin
-              && (err = posix_spawn_file_actions_addclose (&actions, ofd[1]))
-                 != 0)
-          || (pipe_stdout
-              && (err = posix_spawn_file_actions_addclose (&actions, ifd[0]))
-                 != 0)
-          || (null_stderr
-              && (err = posix_spawn_file_actions_addopen (&actions,
-                                                          STDERR_FILENO,
-                                                          "/dev/null", O_RDWR,
-                                                          0))
-                 != 0)
-          || (!pipe_stdin
-              && prog_stdin != NULL
-              && (err = posix_spawn_file_actions_addopen (&actions,
-                                                          STDIN_FILENO,
-                                                          prog_stdin, O_RDONLY,
-                                                          0))
-                 != 0)
-          || (!pipe_stdout
-              && prog_stdout != NULL
-              && (err = posix_spawn_file_actions_addopen (&actions,
-                                                          STDOUT_FILENO,
-                                                          prog_stdout, O_WRONLY,
-                                                          0))
-                 != 0)
-          || (slave_process
-              && ((err = posix_spawnattr_init (&attrs)) != 0
-                  || (attrs_allocated = true,
-                      (err = posix_spawnattr_setsigmask (&attrs,
-                                                         &blocked_signals))
-                      != 0
-                      || (err = posix_spawnattr_setflags (&attrs,
-                                                        POSIX_SPAWN_SETSIGMASK))
-                         != 0)))
-          || (err = posix_spawnp (&child, prog_path, &actions,
-                                  attrs_allocated ? &attrs : NULL, prog_argv,
-                                  environ))
-             != 0))
-    {
-      if (actions_allocated)
-        posix_spawn_file_actions_destroy (&actions);
-      if (attrs_allocated)
-        posix_spawnattr_destroy (&attrs);
-      if (slave_process)
-        unblock_fatal_signals ();
-      if (exit_on_error || !null_stderr)
-        error (exit_on_error ? EXIT_FAILURE : 0, err,
-               _("%s subprocess failed"), progname);
-      if (pipe_stdout)
-        {
-          close (ifd[0]);
-          close (ifd[1]);
-        }
-      if (pipe_stdin)
-        {
-          close (ofd[0]);
-          close (ofd[1]);
-        }
-      errno = err;
-      return -1;
-    }
-  posix_spawn_file_actions_destroy (&actions);
-  if (attrs_allocated)
-    posix_spawnattr_destroy (&attrs);
-  if (slave_process)
-    {
-      register_slave_subprocess (child);
-      unblock_fatal_signals ();
-    }
-  if (pipe_stdin)
-    close (ofd[0]);
-  if (pipe_stdout)
-    close (ifd[1]);
-
-  if (pipe_stdout)
-    fd[0] = ifd[0];
-  if (pipe_stdin)
-    fd[1] = ofd[1];
-  return child;
-
-#endif
-}
-
-/* Open a bidirectional pipe.
- *
- *           write       system                read
- *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child
- *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
- *           read        system                write
- *
- */
-pid_t
-create_pipe_bidi (const char *progname,
-                  const char *prog_path, char **prog_argv,
-                  bool null_stderr,
-                  bool slave_process, bool exit_on_error,
-                  int fd[2])
-{
-  pid_t result = create_pipe (progname, prog_path, prog_argv,
-                              true, true, NULL, NULL,
-                              null_stderr, slave_process, exit_on_error,
-                              fd);
-  return result;
-}
-
-/* Open a pipe for input from a child process.
- * The child's stdin comes from a file.
- *
- *           read        system                write
- *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
- *
- */
-pid_t
-create_pipe_in (const char *progname,
-                const char *prog_path, char **prog_argv,
-                const char *prog_stdin, bool null_stderr,
-                bool slave_process, bool exit_on_error,
-                int fd[1])
-{
-  int iofd[2];
-  pid_t result = create_pipe (progname, prog_path, prog_argv,
-                              false, true, prog_stdin, NULL,
-                              null_stderr, slave_process, exit_on_error,
-                              iofd);
-  if (result != -1)
-    fd[0] = iofd[0];
-  return result;
-}
-
-/* Open a pipe for output to a child process.
- * The child's stdout goes to a file.
- *
- *           write       system                read
- *    parent  ->   fd[0]   ->   STDIN_FILENO    ->   child
- *
- */
-pid_t
-create_pipe_out (const char *progname,
-                 const char *prog_path, char **prog_argv,
-                 const char *prog_stdout, bool null_stderr,
-                 bool slave_process, bool exit_on_error,
-                 int fd[1])
-{
-  int iofd[2];
-  pid_t result = create_pipe (progname, prog_path, prog_argv,
-                              true, false, NULL, prog_stdout,
-                              null_stderr, slave_process, exit_on_error,
-                              iofd);
-  if (result != -1)
-    fd[0] = iofd[1];
-  return result;
-}
diff --git a/lib/pipe.h b/lib/pipe.h
deleted file mode 100644 (file)
index 7517892..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Creation of subprocesses, communicating via pipes.
-   Copyright (C) 2001-2003, 2006, 2008-2010 Free Software Foundation, Inc.
-   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#ifndef _PIPE_H
-#define _PIPE_H
-
-/* Get pid_t.  */
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include <stdbool.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* All these functions create a subprocess and don't wait for its termination.
-   They return the process id of the subprocess.  They also return in fd[]
-   one or two file descriptors for communication with the subprocess.
-   If the subprocess creation fails: if exit_on_error is true, the main
-   process exits with an error message; otherwise, an error message is given
-   if null_stderr is false, then -1 is returned, with errno set, and fd[]
-   remain uninitialized.
-
-   After finishing communication, the caller should call wait_subprocess()
-   to get rid of the subprocess in the process table.
-
-   If slave_process is true, the child process will be terminated when its
-   creator receives a catchable fatal signal or exits normally.  If
-   slave_process is false, the child process will continue running in this
-   case, until it is lucky enough to attempt to communicate with its creator
-   and thus get a SIGPIPE signal.
-
-   If exit_on_error is false, a child process id of -1 should be treated the
-   same way as a subprocess which accepts no input, produces no output and
-   terminates with exit code 127.  Why?  Some errors during posix_spawnp()
-   cause the function posix_spawnp() to return an error code; some other
-   errors cause the subprocess to exit with return code 127.  It is
-   implementation dependent which error is reported which way.  The caller
-   must treat both cases as equivalent.
-
-   It is recommended that no signal is blocked or ignored (i.e. have a
-   signal handler with value SIG_IGN) while any of these functions is called.
-   The reason is that child processes inherit the mask of blocked signals
-   from their parent (both through posix_spawn() and fork()/exec());
-   likewise, signals ignored in the parent are also ignored in the child
-   (except possibly for SIGCHLD).  And POSIX:2001 says [in the description
-   of exec()]:
-       "it should be noted that many existing applications wrongly
-        assume that they start with certain signals set to the default
-        action and/or unblocked. In particular, applications written
-        with a simpler signal model that does not include blocking of
-        signals, such as the one in the ISO C standard, may not behave
-        properly if invoked with some signals blocked. Therefore, it is
-        best not to block or ignore signals across execs without explicit
-        reason to do so, and especially not to block signals across execs
-        of arbitrary (not closely co-operating) programs."  */
-
-/* Open a pipe for output to a child process.
- * The child's stdout goes to a file.
- *
- *           write       system                read
- *    parent  ->   fd[0]   ->   STDIN_FILENO    ->   child
- *
- * Note: When writing to a child process, it is useful to ignore the SIGPIPE
- * signal and the EPIPE error code.
- */
-extern pid_t create_pipe_out (const char *progname,
-                              const char *prog_path, char **prog_argv,
-                              const char *prog_stdout, bool null_stderr,
-                              bool slave_process, bool exit_on_error,
-                              int fd[1]);
-
-/* Open a pipe for input from a child process.
- * The child's stdin comes from a file.
- *
- *           read        system                write
- *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
- *
- */
-extern pid_t create_pipe_in (const char *progname,
-                             const char *prog_path, char **prog_argv,
-                             const char *prog_stdin, bool null_stderr,
-                             bool slave_process, bool exit_on_error,
-                             int fd[1]);
-
-/* Open a bidirectional pipe.
- *
- *           write       system                read
- *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child
- *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
- *           read        system                write
- *
- * Note: When writing to a child process, it is useful to ignore the SIGPIPE
- * signal and the EPIPE error code.
- *
- * Note: The parent process must be careful to avoid deadlock.
- * 1) If you write more than PIPE_MAX bytes or, more generally, if you write
- *    more bytes than the subprocess can handle at once, the subprocess
- *    may write its data and wait on you to read it, but you are currently
- *    busy writing.
- * 2) When you don't know ahead of time how many bytes the subprocess
- *    will produce, the usual technique of calling read (fd, buf, BUFSIZ)
- *    with a fixed BUFSIZ will, on Linux 2.2.17 and on BSD systems, cause
- *    the read() call to block until *all* of the buffer has been filled.
- *    But the subprocess cannot produce more data until you gave it more
- *    input.  But you are currently busy reading from it.
- */
-extern pid_t create_pipe_bidi (const char *progname,
-                               const char *prog_path, char **prog_argv,
-                               bool null_stderr,
-                               bool slave_process, bool exit_on_error,
-                               int fd[2]);
-
-/* The name of the "always silent" device.  */
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-/* Native Woe32 API.  */
-# define DEV_NULL "NUL"
-#else
-/* Unix API.  */
-# define DEV_NULL "/dev/null"
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* _PIPE_H */
diff --git a/lib/spawn-pipe.c b/lib/spawn-pipe.c
new file mode 100644 (file)
index 0000000..809cccf
--- /dev/null
@@ -0,0 +1,450 @@
+/* Creation of subprocesses, communicating via pipes.
+   Copyright (C) 2001-2004, 2006-2010 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#include <config.h>
+
+/* Specification.  */
+#include "spawn-pipe.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "error.h"
+#include "fatal-signal.h"
+#include "unistd-safer.h"
+#include "wait-process.h"
+#include "gettext.h"
+
+#define _(str) gettext (str)
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+
+/* Native Woe32 API.  */
+# include <process.h>
+# include "w32spawn.h"
+
+#else
+
+/* Unix API.  */
+# include <spawn.h>
+
+#endif
+
+/* The results of open() in this file are not used with fchdir,
+   therefore save some unnecessary work in fchdir.c.  */
+#undef open
+#undef close
+
+
+#ifdef EINTR
+
+/* EINTR handling for close().
+   These functions can return -1/EINTR even though we don't have any
+   signal handlers set up, namely when we get interrupted via SIGSTOP.  */
+
+static inline int
+nonintr_close (int fd)
+{
+  int retval;
+
+  do
+    retval = close (fd);
+  while (retval < 0 && errno == EINTR);
+
+  return retval;
+}
+#define close nonintr_close
+
+static inline int
+nonintr_open (const char *pathname, int oflag, mode_t mode)
+{
+  int retval;
+
+  do
+    retval = open (pathname, oflag, mode);
+  while (retval < 0 && errno == EINTR);
+
+  return retval;
+}
+#undef open /* avoid warning on VMS */
+#define open nonintr_open
+
+#endif
+
+
+/* Open a pipe connected to a child process.
+ *
+ *           write       system                read
+ *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child       if pipe_stdin
+ *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child       if pipe_stdout
+ *           read        system                write
+ *
+ * At least one of pipe_stdin, pipe_stdout must be true.
+ * pipe_stdin and prog_stdin together determine the child's standard input.
+ * pipe_stdout and prog_stdout together determine the child's standard output.
+ * If pipe_stdin is true, prog_stdin is ignored.
+ * If pipe_stdout is true, prog_stdout is ignored.
+ */
+static pid_t
+create_pipe (const char *progname,
+             const char *prog_path, char **prog_argv,
+             bool pipe_stdin, bool pipe_stdout,
+             const char *prog_stdin, const char *prog_stdout,
+             bool null_stderr,
+             bool slave_process, bool exit_on_error,
+             int fd[2])
+{
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+
+  /* Native Woe32 API.
+     This uses _pipe(), dup2(), and spawnv().  It could also be implemented
+     using the low-level functions CreatePipe(), DuplicateHandle(),
+     CreateProcess() and _open_osfhandle(); see the GNU make and GNU clisp
+     and cvs source code.  */
+  int ifd[2];
+  int ofd[2];
+  int orig_stdin;
+  int orig_stdout;
+  int orig_stderr;
+  int child;
+  int nulloutfd;
+  int stdinfd;
+  int stdoutfd;
+  int saved_errno;
+
+  /* FIXME: Need to free memory allocated by prepare_spawn.  */
+  prog_argv = prepare_spawn (prog_argv);
+
+  if (pipe_stdout)
+    if (pipe2_safer (ifd, O_BINARY | O_CLOEXEC) < 0)
+      error (EXIT_FAILURE, errno, _("cannot create pipe"));
+  if (pipe_stdin)
+    if (pipe2_safer (ofd, O_BINARY | O_CLOEXEC) < 0)
+      error (EXIT_FAILURE, errno, _("cannot create pipe"));
+/* Data flow diagram:
+ *
+ *           write        system         read
+ *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
+ *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
+ *           read         system         write
+ *
+ */
+
+  /* Save standard file handles of parent process.  */
+  if (pipe_stdin || prog_stdin != NULL)
+    orig_stdin = dup_safer_noinherit (STDIN_FILENO);
+  if (pipe_stdout || prog_stdout != NULL)
+    orig_stdout = dup_safer_noinherit (STDOUT_FILENO);
+  if (null_stderr)
+    orig_stderr = dup_safer_noinherit (STDERR_FILENO);
+  child = -1;
+
+  /* Create standard file handles of child process.  */
+  nulloutfd = -1;
+  stdinfd = -1;
+  stdoutfd = -1;
+  if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
+      && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
+      && (!null_stderr
+          || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
+              && (nulloutfd == STDERR_FILENO
+                  || (dup2 (nulloutfd, STDERR_FILENO) >= 0
+                      && close (nulloutfd) >= 0))))
+      && (pipe_stdin
+          || prog_stdin == NULL
+          || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
+              && (stdinfd == STDIN_FILENO
+                  || (dup2 (stdinfd, STDIN_FILENO) >= 0
+                      && close (stdinfd) >= 0))))
+      && (pipe_stdout
+          || prog_stdout == NULL
+          || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
+              && (stdoutfd == STDOUT_FILENO
+                  || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
+                      && close (stdoutfd) >= 0)))))
+    /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
+       but it inherits all open()ed or dup2()ed file handles (which is what
+       we want in the case of STD*_FILENO).  */
+    /* Use spawnvpe and pass the environment explicitly.  This is needed if
+       the program has modified the environment using putenv() or [un]setenv().
+       On Windows, programs have two environments, one in the "environment
+       block" of the process and managed through SetEnvironmentVariable(), and
+       one inside the process, in the location retrieved by the 'environ'
+       macro.  When using spawnvp() without 'e', the child process inherits a
+       copy of the environment block - ignoring the effects of putenv() and
+       [un]setenv().  */
+    {
+      child = spawnvpe (P_NOWAIT, prog_path, (const char **) prog_argv,
+                        (const char **) environ);
+      if (child < 0 && errno == ENOEXEC)
+        {
+          /* prog is not an native executable.  Try to execute it as a
+             shell script.  Note that prepare_spawn() has already prepended
+             a hidden element "sh.exe" to prog_argv.  */
+          --prog_argv;
+          child = spawnvpe (P_NOWAIT, prog_argv[0], (const char **) prog_argv,
+                            (const char **) environ);
+        }
+    }
+  if (child == -1)
+    saved_errno = errno;
+  if (stdinfd >= 0)
+    close (stdinfd);
+  if (stdoutfd >= 0)
+    close (stdoutfd);
+  if (nulloutfd >= 0)
+    close (nulloutfd);
+
+  /* Restore standard file handles of parent process.  */
+  if (null_stderr)
+    undup_safer_noinherit (orig_stderr, STDERR_FILENO);
+  if (pipe_stdout || prog_stdout != NULL)
+    undup_safer_noinherit (orig_stdout, STDOUT_FILENO);
+  if (pipe_stdin || prog_stdin != NULL)
+    undup_safer_noinherit (orig_stdin, STDIN_FILENO);
+
+  if (pipe_stdin)
+    close (ofd[0]);
+  if (pipe_stdout)
+    close (ifd[1]);
+  if (child == -1)
+    {
+      if (exit_on_error || !null_stderr)
+        error (exit_on_error ? EXIT_FAILURE : 0, saved_errno,
+               _("%s subprocess failed"), progname);
+      if (pipe_stdout)
+        close (ifd[0]);
+      if (pipe_stdin)
+        close (ofd[1]);
+      errno = saved_errno;
+      return -1;
+    }
+
+  if (pipe_stdout)
+    fd[0] = ifd[0];
+  if (pipe_stdin)
+    fd[1] = ofd[1];
+  return child;
+
+#else
+
+  /* Unix API.  */
+  int ifd[2];
+  int ofd[2];
+  sigset_t blocked_signals;
+  posix_spawn_file_actions_t actions;
+  bool actions_allocated;
+  posix_spawnattr_t attrs;
+  bool attrs_allocated;
+  int err;
+  pid_t child;
+
+  if (pipe_stdout)
+    if (pipe_safer (ifd) < 0)
+      error (EXIT_FAILURE, errno, _("cannot create pipe"));
+  if (pipe_stdin)
+    if (pipe_safer (ofd) < 0)
+      error (EXIT_FAILURE, errno, _("cannot create pipe"));
+/* Data flow diagram:
+ *
+ *           write        system         read
+ *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
+ *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
+ *           read         system         write
+ *
+ */
+
+  if (slave_process)
+    {
+      sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
+      block_fatal_signals ();
+    }
+  actions_allocated = false;
+  attrs_allocated = false;
+  if ((err = posix_spawn_file_actions_init (&actions)) != 0
+      || (actions_allocated = true,
+          (pipe_stdin
+           && (err = posix_spawn_file_actions_adddup2 (&actions,
+                                                       ofd[0], STDIN_FILENO))
+              != 0)
+          || (pipe_stdout
+              && (err = posix_spawn_file_actions_adddup2 (&actions,
+                                                          ifd[1], STDOUT_FILENO))
+                 != 0)
+          || (pipe_stdin
+              && (err = posix_spawn_file_actions_addclose (&actions, ofd[0]))
+                 != 0)
+          || (pipe_stdout
+              && (err = posix_spawn_file_actions_addclose (&actions, ifd[1]))
+                 != 0)
+          || (pipe_stdin
+              && (err = posix_spawn_file_actions_addclose (&actions, ofd[1]))
+                 != 0)
+          || (pipe_stdout
+              && (err = posix_spawn_file_actions_addclose (&actions, ifd[0]))
+                 != 0)
+          || (null_stderr
+              && (err = posix_spawn_file_actions_addopen (&actions,
+                                                          STDERR_FILENO,
+                                                          "/dev/null", O_RDWR,
+                                                          0))
+                 != 0)
+          || (!pipe_stdin
+              && prog_stdin != NULL
+              && (err = posix_spawn_file_actions_addopen (&actions,
+                                                          STDIN_FILENO,
+                                                          prog_stdin, O_RDONLY,
+                                                          0))
+                 != 0)
+          || (!pipe_stdout
+              && prog_stdout != NULL
+              && (err = posix_spawn_file_actions_addopen (&actions,
+                                                          STDOUT_FILENO,
+                                                          prog_stdout, O_WRONLY,
+                                                          0))
+                 != 0)
+          || (slave_process
+              && ((err = posix_spawnattr_init (&attrs)) != 0
+                  || (attrs_allocated = true,
+                      (err = posix_spawnattr_setsigmask (&attrs,
+                                                         &blocked_signals))
+                      != 0
+                      || (err = posix_spawnattr_setflags (&attrs,
+                                                        POSIX_SPAWN_SETSIGMASK))
+                         != 0)))
+          || (err = posix_spawnp (&child, prog_path, &actions,
+                                  attrs_allocated ? &attrs : NULL, prog_argv,
+                                  environ))
+             != 0))
+    {
+      if (actions_allocated)
+        posix_spawn_file_actions_destroy (&actions);
+      if (attrs_allocated)
+        posix_spawnattr_destroy (&attrs);
+      if (slave_process)
+        unblock_fatal_signals ();
+      if (exit_on_error || !null_stderr)
+        error (exit_on_error ? EXIT_FAILURE : 0, err,
+               _("%s subprocess failed"), progname);
+      if (pipe_stdout)
+        {
+          close (ifd[0]);
+          close (ifd[1]);
+        }
+      if (pipe_stdin)
+        {
+          close (ofd[0]);
+          close (ofd[1]);
+        }
+      errno = err;
+      return -1;
+    }
+  posix_spawn_file_actions_destroy (&actions);
+  if (attrs_allocated)
+    posix_spawnattr_destroy (&attrs);
+  if (slave_process)
+    {
+      register_slave_subprocess (child);
+      unblock_fatal_signals ();
+    }
+  if (pipe_stdin)
+    close (ofd[0]);
+  if (pipe_stdout)
+    close (ifd[1]);
+
+  if (pipe_stdout)
+    fd[0] = ifd[0];
+  if (pipe_stdin)
+    fd[1] = ofd[1];
+  return child;
+
+#endif
+}
+
+/* Open a bidirectional pipe.
+ *
+ *           write       system                read
+ *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child
+ *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
+ *           read        system                write
+ *
+ */
+pid_t
+create_pipe_bidi (const char *progname,
+                  const char *prog_path, char **prog_argv,
+                  bool null_stderr,
+                  bool slave_process, bool exit_on_error,
+                  int fd[2])
+{
+  pid_t result = create_pipe (progname, prog_path, prog_argv,
+                              true, true, NULL, NULL,
+                              null_stderr, slave_process, exit_on_error,
+                              fd);
+  return result;
+}
+
+/* Open a pipe for input from a child process.
+ * The child's stdin comes from a file.
+ *
+ *           read        system                write
+ *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
+ *
+ */
+pid_t
+create_pipe_in (const char *progname,
+                const char *prog_path, char **prog_argv,
+                const char *prog_stdin, bool null_stderr,
+                bool slave_process, bool exit_on_error,
+                int fd[1])
+{
+  int iofd[2];
+  pid_t result = create_pipe (progname, prog_path, prog_argv,
+                              false, true, prog_stdin, NULL,
+                              null_stderr, slave_process, exit_on_error,
+                              iofd);
+  if (result != -1)
+    fd[0] = iofd[0];
+  return result;
+}
+
+/* Open a pipe for output to a child process.
+ * The child's stdout goes to a file.
+ *
+ *           write       system                read
+ *    parent  ->   fd[0]   ->   STDIN_FILENO    ->   child
+ *
+ */
+pid_t
+create_pipe_out (const char *progname,
+                 const char *prog_path, char **prog_argv,
+                 const char *prog_stdout, bool null_stderr,
+                 bool slave_process, bool exit_on_error,
+                 int fd[1])
+{
+  int iofd[2];
+  pid_t result = create_pipe (progname, prog_path, prog_argv,
+                              true, false, NULL, prog_stdout,
+                              null_stderr, slave_process, exit_on_error,
+                              iofd);
+  if (result != -1)
+    fd[0] = iofd[1];
+  return result;
+}
diff --git a/lib/spawn-pipe.h b/lib/spawn-pipe.h
new file mode 100644 (file)
index 0000000..449583d
--- /dev/null
@@ -0,0 +1,147 @@
+/* Creation of subprocesses, communicating via pipes.
+   Copyright (C) 2001-2003, 2006, 2008-2010 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _SPAWN_PIPE_H
+#define _SPAWN_PIPE_H
+
+/* Get pid_t.  */
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <stdbool.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* All these functions create a subprocess and don't wait for its termination.
+   They return the process id of the subprocess.  They also return in fd[]
+   one or two file descriptors for communication with the subprocess.
+   If the subprocess creation fails: if exit_on_error is true, the main
+   process exits with an error message; otherwise, an error message is given
+   if null_stderr is false, then -1 is returned, with errno set, and fd[]
+   remain uninitialized.
+
+   After finishing communication, the caller should call wait_subprocess()
+   to get rid of the subprocess in the process table.
+
+   If slave_process is true, the child process will be terminated when its
+   creator receives a catchable fatal signal or exits normally.  If
+   slave_process is false, the child process will continue running in this
+   case, until it is lucky enough to attempt to communicate with its creator
+   and thus get a SIGPIPE signal.
+
+   If exit_on_error is false, a child process id of -1 should be treated the
+   same way as a subprocess which accepts no input, produces no output and
+   terminates with exit code 127.  Why?  Some errors during posix_spawnp()
+   cause the function posix_spawnp() to return an error code; some other
+   errors cause the subprocess to exit with return code 127.  It is
+   implementation dependent which error is reported which way.  The caller
+   must treat both cases as equivalent.
+
+   It is recommended that no signal is blocked or ignored (i.e. have a
+   signal handler with value SIG_IGN) while any of these functions is called.
+   The reason is that child processes inherit the mask of blocked signals
+   from their parent (both through posix_spawn() and fork()/exec());
+   likewise, signals ignored in the parent are also ignored in the child
+   (except possibly for SIGCHLD).  And POSIX:2001 says [in the description
+   of exec()]:
+       "it should be noted that many existing applications wrongly
+        assume that they start with certain signals set to the default
+        action and/or unblocked. In particular, applications written
+        with a simpler signal model that does not include blocking of
+        signals, such as the one in the ISO C standard, may not behave
+        properly if invoked with some signals blocked. Therefore, it is
+        best not to block or ignore signals across execs without explicit
+        reason to do so, and especially not to block signals across execs
+        of arbitrary (not closely co-operating) programs."  */
+
+/* Open a pipe for output to a child process.
+ * The child's stdout goes to a file.
+ *
+ *           write       system                read
+ *    parent  ->   fd[0]   ->   STDIN_FILENO    ->   child
+ *
+ * Note: When writing to a child process, it is useful to ignore the SIGPIPE
+ * signal and the EPIPE error code.
+ */
+extern pid_t create_pipe_out (const char *progname,
+                              const char *prog_path, char **prog_argv,
+                              const char *prog_stdout, bool null_stderr,
+                              bool slave_process, bool exit_on_error,
+                              int fd[1]);
+
+/* Open a pipe for input from a child process.
+ * The child's stdin comes from a file.
+ *
+ *           read        system                write
+ *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
+ *
+ */
+extern pid_t create_pipe_in (const char *progname,
+                             const char *prog_path, char **prog_argv,
+                             const char *prog_stdin, bool null_stderr,
+                             bool slave_process, bool exit_on_error,
+                             int fd[1]);
+
+/* Open a bidirectional pipe.
+ *
+ *           write       system                read
+ *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child
+ *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
+ *           read        system                write
+ *
+ * Note: When writing to a child process, it is useful to ignore the SIGPIPE
+ * signal and the EPIPE error code.
+ *
+ * Note: The parent process must be careful to avoid deadlock.
+ * 1) If you write more than PIPE_MAX bytes or, more generally, if you write
+ *    more bytes than the subprocess can handle at once, the subprocess
+ *    may write its data and wait on you to read it, but you are currently
+ *    busy writing.
+ * 2) When you don't know ahead of time how many bytes the subprocess
+ *    will produce, the usual technique of calling read (fd, buf, BUFSIZ)
+ *    with a fixed BUFSIZ will, on Linux 2.2.17 and on BSD systems, cause
+ *    the read() call to block until *all* of the buffer has been filled.
+ *    But the subprocess cannot produce more data until you gave it more
+ *    input.  But you are currently busy reading from it.
+ */
+extern pid_t create_pipe_bidi (const char *progname,
+                               const char *prog_path, char **prog_argv,
+                               bool null_stderr,
+                               bool slave_process, bool exit_on_error,
+                               int fd[2]);
+
+/* The name of the "always silent" device.  */
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Native Woe32 API.  */
+# define DEV_NULL "NUL"
+#else
+/* Unix API.  */
+# define DEV_NULL "/dev/null"
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SPAWN_PIPE_H */
diff --git a/m4/pipe.m4 b/m4/pipe.m4
deleted file mode 100644 (file)
index 401881c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# pipe.m4 serial 4
-dnl Copyright (C) 2004, 2008, 2009, 2010 Free Software Foundation, Inc.
-dnl This file is free software; the Free Software Foundation
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-AC_DEFUN([gl_PIPE],
-[
-  dnl Prerequisites of lib/pipe.c.
-  AC_REQUIRE([AC_C_INLINE])
-  AC_REQUIRE([AC_TYPE_MODE_T])
-])
diff --git a/m4/spawn-pipe.m4 b/m4/spawn-pipe.m4
new file mode 100644 (file)
index 0000000..022c5a0
--- /dev/null
@@ -0,0 +1,12 @@
+# spawn-pipe.m4 serial 1
+dnl Copyright (C) 2004, 2008-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_SPAWN_PIPE],
+[
+  dnl Prerequisites of lib/spawn-pipe.c.
+  AC_REQUIRE([AC_C_INLINE])
+  AC_REQUIRE([AC_TYPE_MODE_T])
+])
index 3b3ee90..853ad84 100644 (file)
@@ -9,7 +9,7 @@ Depends-on:
 stdbool
 xmalloca
 execute
-pipe
+spawn-pipe
 wait-process
 getline
 sh-quote
index 3bc33b8..6cb6845 100644 (file)
@@ -10,7 +10,7 @@ stdbool
 unistd
 javaversion
 execute
-pipe
+spawn-pipe
 wait-process
 classpath
 xsetenv
index 8011077..bf1a47b 100644 (file)
@@ -10,7 +10,7 @@ lib/javaversion.class
 Depends-on:
 javaexec
 stdbool
-pipe
+spawn-pipe
 wait-process
 getline
 gettext-h
index 922bda1..3d6ccee 100644 (file)
@@ -1,48 +1,23 @@
 Description:
 Creation of subprocesses, communicating via pipes.
 
+Status:
+obsolete
+
+Notice:
+This module is obsolete. Use the module 'spawn-pipe' instead.
+
 Files:
-lib/pipe.h
-lib/pipe.c
-lib/w32spawn.h
-m4/pipe.m4
 
 Depends-on:
-cloexec
-dup2
-environ
-error
-exit
-fatal-signal
-gettext-h
-open
-pipe2
-pipe2-safer
-spawn
-posix_spawnp
-posix_spawn_file_actions_init
-posix_spawn_file_actions_addclose
-posix_spawn_file_actions_adddup2
-posix_spawn_file_actions_addopen
-posix_spawn_file_actions_destroy
-posix_spawnattr_init
-posix_spawnattr_setsigmask
-posix_spawnattr_setflags
-posix_spawnattr_destroy
-stdbool
-strpbrk
-unistd
-unistd-safer
-wait-process
+spawn-pipe
 
 configure.ac:
-gl_PIPE
 
 Makefile.am:
-lib_SOURCES += pipe.h pipe.c w32spawn.h
 
 Include:
-"pipe.h"
+"spawn-pipe.h"
 
 License:
 GPL
index 95ab27a..7122c1a 100644 (file)
@@ -7,7 +7,7 @@ lib/pipe-filter-gi.c
 lib/pipe-filter-aux.h
 
 Depends-on:
-pipe
+spawn-pipe
 wait-process
 error
 exit
index 6ae2801..f845a8f 100644 (file)
@@ -7,7 +7,7 @@ lib/pipe-filter-ii.c
 lib/pipe-filter-aux.h
 
 Depends-on:
-pipe
+spawn-pipe
 wait-process
 error
 exit
diff --git a/modules/pipe-tests b/modules/pipe-tests
deleted file mode 100644 (file)
index b20ea68..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-Files:
-tests/test-pipe.sh
-tests/test-pipe.c
-tests/macros.h
-
-Depends-on:
-progname
-
-configure.ac:
-
-Makefile.am:
-TESTS += test-pipe.sh
-check_PROGRAMS += test-pipe
-test_pipe_LDADD = $(LDADD) @LIBINTL@
diff --git a/modules/spawn-pipe b/modules/spawn-pipe
new file mode 100644 (file)
index 0000000..04441b1
--- /dev/null
@@ -0,0 +1,51 @@
+Description:
+Creation of subprocesses, communicating via pipes.
+
+Files:
+lib/spawn-pipe.h
+lib/spawn-pipe.c
+lib/w32spawn.h
+m4/spawn-pipe.m4
+
+Depends-on:
+cloexec
+dup2
+environ
+error
+exit
+fatal-signal
+gettext-h
+open
+pipe2
+pipe2-safer
+spawn
+posix_spawnp
+posix_spawn_file_actions_init
+posix_spawn_file_actions_addclose
+posix_spawn_file_actions_adddup2
+posix_spawn_file_actions_addopen
+posix_spawn_file_actions_destroy
+posix_spawnattr_init
+posix_spawnattr_setsigmask
+posix_spawnattr_setflags
+posix_spawnattr_destroy
+stdbool
+strpbrk
+unistd
+unistd-safer
+wait-process
+
+configure.ac:
+gl_SPAWN_PIPE
+
+Makefile.am:
+lib_SOURCES += spawn-pipe.h spawn-pipe.c w32spawn.h
+
+Include:
+"spawn-pipe.h"
+
+License:
+GPL
+
+Maintainer:
+Bruno Haible
diff --git a/modules/spawn-pipe-tests b/modules/spawn-pipe-tests
new file mode 100644 (file)
index 0000000..c559033
--- /dev/null
@@ -0,0 +1,14 @@
+Files:
+tests/test-spawn-pipe.sh
+tests/test-spawn-pipe.c
+tests/macros.h
+
+Depends-on:
+progname
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-spawn-pipe.sh
+check_PROGRAMS += test-spawn-pipe
+test_spawn_pipe_LDADD = $(LDADD) @LIBINTL@
diff --git a/tests/test-pipe.c b/tests/test-pipe.c
deleted file mode 100644 (file)
index 2dcab58..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/* Test of create_pipe_bidi/wait_subprocess.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
-
-#include <config.h>
-
-#include "pipe.h"
-#include "wait-process.h"
-
-#include <errno.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-/* Depending on arguments, this test intentionally closes stderr or
-   starts life with stderr closed.  So, we arrange to have fd 10
-   (outside the range of interesting fd's during the test) set up to
-   duplicate the original stderr.  */
-
-#define BACKUP_STDERR_FILENO 10
-#define ASSERT_STREAM myerr
-#include "macros.h"
-
-static FILE *myerr;
-
-/* Code executed by the child process.  argv[1] = "child".  */
-static int
-child_main (int argc, char *argv[])
-{
-  char buffer[2] = { 's', 't' };
-  int fd;
-  int ret;
-
-  ASSERT (argc == 3);
-
-  /* Read one byte from fd 0, and write its value plus one to fd 1.
-     fd 2 should be closed iff the argument is 1.  Check that no other file
-     descriptors leaked.  */
-
-  ASSERT (read (STDIN_FILENO, buffer, 2) == 1);
-
-  buffer[0]++;
-  ASSERT (write (STDOUT_FILENO, buffer, 1) == 1);
-
-  errno = 0;
-  ret = dup2 (STDERR_FILENO, STDERR_FILENO);
-  switch (atoi (argv[2]))
-    {
-    case 0:
-      /* Expect fd 2 is open.  */
-      ASSERT (ret == STDERR_FILENO);
-      break;
-    case 1:
-      /* Expect fd 2 is closed.  */
-      ASSERT (ret == -1);
-      ASSERT (errno == EBADF);
-      break;
-    default:
-      ASSERT (false);
-    }
-
-  for (fd = 3; fd < 7; fd++)
-    {
-      errno = 0;
-      ASSERT (close (fd) == -1);
-      ASSERT (errno == EBADF);
-    }
-
-  return 0;
-}
-
-/* Create a bi-directional pipe to a test child, and validate that the
-   child program returns the expected output.  The child is the same
-   program as the parent ARGV0, but with different arguments.
-   STDERR_CLOSED is true if we have already closed fd 2.  */
-static void
-test_pipe (const char *argv0, bool stderr_closed)
-{
-  int fd[2];
-  char *argv[4];
-  pid_t pid;
-  char buffer[2] = { 'a', 't' };
-
-  /* Set up child.  */
-  argv[0] = (char *) argv0;
-  argv[1] = (char *) "child";
-  argv[2] = (char *) (stderr_closed ? "1" : "0");
-  argv[3] = NULL;
-  pid = create_pipe_bidi (argv0, argv0, argv, false, true, true, fd);
-  ASSERT (0 <= pid);
-  ASSERT (STDERR_FILENO < fd[0]);
-  ASSERT (STDERR_FILENO < fd[1]);
-
-  /* Push child's input.  */
-  ASSERT (write (fd[1], buffer, 1) == 1);
-  ASSERT (close (fd[1]) == 0);
-
-  /* Get child's output.  */
-  ASSERT (read (fd[0], buffer, 2) == 1);
-
-  /* Wait for child.  */
-  ASSERT (wait_subprocess (pid, argv0, true, false, true, true, NULL) == 0);
-  ASSERT (close (fd[0]) == 0);
-
-  /* Check the result.  */
-  ASSERT (buffer[0] == 'b');
-  ASSERT (buffer[1] == 't');
-}
-
-/* Code executed by the parent process.  */
-static int
-parent_main (int argc, char *argv[])
-{
-  int test;
-  int fd;
-
-  ASSERT (argc == 2);
-
-  /* Selectively close various standard fds, to verify the child process is
-     not impacted by this.  */
-  test = atoi (argv[1]);
-  switch (test)
-    {
-    case 0:
-      break;
-    case 1:
-      close (0);
-      break;
-    case 2:
-      close (1);
-      break;
-    case 3:
-      close (0);
-      close (1);
-      break;
-    case 4:
-      close (2);
-      break;
-    case 5:
-      close (0);
-      close (2);
-      break;
-    case 6:
-      close (1);
-      close (2);
-      break;
-    case 7:
-      close (0);
-      close (1);
-      close (2);
-      break;
-    default:
-      ASSERT (false);
-    }
-
-  /* Plug any file descriptor leaks inherited from outside world before
-     starting, so that child has a clean slate (at least for the fds that we
-     might be manipulating).  */
-  for (fd = 3; fd < 7; fd++)
-    close (fd);
-
-  test_pipe (argv[0], test >= 4);
-
-  return 0;
-}
-
-int
-main (int argc, char *argv[])
-{
-  if (argc < 2)
-    {
-      fprintf (stderr, "%s: need arguments\n", argv[0]);
-      return 2;
-    }
-  if (strcmp (argv[1], "child") == 0)
-    {
-      /* fd 2 might be closed, but fd BACKUP_STDERR_FILENO is the original
-         stderr.  */
-      myerr = fdopen (BACKUP_STDERR_FILENO, "w");
-      if (!myerr)
-        return 2;
-      return child_main (argc, argv);
-    }
-  /* We might close fd 2 later, so save it in fd 10.  */
-  if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
-      || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
-    return 2;
-  return parent_main (argc, argv);
-}
diff --git a/tests/test-pipe.sh b/tests/test-pipe.sh
deleted file mode 100755 (executable)
index 323c90f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-st=0
-for i in 0 1 2 3 4 5 6 7 ; do
-  ./test-pipe${EXEEXT} $i \
-    || { echo test-pipe.sh: iteration $i failed >&2; st=1; }
-done
-exit $st
diff --git a/tests/test-spawn-pipe.c b/tests/test-spawn-pipe.c
new file mode 100644 (file)
index 0000000..1f606f0
--- /dev/null
@@ -0,0 +1,204 @@
+/* Test of create_pipe_bidi/wait_subprocess.
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <config.h>
+
+#include "spawn-pipe.h"
+#include "wait-process.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Depending on arguments, this test intentionally closes stderr or
+   starts life with stderr closed.  So, we arrange to have fd 10
+   (outside the range of interesting fd's during the test) set up to
+   duplicate the original stderr.  */
+
+#define BACKUP_STDERR_FILENO 10
+#define ASSERT_STREAM myerr
+#include "macros.h"
+
+static FILE *myerr;
+
+/* Code executed by the child process.  argv[1] = "child".  */
+static int
+child_main (int argc, char *argv[])
+{
+  char buffer[2] = { 's', 't' };
+  int fd;
+  int ret;
+
+  ASSERT (argc == 3);
+
+  /* Read one byte from fd 0, and write its value plus one to fd 1.
+     fd 2 should be closed iff the argument is 1.  Check that no other file
+     descriptors leaked.  */
+
+  ASSERT (read (STDIN_FILENO, buffer, 2) == 1);
+
+  buffer[0]++;
+  ASSERT (write (STDOUT_FILENO, buffer, 1) == 1);
+
+  errno = 0;
+  ret = dup2 (STDERR_FILENO, STDERR_FILENO);
+  switch (atoi (argv[2]))
+    {
+    case 0:
+      /* Expect fd 2 is open.  */
+      ASSERT (ret == STDERR_FILENO);
+      break;
+    case 1:
+      /* Expect fd 2 is closed.  */
+      ASSERT (ret == -1);
+      ASSERT (errno == EBADF);
+      break;
+    default:
+      ASSERT (false);
+    }
+
+  for (fd = 3; fd < 7; fd++)
+    {
+      errno = 0;
+      ASSERT (close (fd) == -1);
+      ASSERT (errno == EBADF);
+    }
+
+  return 0;
+}
+
+/* Create a bi-directional pipe to a test child, and validate that the
+   child program returns the expected output.  The child is the same
+   program as the parent ARGV0, but with different arguments.
+   STDERR_CLOSED is true if we have already closed fd 2.  */
+static void
+test_pipe (const char *argv0, bool stderr_closed)
+{
+  int fd[2];
+  char *argv[4];
+  pid_t pid;
+  char buffer[2] = { 'a', 't' };
+
+  /* Set up child.  */
+  argv[0] = (char *) argv0;
+  argv[1] = (char *) "child";
+  argv[2] = (char *) (stderr_closed ? "1" : "0");
+  argv[3] = NULL;
+  pid = create_pipe_bidi (argv0, argv0, argv, false, true, true, fd);
+  ASSERT (0 <= pid);
+  ASSERT (STDERR_FILENO < fd[0]);
+  ASSERT (STDERR_FILENO < fd[1]);
+
+  /* Push child's input.  */
+  ASSERT (write (fd[1], buffer, 1) == 1);
+  ASSERT (close (fd[1]) == 0);
+
+  /* Get child's output.  */
+  ASSERT (read (fd[0], buffer, 2) == 1);
+
+  /* Wait for child.  */
+  ASSERT (wait_subprocess (pid, argv0, true, false, true, true, NULL) == 0);
+  ASSERT (close (fd[0]) == 0);
+
+  /* Check the result.  */
+  ASSERT (buffer[0] == 'b');
+  ASSERT (buffer[1] == 't');
+}
+
+/* Code executed by the parent process.  */
+static int
+parent_main (int argc, char *argv[])
+{
+  int test;
+  int fd;
+
+  ASSERT (argc == 2);
+
+  /* Selectively close various standard fds, to verify the child process is
+     not impacted by this.  */
+  test = atoi (argv[1]);
+  switch (test)
+    {
+    case 0:
+      break;
+    case 1:
+      close (0);
+      break;
+    case 2:
+      close (1);
+      break;
+    case 3:
+      close (0);
+      close (1);
+      break;
+    case 4:
+      close (2);
+      break;
+    case 5:
+      close (0);
+      close (2);
+      break;
+    case 6:
+      close (1);
+      close (2);
+      break;
+    case 7:
+      close (0);
+      close (1);
+      close (2);
+      break;
+    default:
+      ASSERT (false);
+    }
+
+  /* Plug any file descriptor leaks inherited from outside world before
+     starting, so that child has a clean slate (at least for the fds that we
+     might be manipulating).  */
+  for (fd = 3; fd < 7; fd++)
+    close (fd);
+
+  test_pipe (argv[0], test >= 4);
+
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  if (argc < 2)
+    {
+      fprintf (stderr, "%s: need arguments\n", argv[0]);
+      return 2;
+    }
+  if (strcmp (argv[1], "child") == 0)
+    {
+      /* fd 2 might be closed, but fd BACKUP_STDERR_FILENO is the original
+         stderr.  */
+      myerr = fdopen (BACKUP_STDERR_FILENO, "w");
+      if (!myerr)
+        return 2;
+      return child_main (argc, argv);
+    }
+  /* We might close fd 2 later, so save it in fd 10.  */
+  if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
+      || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
+    return 2;
+  return parent_main (argc, argv);
+}
diff --git a/tests/test-spawn-pipe.sh b/tests/test-spawn-pipe.sh
new file mode 100755 (executable)
index 0000000..2e4ea12
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+st=0
+for i in 0 1 2 3 4 5 6 7 ; do
+  ./test-spawn-pipe${EXEEXT} $i \
+    || { echo test-spawn-pipe.sh: iteration $i failed >&2; st=1; }
+done
+exit $st