diff options
author | obrien <obrien@FreeBSD.org> | 2008-01-13 05:49:32 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2008-01-13 05:49:32 +0000 |
commit | def79099e7c2ca2b773aa94d5b80c571dec9460f (patch) | |
tree | 9a6cba0f4384569a2eee18bf74577d8fd41aa2c7 /contrib/cvs/src/run.c | |
parent | 0526761d4d99d34d2de093998c7ccd3f82695651 (diff) | |
parent | 55b663837dd12bbe5836969ac2a3f052a9028ea5 (diff) | |
download | FreeBSD-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.c | 160 |
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]); } |