summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/run.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2008-01-13 05:49:32 +0000
committerobrien <obrien@FreeBSD.org>2008-01-13 05:49:32 +0000
commitdef79099e7c2ca2b773aa94d5b80c571dec9460f (patch)
tree9a6cba0f4384569a2eee18bf74577d8fd41aa2c7 /contrib/cvs/src/run.c
parent0526761d4d99d34d2de093998c7ccd3f82695651 (diff)
parent55b663837dd12bbe5836969ac2a3f052a9028ea5 (diff)
downloadFreeBSD-src-def79099e7c2ca2b773aa94d5b80c571dec9460f.zip
FreeBSD-src-def79099e7c2ca2b773aa94d5b80c571dec9460f.tar.gz
This commit was generated by cvs2svn to compensate for changes in r175261,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/cvs/src/run.c')
-rw-r--r--contrib/cvs/src/run.c160
1 files changed, 136 insertions, 24 deletions
diff --git a/contrib/cvs/src/run.c b/contrib/cvs/src/run.c
index b03d683..98ae911 100644
--- a/contrib/cvs/src/run.c
+++ b/contrib/cvs/src/run.c
@@ -36,7 +36,19 @@ extern char *strtok ();
*/
static char **run_argv;
static int run_argc;
-static int run_argc_allocated;
+static size_t run_argc_allocated;
+
+
+
+void
+run_arg_free_p (int argc, char **argv)
+{
+ int i;
+ for (i = 0; i < argc; i++)
+ free (argv[i]);
+}
+
+
/* VARARGS */
void
@@ -44,18 +56,10 @@ run_setup (prog)
const char *prog;
{
char *cp;
- int i;
char *run_prog;
/* clean out any malloc'ed values from run_argv */
- for (i = 0; i < run_argc; i++)
- {
- if (run_argv[i])
- {
- free (run_argv[i]);
- run_argv[i] = (char *) 0;
- }
- }
+ run_arg_free_p (run_argc, run_argv);
run_argc = 0;
run_prog = xstrdup (prog);
@@ -73,22 +77,35 @@ run_arg (s)
run_add_arg (s);
}
-static void
-run_add_arg (s)
+
+
+void
+run_add_arg_p (iargc, iarg_allocated, iargv, s)
+ int *iargc;
+ size_t *iarg_allocated;
+ char ***iargv;
const char *s;
{
/* allocate more argv entries if we've run out */
- if (run_argc >= run_argc_allocated)
+ if (*iargc >= *iarg_allocated)
{
- run_argc_allocated += 50;
- run_argv = (char **) xrealloc ((char *) run_argv,
- run_argc_allocated * sizeof (char **));
+ *iarg_allocated += 50;
+ *iargv = xrealloc (*iargv, *iarg_allocated * sizeof (char **));
}
if (s)
- run_argv[run_argc++] = xstrdup (s);
+ (*iargv)[(*iargc)++] = xstrdup (s);
else
- run_argv[run_argc] = (char *) 0; /* not post-incremented on purpose! */
+ (*iargv)[*iargc] = NULL; /* not post-incremented on purpose! */
+}
+
+
+
+static void
+run_add_arg (s)
+ const char *s;
+{
+ run_add_arg_p (&run_argc, &run_argc_allocated, &run_argv, s);
}
@@ -400,11 +417,107 @@ run_popen (cmd, mode)
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];
@@ -422,11 +535,7 @@ piped_child (command, tofdp, fromfdp)
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)
@@ -440,7 +549,10 @@ piped_child (command, tofdp, fromfdp)
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]);
}
OpenPOWER on IntegriCloud