cvs-cvs
[Top][All Lists]
Advanced

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

[Cvs-cvs] Changes to ccvs/src/run.c [cvs1-11-x-branch]


From: Derek Robert Price
Subject: [Cvs-cvs] Changes to ccvs/src/run.c [cvs1-11-x-branch]
Date: Thu, 29 Sep 2005 14:32:14 -0400

Index: ccvs/src/run.c
diff -u ccvs/src/run.c:1.33.6.6 ccvs/src/run.c:1.33.6.7
--- ccvs/src/run.c:1.33.6.6     Mon Jun  6 21:32:50 2005
+++ ccvs/src/run.c      Thu Sep 29 18:32:08 2005
@@ -417,11 +417,107 @@
     return (popen (cmd, mode));
 }
 
+
+
+/* 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 (command, tofdp, fromfdp)
+piped_child (command, tofdp, fromfdp, fix_stderr)
      const char **command;
      int *tofdp;
      int *fromfdp;
+     int fix_stderr;
 {
     int pid;
     int to_child_pipe[2];
@@ -439,11 +535,7 @@
     setmode (from_child_pipe[1], O_BINARY);
 #endif
 
-#ifdef HAVE_VFORK
-    pid = vfork ();
-#else
     pid = fork ();
-#endif
     if (pid < 0)
        error (1, errno, "cannot fork");
     if (pid == 0)
@@ -457,7 +549,10 @@
        if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
            error (1, errno, "cannot dup2 pipe");
 
-       /* Okay to cast out const below - execvp don't return anyhow.  */
+        if (fix_stderr)
+           work_around_openssh_glitch ();
+
+       /* Okay to cast out const below - execvp don't return nohow.  */
        execvp ((char *)command[0], (char **)command);
        error (1, errno, "cannot exec %s", command[0]);
     }




reply via email to

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