summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/run.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/run.c')
-rw-r--r--contrib/cvs/src/run.c578
1 files changed, 0 insertions, 578 deletions
diff --git a/contrib/cvs/src/run.c b/contrib/cvs/src/run.c
deleted file mode 100644
index 98ae911..0000000
--- a/contrib/cvs/src/run.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/* run.c --- routines for executing subprocesses.
-
- This file is part of GNU CVS.
-
- GNU CVS 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 2, 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. */
-
-#include "cvs.h"
-
-#ifndef HAVE_UNISTD_H
-extern int execvp PROTO((char *file, char **argv));
-#endif
-
-static void run_add_arg PROTO((const char *s));
-
-extern char *strtok ();
-
-/*
- * To exec a program under CVS, first call run_setup() to setup initial
- * arguments. The argument to run_setup will be parsed into whitespace
- * separated words and added to the global run_argv list.
- *
- * Then, optionally call run_arg() for each additional argument that you'd like
- * to pass to the executed program.
- *
- * Finally, call run_exec() to execute the program with the specified arguments.
- * The execvp() syscall will be used, so that the PATH is searched correctly.
- * File redirections can be performed in the call to run_exec().
- */
-static char **run_argv;
-static int run_argc;
-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
-run_setup (prog)
- const char *prog;
-{
- char *cp;
- char *run_prog;
-
- /* clean out any malloc'ed values from run_argv */
- run_arg_free_p (run_argc, run_argv);
- run_argc = 0;
-
- run_prog = xstrdup (prog);
-
- /* put each word into run_argv, allocating it as we go */
- for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
- run_add_arg (cp);
- free (run_prog);
-}
-
-void
-run_arg (s)
- const char *s;
-{
- 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 (*iargc >= *iarg_allocated)
- {
- *iarg_allocated += 50;
- *iargv = xrealloc (*iargv, *iarg_allocated * sizeof (char **));
- }
-
- if (s)
- (*iargv)[(*iargc)++] = xstrdup (s);
- else
- (*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);
-}
-
-
-
-int
-run_exec (stin, stout, sterr, flags)
- const char *stin;
- const char *stout;
- const char *sterr;
- int flags;
-{
- int shin, shout, sherr;
- int mode_out, mode_err;
- int status;
- int rc = -1;
- int rerrno = 0;
- int pid, w;
-
-#ifdef POSIX_SIGNALS
- sigset_t sigset_mask, sigset_omask;
- struct sigaction act, iact, qact;
-
-#else
-#ifdef BSD_SIGNALS
- int mask;
- struct sigvec vec, ivec, qvec;
-
-#else
- RETSIGTYPE (*istat) (), (*qstat) ();
-#endif
-#endif
-
- if (trace)
- {
-#ifdef SERVER_SUPPORT
- cvs_outerr (server_active ? "S" : " ", 1);
-#endif
- cvs_outerr ("-> system(", 0);
- run_print (stderr);
- cvs_outerr (")\n", 0);
- }
- if (noexec && (flags & RUN_REALLY) == 0)
- return 0;
-
- /* make sure that we are null terminated, since we didn't calloc */
- run_add_arg ((char *)0);
-
- /* setup default file descriptor numbers */
- shin = 0;
- shout = 1;
- sherr = 2;
-
- /* set the file modes for stdout and stderr */
- mode_out = mode_err = O_WRONLY | O_CREAT;
- mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
- mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
-
- if (stin && (shin = open (stin, O_RDONLY)) == -1)
- {
- rerrno = errno;
- error (0, errno, "cannot open %s for reading (prog %s)",
- stin, run_argv[0]);
- goto out0;
- }
- if (stout && (shout = open (stout, mode_out, 0666)) == -1)
- {
- rerrno = errno;
- error (0, errno, "cannot open %s for writing (prog %s)",
- stout, run_argv[0]);
- goto out1;
- }
- if (sterr && (flags & RUN_COMBINED) == 0)
- {
- if ((sherr = open (sterr, mode_err, 0666)) == -1)
- {
- rerrno = errno;
- error (0, errno, "cannot open %s for writing (prog %s)",
- sterr, run_argv[0]);
- goto out2;
- }
- }
-
- /* Make sure we don't flush this twice, once in the subprocess. */
- cvs_flushout();
- cvs_flusherr();
-
- /* The output files, if any, are now created. Do the fork and dups.
-
- We use vfork not so much for a performance boost (the
- performance boost, if any, is modest on most modern unices),
- but for the sake of systems without a memory management unit,
- which find it difficult or impossible to implement fork at all
- (e.g. Amiga). The other solution is spawn (see
- windows-NT/run.c). */
-
-#ifdef HAVE_VFORK
- pid = vfork ();
-#else
- pid = fork ();
-#endif
- if (pid == 0)
- {
- if (shin != 0)
- {
- (void) dup2 (shin, 0);
- (void) close (shin);
- }
- if (shout != 1)
- {
- (void) dup2 (shout, 1);
- (void) close (shout);
- }
- if (flags & RUN_COMBINED)
- (void) dup2 (1, 2);
- else if (sherr != 2)
- {
- (void) dup2 (sherr, 2);
- (void) close (sherr);
- }
-
-#ifdef SETXID_SUPPORT
- /*
- ** This prevents a user from creating a privileged shell
- ** from the text editor when the SETXID_SUPPORT option is selected.
- */
- if (!strcmp (run_argv[0], Editor) && setegid (getgid ()))
- {
- error (0, errno, "cannot set egid to gid");
- _exit (127);
- }
-#endif
-
- /* dup'ing is done. try to run it now */
- (void) execvp (run_argv[0], run_argv);
- error (0, errno, "cannot exec %s", run_argv[0]);
- _exit (127);
- }
- else if (pid == -1)
- {
- rerrno = errno;
- goto out;
- }
-
- /* the parent. Ignore some signals for now */
-#ifdef POSIX_SIGNALS
- if (flags & RUN_SIGIGNORE)
- {
- act.sa_handler = SIG_IGN;
- (void) sigemptyset (&act.sa_mask);
- act.sa_flags = 0;
- (void) sigaction (SIGINT, &act, &iact);
- (void) sigaction (SIGQUIT, &act, &qact);
- }
- else
- {
- (void) sigemptyset (&sigset_mask);
- (void) sigaddset (&sigset_mask, SIGINT);
- (void) sigaddset (&sigset_mask, SIGQUIT);
- (void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
- }
-#else
-#ifdef BSD_SIGNALS
- if (flags & RUN_SIGIGNORE)
- {
- memset ((char *)&vec, 0, sizeof (vec));
- vec.sv_handler = SIG_IGN;
- (void) sigvec (SIGINT, &vec, &ivec);
- (void) sigvec (SIGQUIT, &vec, &qvec);
- }
- else
- mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
-#else
- istat = signal (SIGINT, SIG_IGN);
- qstat = signal (SIGQUIT, SIG_IGN);
-#endif
-#endif
-
- /* wait for our process to die and munge return status */
-#ifdef POSIX_SIGNALS
- while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
- ;
-#else
- while ((w = wait (&status)) != pid)
- {
- if (w == -1 && errno != EINTR)
- break;
- }
-#endif
-
- if (w == -1)
- {
- rc = -1;
- rerrno = errno;
- }
-#ifndef VMS /* status is return status */
- else if (WIFEXITED (status))
- rc = WEXITSTATUS (status);
- else if (WIFSIGNALED (status))
- {
- if (WTERMSIG (status) == SIGPIPE)
- error (1, 0, "broken pipe");
- rc = 2;
- }
- else
- rc = 1;
-#else /* VMS */
- rc = WEXITSTATUS (status);
-#endif /* VMS */
-
- /* restore the signals */
-#ifdef POSIX_SIGNALS
- if (flags & RUN_SIGIGNORE)
- {
- (void) sigaction (SIGINT, &iact, (struct sigaction *)NULL);
- (void) sigaction (SIGQUIT, &qact, (struct sigaction *)NULL);
- }
- else
- (void) sigprocmask (SIG_SETMASK, &sigset_omask, (sigset_t *)NULL);
-#else
-#ifdef BSD_SIGNALS
- if (flags & RUN_SIGIGNORE)
- {
- (void) sigvec (SIGINT, &ivec, (struct sigvec *)NULL);
- (void) sigvec (SIGQUIT, &qvec, (struct sigvec *)NULL);
- }
- else
- (void) sigsetmask (mask);
-#else
- (void) signal (SIGINT, istat);
- (void) signal (SIGQUIT, qstat);
-#endif
-#endif
-
- /* cleanup the open file descriptors */
- out:
- if (sterr)
- (void) close (sherr);
- else
- /* ensure things are received by the parent in the correct order
- * relative to the protocol pipe
- */
- cvs_flusherr();
- out2:
- if (stout)
- (void) close (shout);
- else
- /* ensure things are received by the parent in the correct order
- * relative to the protocol pipe
- */
- cvs_flushout();
- out1:
- if (stin)
- (void) close (shin);
-
- out0:
- if (rerrno)
- errno = rerrno;
- return rc;
-}
-
-
-
-void
-run_print (fp)
- FILE *fp;
-{
- int i;
- void (*outfn) PROTO ((const char *, size_t));
-
- if (fp == stderr)
- outfn = cvs_outerr;
- else if (fp == stdout)
- outfn = cvs_output;
- else
- {
- error (1, 0, "internal error: bad argument to run_print");
- /* Solely to placate gcc -Wall.
- FIXME: it'd be better to use a function named `fatal' that
- is known never to return. Then kludges wouldn't be necessary. */
- outfn = NULL;
- }
-
- for (i = 0; i < run_argc; i++)
- {
- (*outfn) ("'", 1);
- (*outfn) (run_argv[i], 0);
- (*outfn) ("'", 1);
- if (i != run_argc - 1)
- (*outfn) (" ", 1);
- }
-}
-
-/* Return value is NULL for error, or if noexec was set. If there was an
- error, return NULL and I'm not sure whether errno was set (the Red Hat
- Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec
- case complicates this even aside from popen behavior). */
-
-FILE *
-run_popen (cmd, mode)
- const char *cmd;
- const char *mode;
-{
- if (trace)
- (void) fprintf (stderr, "%s-> run_popen(%s,%s)\n",
- CLIENT_SERVER_STR, cmd, mode);
- if (noexec)
- return (NULL);
-
- 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, fix_stderr)
- const char **command;
- int *tofdp;
- int *fromfdp;
- int fix_stderr;
-{
- int pid;
- int to_child_pipe[2];
- int from_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");
-
-#ifdef USE_SETMODE_BINARY
- setmode (to_child_pipe[0], O_BINARY);
- setmode (to_child_pipe[1], O_BINARY);
- setmode (from_child_pipe[0], O_BINARY);
- setmode (from_child_pipe[1], O_BINARY);
-#endif
-
- pid = fork ();
- if (pid < 0)
- error (1, errno, "cannot fork");
- if (pid == 0)
- {
- if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
- error (1, errno, "cannot dup2 pipe");
- if (close (to_child_pipe[1]) < 0)
- error (1, errno, "cannot close pipe");
- if (close (from_child_pipe[0]) < 0)
- error (1, errno, "cannot close pipe");
- if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
- error (1, errno, "cannot dup2 pipe");
-
- 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]);
- }
- if (close (to_child_pipe[0]) < 0)
- error (1, errno, "cannot close pipe");
- if (close (from_child_pipe[1]) < 0)
- error (1, errno, "cannot close pipe");
-
- *tofdp = to_child_pipe[1];
- *fromfdp = from_child_pipe[0];
- return pid;
-}
-
-
-void
-close_on_exec (fd)
- int fd;
-{
-#ifdef F_SETFD
- if (fcntl (fd, F_SETFD, 1) == -1)
- error (1, errno, "can't set close-on-exec flag on %d", fd);
-#endif
-}
OpenPOWER on IntegriCloud