bug-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: CVS problem with ssh


From: Paul Eggert
Subject: Re: CVS problem with ssh
Date: Sat, 16 Jul 2005 18:58:05 -0700
User-agent: Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux)

It is possible to fix the problem without creating an intervening "cat
-u"-like process as was done in the patch I just sent in.  This can be
done by creating a pipe, redirecting ssh's stderr into this pipe, and
having cvs read from the pipe and write to stderr.  I sketched out a
solution to this problem, enclosed below, but I haven't had time to
make it real (it doesn't work as written).

I'm sending this incomplete patch only because perhaps someone else
might want to run with it.

diff -pubr cvs-1.12.12/src/buffer.c cvs-1.12.12-nonblock-1/src/buffer.c
--- cvs-1.12.12/src/buffer.c    2005-03-17 11:42:23.000000000 -0800
+++ cvs-1.12.12-nonblock-1/src/buffer.c 2005-07-16 12:18:30.000000000 -0700
@@ -1717,6 +1717,8 @@ struct fd_buffer
 {
     /* The file descriptor.  */
     int fd;
+    /* The error file descriptor, or -1 if this does not apply.  */
+    int errorfd;
     /* Nonzero if the file descriptor is in blocking mode.  */
     int blocking;
     /* The child process id when fd is a pipe.  */
@@ -1733,18 +1735,21 @@ static int fd_buffer_get_fd (void *);
 static int fd_buffer_shutdown (struct buffer *);
 
 /* Initialize a buffer built on a file descriptor.  FD is the file
-   descriptor.  INPUT is nonzero if this is for input, zero if this is
-   for output.  MEMORY is the function to call when a memory error
-   occurs.  */
+   descriptor.  ERRORFD is an error file descriptor; normally it is
+   -1, representing an unused value, but can be nonnegative if FD is
+   an input FD; ERRORFD represents stderr from the same process.
+   INPUT is nonzero if FD is for input, zero if for output.  MEMORY is
+   the function to call when a memory error occurs.  */
 
 struct buffer *
-fd_buffer_initialize (int fd, pid_t child_pid, cvsroot_t *root, bool input,
-                      void (*memory) (struct buffer *))
+fd_buffer_initialize (int fd, int errorfd, pid_t child_pid, cvsroot_t *root,
+                     bool input, void (*memory) (struct buffer *))
 {
     struct fd_buffer *n;
 
     n = xmalloc (sizeof *n);
     n->fd = fd;
+    n->errorfd = errorfd;
     n->child_pid = child_pid;
     n->root = root;
     fd_buffer_block (n, true);
@@ -1758,10 +1763,34 @@ fd_buffer_initialize (int fd, pid_t chil
 }
 
 
+/* If ERRORFD is a file descriptor, copy it to standard error.
+   Return true if successful, false if EOF reached.  */
+
+static bool
+copy_error_fd (int errorfd)
+{
+    if (0 <= errorfd)
+       for (;;)
+       {
+           char errbuf [1 << 13];
+           ssize_t r = read (errorfd, errbuf, sizeof errbuf);
+           if (0 < r)
+           {
+               fflush (stdout);
+               fwrite (errbuf, 1, r, stderr);
+           }
+           else if (r == 0)
+               return false;
+           else if (r < 0 && errno != EINTR)
+               break;
+       }
+
+    return true;
+}
 
 /* The buffer input function for a buffer built on a file descriptor.
  *
- * In non-blocing mode, this function will read as many bytes as it can in a
+ * In non-blocking mode, this function will read as many bytes as it can in a
  * single try, up to SIZE bytes, and return.
  *
  * In blocking mode with NEED > 0, this function will read as many bytes as it
@@ -1801,6 +1830,11 @@ fd_buffer_input (void *closure, char *da
 {
     struct fd_buffer *fb = closure;
     int nbytes;
+    int numfds;
+    int errorfd = fb->errorfd;
+    int maxfd = MAX (fb->fd, errorfd);
+    fd_set readfds;
+    char errbuf[1 << 13];
 
     assert (need <= size);
 
@@ -1809,28 +1843,39 @@ fd_buffer_input (void *closure, char *da
     if (fb->blocking)
     {
        int status;
-       fd_set readfds;
 
        /* Set non-block.  */
         status = fd_buffer_block (fb, false);
        if (status != 0) return status;
 
-       FD_ZERO (&readfds);
-       FD_SET (fb->fd, &readfds);
        do
        {
-           int numfds;
-
            do {
                /* This used to select on exceptions too, but as far
                   as I know there was never any reason to do that and
                   SCO doesn't let you select on exceptions on pipes.  */
-               numfds = select (fb->fd + 1, &readfds, NULL, NULL, NULL);
+               FD_ZERO (&readfds);
+               FD_SET (fb->fd, &readfds);
+               if (0 <= errorfd)
+                   FD_SET (errorfd, &readfds);
+               numfds = select (maxfd + 1, &readfds, NULL, NULL, NULL);
                if (numfds < 0 && errno != EINTR)
                {
                    status = errno;
                    goto block_done;
                }
+               if (0 < numfds && 0 <= errorfd && FD_ISSET (errorfd, &readfds))
+               {
+                   ssize_t r = read (errorfd, errbuf, sizeof errbuf);
+                   if (r == 0)
+                       fb->errorfd = errorfd = -1;
+                   else if (0 < r)
+                   {
+                       fflush (stdout);
+                       fwrite (errbuf, 1, r, stderr);
+                   }
+                   continue;
+               }
            } while (numfds < 0);
 
            nbytes = read (fb->fd, data + *got, size - *got);
@@ -1883,6 +1928,10 @@ block_done:
     }
 
     /* The above will always return.  Handle non-blocking read.  */
+
+    if (! copy_error_fd (errorfd))
+       fb->errorfd = -1;
+
     nbytes = read (fb->fd, data, size);
 
     if (nbytes > 0)
@@ -1954,11 +2003,12 @@ fd_buffer_output (void *closure, const c
 static int
 fd_buffer_flush (void *closure)
 {
-    /* We don't need to do anything here.  Our fd doesn't have its own buffer
+    struct fd_buffer *fb = closure;
+    copy_error_fd (fb->errorfd);
+
+    /* We don't need to sync here.  Our fd doesn't have its own buffer
      * and syncing won't do anything but slow us down.
      *
-     * struct fd_buffer *fb = closure;
-     *
      * if (fsync (fb->fd) < 0 && errno != EROFS && errno != EINVAL)
      *     return errno;
      */
@@ -1970,15 +2020,13 @@ fd_buffer_flush (void *closure)
 static struct stat devnull;
 static int devnull_set = -1;
 
-/* The buffer block function for a buffer built on a file descriptor.  */
-static int
-fd_buffer_block (void *closure, bool block)
+static void
+block_fd (int fd, bool block)
 {
-    struct fd_buffer *fb = closure;
 # if defined (F_GETFL) && defined (O_NONBLOCK) && defined (F_SETFL)
     int flags;
 
-    flags = fcntl (fb->fd, F_GETFL, 0);
+    flags = fcntl (fd, F_GETFL, 0);
     if (flags < 0)
        return errno;
 
@@ -1987,7 +2035,7 @@ fd_buffer_block (void *closure, bool blo
     else
        flags |= O_NONBLOCK;
 
-    if (fcntl (fb->fd, F_SETFL, flags) < 0)
+    if (fcntl (fd, F_SETFL, flags) < 0)
     {
        /*
         * BSD returns ENODEV when we try to set block/nonblock on /dev/null.
@@ -2002,7 +2050,7 @@ fd_buffer_block (void *closure, bool blo
 
        if (devnull_set >= 0)
            /* Equivalent to /dev/null ? */
-           isdevnull = (fstat (fb->fd, &sb) >= 0
+           isdevnull = (fstat (fd, &sb) >= 0
                         && sb.st_dev == devnull.st_dev
                         && sb.st_ino == devnull.st_ino
                         && sb.st_mode == devnull.st_mode
@@ -2020,6 +2068,16 @@ fd_buffer_block (void *closure, bool blo
        }
     }
 # endif /* F_GETFL && O_NONBLOCK && F_SETFL */
+}
+
+/* The buffer block function for a buffer built on a file descriptor.  */
+static int
+fd_buffer_block (void *closure, bool block)
+{
+    struct fd_buffer *fb = closure;
+    block_fd (fb->fd, block);
+    if (0 <= fb->errorfd)
+      block_fd (fb->errorfd, block);
 
     fb->blocking = block;
 
diff -pubr cvs-1.12.12/src/buffer.h cvs-1.12.12-nonblock-1/src/buffer.h
--- cvs-1.12.12/src/buffer.h    2005-03-15 09:45:09.000000000 -0800
+++ cvs-1.12.12-nonblock-1/src/buffer.h 2005-07-15 22:12:51.000000000 -0700
@@ -162,8 +162,8 @@ int buf_count_mem (struct buffer *);
 #endif /* SERVER_FLOWCONTROL */
 
 struct buffer *
-fd_buffer_initialize (int fd, pid_t child_pid, cvsroot_t *root, bool input,
-                      void (*memory) (struct buffer *));
+fd_buffer_initialize (int fd, int errorfd, pid_t child_pid, cvsroot_t *root,
+                     bool input, void (*memory) (struct buffer *));
 
 /* EWOULDBLOCK is not defined by POSIX, but some BSD systems will
    return it, rather than EAGAIN, for nonblocking writes.  */
diff -pubr cvs-1.12.12/src/client.c cvs-1.12.12-nonblock-1/src/client.c
--- cvs-1.12.12/src/client.c    2005-04-14 07:13:25.000000000 -0700
+++ cvs-1.12.12-nonblock-1/src/client.c 2005-07-15 22:12:20.000000000 -0700
@@ -2718,9 +2718,6 @@ handle_wrapper_rcs_option (char *args, s
 static void
 handle_m (char *args, size_t len)
 {
-    fd_set wfds;
-    int s;
-
     /* In the case where stdout and stderr point to the same place,
        fflushing stderr will make output happen in the correct order.
        Often stderr will be line-buffered and this won't be needed,
@@ -2728,12 +2725,6 @@ handle_m (char *args, size_t len)
        based on being confused between default buffering between
        stdout and stderr.  But I'm not sure).  */
     fflush (stderr);
-    FD_ZERO (&wfds);
-    FD_SET (STDOUT_FILENO, &wfds);
-    errno = 0;
-    s = select (STDOUT_FILENO+1, NULL, &wfds, NULL, NULL);
-    if (s < 1 && errno != 0)
-        perror ("cannot write to stdout");
     fwrite (args, len, sizeof (*args), stdout);
     putc ('\n', stdout);
 }
@@ -2779,24 +2770,9 @@ handle_mbinary (char *args, size_t len)
 static void
 handle_e (char *args, size_t len)
 {
-    fd_set wfds;
-    int s;
-
     /* In the case where stdout and stderr point to the same place,
        fflushing stdout will make output happen in the correct order.  */
     fflush (stdout);
-    FD_ZERO (&wfds);
-    FD_SET (STDERR_FILENO, &wfds);
-    errno = 0;
-    s = select (STDERR_FILENO+1, NULL, &wfds, NULL, NULL);
-    /*
-     * If stderr has problems, then adding a call to
-     *   perror ("cannot write to stderr")
-     * will not work. So, try to write a message on stdout and
-     * terminate cvs.
-     */
-    if (s < 1 && errno != 0)
-        fperrmsg (stdout, 1, errno, "cannot write to stderr");
     fwrite (args, len, sizeof (*args), stderr);
     putc ('\n', stderr);
 }
@@ -3369,14 +3345,15 @@ get_proxy_port_number (const cvsroot_t *
 
 
 void
-make_bufs_from_fds(int tofd, int fromfd, int child_pid, cvsroot_t *root,
+make_bufs_from_fds(int tofd, int fromfd, int errorfd,
+                  int child_pid, cvsroot_t *root,
                    struct buffer **to_server_p,
                    struct buffer **from_server_p, int is_sock)
 {
 # ifdef NO_SOCKET_TO_FD
     if (is_sock)
     {
-       assert (tofd == fromfd);
+       assert (tofd == fromfd && errorfd < 0);
        *to_server_p = socket_buffer_initialize (tofd, 0, NULL);
        *from_server_p = socket_buffer_initialize (tofd, 1, NULL);
     }
@@ -3386,6 +3363,8 @@ make_bufs_from_fds(int tofd, int fromfd,
        /* todo: some OS's don't need these calls... */
        close_on_exec (tofd);
        close_on_exec (fromfd);
+       if (0 <= errorfd)
+           close_on_exec (errorfd);
 
        /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes
           fdopening the same file descriptor twice, so dup it if it is the
@@ -3403,9 +3382,9 @@ make_bufs_from_fds(int tofd, int fromfd,
         * child_pid in there.  In theory, it should be stored in both
         * buffers with a ref count...
         */
-       *to_server_p = fd_buffer_initialize (tofd, 0, root, false, NULL);
-       *from_server_p = fd_buffer_initialize (fromfd, child_pid, root,
-                                               true, NULL);
+       *to_server_p = fd_buffer_initialize (tofd, -1, 0, root, false, NULL);
+       *from_server_p = fd_buffer_initialize (fromfd, errorfd, child_pid,
+                                              root, true, NULL);
     }
 }
 #endif /* defined (AUTH_CLIENT_SUPPORT) || defined (SERVER_SUPPORT) || defined 
(HAVE_KERBEROS) || defined(HAVE_GSSAPI) */
@@ -3472,7 +3451,7 @@ connect_to_pserver (cvsroot_t *root, str
               root->proxy_hostname ? proxy_port_number : port_number,
                SOCK_STRERROR (SOCK_ERRNO));
 
-    make_bufs_from_fds (sock, sock, 0, root, &to_server, &from_server, 1);
+    make_bufs_from_fds (sock, sock, -1, 0, root, &to_server, &from_server, 1);
 
     /* if we have proxy then connect to the proxy first */
     if (root->proxy_hostname)
@@ -3758,11 +3737,11 @@ connect_to_forked_server (cvsroot_t *roo
     TRACE (TRACE_FUNCTION, "Forking server: %s %s",
           command[0] ? command[0] : "(null)", command[1]);
 
-    child_pid = piped_child (command, &tofd, &fromfd);
+    child_pid = piped_child (command, &tofd, &fromfd, NULL);
     if (child_pid < 0)
        error (1, 0, "could not fork server process");
 
-    make_bufs_from_fds (tofd, fromfd, child_pid, root, to_server_p,
+    make_bufs_from_fds (tofd, fromfd, -1, child_pid, root, to_server_p,
                         from_server_p, 0);
 }
 #endif /* CLIENT_SUPPORT || SERVER_SUPPORT */
@@ -3850,10 +3829,10 @@ open_connection_to_server (cvsroot_t *ro
                           root->hostname,
                          root->directory);
 # ifdef START_SERVER_RETURNS_SOCKET
-           make_bufs_from_fds (tofd, fromfd, 0, root, to_server_p,
+           make_bufs_from_fds (tofd, fromfd, -1, 0, root, to_server_p,
                                 from_server_p, 1);
 # else /* ! START_SERVER_RETURNS_SOCKET */
-           make_bufs_from_fds (tofd, fromfd, 0, root, to_server_p,
+           make_bufs_from_fds (tofd, fromfd, -1, 0, root, to_server_p,
                                 from_server_p, 0);
 # endif /* START_SERVER_RETURNS_SOCKET */
            }
diff -pubr cvs-1.12.12/src/client.h cvs-1.12.12-nonblock-1/src/client.h
--- cvs-1.12.12/src/client.h    2004-10-14 09:44:45.000000000 -0700
+++ cvs-1.12.12-nonblock-1/src/client.h 2005-07-15 23:45:41.000000000 -0700
@@ -9,7 +9,7 @@ extern int file_gzip_level;
 
 struct buffer;
 
-void make_bufs_from_fds (int, int, int, cvsroot_t *,
+void make_bufs_from_fds (int, int, int, int, cvsroot_t *,
                         struct buffer **, struct buffer **, int);
 
 
diff -pubr cvs-1.12.12/src/cvs.h cvs-1.12.12-nonblock-1/src/cvs.h
--- cvs-1.12.12/src/cvs.h       2005-04-14 07:14:55.000000000 -0700
+++ cvs-1.12.12-nonblock-1/src/cvs.h    2005-07-15 22:07:02.000000000 -0700
@@ -666,7 +666,7 @@ int run_piped (int *, int *);
 
 /* other similar-minded stuff from run.c.  */
 FILE *run_popen (const char *, const char *);
-int piped_child (char *const *, int *, int *);
+int piped_child (char *const *, int *, int *, int *);
 void close_on_exec (int);
 
 pid_t waitpid (pid_t, int *, int);
diff -pubr cvs-1.12.12/src/kerberos4-client.c 
cvs-1.12.12-nonblock-1/src/kerberos4-client.c
--- cvs-1.12.12/src/kerberos4-client.c  2005-04-14 07:13:26.000000000 -0700
+++ cvs-1.12.12-nonblock-1/src/kerberos4-client.c       2005-07-15 
23:45:45.000000000 -0700
@@ -95,7 +95,7 @@ start_kerberos4_server (cvsroot_t *root,
     free (hname);
 
     /* Give caller the values it wants. */
-    make_bufs_from_fds (s, s, 0, to_server_p, from_server_p, 1);
+    make_bufs_from_fds (s, s, -1, 0, to_server_p, from_server_p, 1);
 }
 
 void
@@ -107,4 +107,3 @@ initialize_kerberos4_encryption_buffers(
   *from_server_p = krb_encrypt_buffer_initialize (*from_server_p, 1,
                                                  sched, kblock, NULL);
 }
-
diff -pubr cvs-1.12.12/src/rsh-client.c cvs-1.12.12-nonblock-1/src/rsh-client.c
--- cvs-1.12.12/src/rsh-client.c        2005-03-15 09:45:10.000000000 -0800
+++ cvs-1.12.12-nonblock-1/src/rsh-client.c     2005-07-15 23:45:44.000000000 
-0700
@@ -118,7 +118,7 @@ start_rsh_server (cvsroot_t *root, struc
        error (1, errno, "cannot start server via rsh");
 
     /* Give caller the file descriptors in a form it can deal with. */
-    make_bufs_from_fds (pipes[0], pipes[1], child_pid, to_server_p,
+    make_bufs_from_fds (pipes[0], pipes[1], -1, child_pid, to_server_p,
                         from_server_p, 0);
 }
 
@@ -136,7 +136,7 @@ start_rsh_server (cvsroot_t *root, struc
     char *cvs_server = (root->cvs_server != NULL
                        ? root->cvs_server : getenv ("CVS_SERVER"));
     char *command;
-    int tofd, fromfd;
+    int tofd, fromfd, errorfd;
     int child_pid;
 
     if (!cvs_rsh)
@@ -184,14 +184,14 @@ start_rsh_server (cvsroot_t *root, struc
                fprintf (stderr, "%s ", argv[i]);
            putc ('\n', stderr);
        }
-       child_pid = piped_child (argv, &tofd, &fromfd);
+       child_pid = piped_child (argv, &tofd, &fromfd, &errorfd);
 
        if (child_pid < 0)
            error (1, errno, "cannot start server via rsh");
     }
     free (command);
 
-    make_bufs_from_fds (tofd, fromfd, child_pid, root, to_server_p,
+    make_bufs_from_fds (tofd, fromfd, errorfd, child_pid, root, to_server_p,
                         from_server_p, 0);
 }
 
diff -pubr cvs-1.12.12/src/run.c cvs-1.12.12-nonblock-1/src/run.c
--- cvs-1.12.12/src/run.c       2005-04-14 07:13:26.000000000 -0700
+++ cvs-1.12.12-nonblock-1/src/run.c    2005-07-16 11:29:34.000000000 -0700
@@ -1,4 +1,4 @@
-/* run.c --- routines for executing subprocesses.
+!/* run.c --- routines for executing subprocesses.
    
    This file is part of GNU CVS.
 
@@ -430,18 +430,112 @@ run_popen (const char *cmd, const char *
 }
 
 
+/* Work around an OpenSSH problem: it can put its standard file
+   descriptors into nonblocking mode, which will mess us up if we
+   share file descriptions with it.  The simplest workaround is
+   to create an intervening process between OpenSSH and the
+   actual stderr.  */
+
+static void
+work_around_openssh_glitch (void)
+{
+    pid_t pid;
+    int stderr_pipe[2];
+    struct stat sb;
+
+    /* Do nothing unless stderr is a file that is affected by
+       nonblocking mode.  */
+    if (! (fstat (STDERR_FILENO, &sb) == 0
+          && (S_ISFIFO (sb.st_mode) || S_ISSOCK (sb.st_mode)
+              || S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode))))
+       return;
+
+    if (pipe (stderr_pipe) < 0)
+       error (1, errno, "cannot create pipe");
+    pid = fork ();
+    if (pid < 0)
+       error (1, errno, "cannot fork");
+    if (pid != 0)
+    {
+       /* Still in child of original process.  Act like "cat -u".  */
+       char buf[1 << 13];
+       ssize_t inbytes;
+       pid_t w;
+       int status;
+
+       if (close (stderr_pipe[1]) < 0)
+           error (1, errno, "cannot close pipe");
+
+       while ((inbytes = read (stderr_pipe[0], buf, sizeof buf)) != 0)
+       {
+           size_t outbytes = 0;
+
+           if (inbytes < 0)
+           {
+               if (errno == EINTR)
+                   continue;
+               error (1, errno, "reading from pipe");
+           }
+
+           do
+           {
+               ssize_t w = write (STDERR_FILENO,
+                                  buf + outbytes, inbytes - outbytes);
+               if (w < 0)
+               {
+                   if (errno = EINTR)
+                     w = 0;
+                   if (w < 0)
+                     _exit (1);
+               }
+               outbytes += w;
+           }
+           while (inbytes != outbytes);
+       }
+
+       /* Done processing output from grandchild.  Propagate
+          its exit status back to the parent.  */
+       while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
+           continue;
+       if (w < 0)
+           error (1, errno, "waiting for child");
+       if (! WIFEXITED (status))
+       {
+           if (WIFSIGNALED (status))
+               raise (WTERMSIG (status));
+           error (1, errno, "child did not exit cleanly");
+       }
+       _exit (WEXITSTATUS (status));
+    }
+
+    /* Grandchild of original process.  */
+    if (close (stderr_pipe[0]) < 0)
+       error (1, errno, "cannot close pipe");
+
+    if (stderr_pipe[1] != STDERR_FILENO)
+    {
+       if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
+           error (1, errno, "cannot dup2 pipe");
+       if (close (stderr_pipe[1]) < 0)
+           error (1, errno, "cannot close pipe");
+    }
+}
+
 
 int
-piped_child (char *const *command, int *tofdp, int *fromfdp)
+piped_child (char *const *command, int *tofdp, int *fromfdp, int *errorfdp)
 {
     int pid;
     int to_child_pipe[2];
     int from_child_pipe[2];
+    int error_child_pipe[2];
 
     if (pipe (to_child_pipe) < 0)
        error (1, errno, "cannot create pipe");
     if (pipe (from_child_pipe) < 0)
        error (1, errno, "cannot create pipe");
+    if (errorfdp && pipe (error_child_pipe) < 0)
+       error (1, errno, "cannot create pipe");
 
 #ifdef USE_SETMODE_BINARY
     setmode (to_child_pipe[0], O_BINARY);
@@ -467,6 +561,13 @@ piped_child (char *const *command, int *
            error (1, errno, "cannot close pipe");
        if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
            error (1, errno, "cannot dup2 pipe");
+       if (errorfdp)
+       {
+           if (close (error_child_pipe[0]) < 0)
+               error (1, errno, "cannot close pipe");
+           if (dup2 (error_child_pipe[1], STDERR_FILENO) < 0)
+               error (1, errno, "cannot dup2 pipe");
+       }
 
        /* Okay to cast out const below - execvp don't return anyhow.  */
        execvp ((char *)command[0], (char **)command);
@@ -476,9 +577,16 @@ piped_child (char *const *command, int *
        error (1, errno, "cannot close pipe");
     if (close (from_child_pipe[1]) < 0)
        error (1, errno, "cannot close pipe");
+    if (errorfdp && close (error_child_pipe[1] < 0))
+       error (1, errno, "cannot close pipe");
 
     *tofdp = to_child_pipe[1];
     *fromfdp = from_child_pipe[0];
+    if (errorfdp)
+    {
+       *errorfdp = error_child_pipe[0];
+       set_nonblock_fd (*errorfdp);
+    }
     return pid;
 }
 
@@ -488,7 +596,7 @@ int
 run_piped (int *tofdp, int *fromfdp)
 {
     run_add_arg (NULL);
-    return piped_child (run_argv, tofdp, fromfdp);
+    return piped_child (run_argv, tofdp, fromfdp, NULL);
 }
 
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]