Home | History | Annotate | Line # | Download | only in src
      1 /* run.c --- routines for executing subprocesses.
      2 
      3    This file is part of GNU CVS.
      4 
      5    GNU CVS is free software; you can redistribute it and/or modify it
      6    under the terms of the GNU General Public License as published by the
      7    Free Software Foundation; either version 2, or (at your option) any
      8    later version.
      9 
     10    This program is distributed in the hope that it will be useful,
     11    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU General Public License for more details.  */
     14 #include <sys/cdefs.h>
     15 __RCSID("$NetBSD: run.c,v 1.4 2018/08/21 15:37:33 christos Exp $");
     16 
     17 #include "cvs.h"
     18 
     19 #ifndef HAVE_UNISTD_H
     20 extern int execvp (char *file, char **argv);
     21 #endif
     22 
     23 
     24 
     25 /*
     26  * To exec a program under CVS, first call run_setup() to setup initial
     27  * arguments.  The argument to run_setup will be parsed into whitespace
     28  * separated words and added to the global run_argv list.
     29  *
     30  * Then, optionally call run_add_arg() for each additional argument that you'd
     31  * like to pass to the executed program.
     32  *
     33  * Finally, call run_exec() to execute the program with the specified arguments.
     34  * The execvp() syscall will be used, so that the PATH is searched correctly.
     35  * File redirections can be performed in the call to run_exec().
     36  */
     37 static char **run_argv;
     38 static int run_argc;
     39 static size_t run_arg_allocated;
     40 
     41 
     42 
     43 void
     44 run_arg_free_p (int argc, char **argv)
     45 {
     46     int i;
     47     for (i = 0; i < argc; i++)
     48 	free (argv[i]);
     49 }
     50 
     51 
     52 
     53 /* VARARGS */
     54 void
     55 run_setup (const char *prog)
     56 {
     57     char *run_prog;
     58     char *buf, *d, *s;
     59     size_t length;
     60     size_t doff;
     61     char inquotes;
     62     int dolastarg;
     63 
     64     /* clean out any malloc'ed values from run_argv */
     65     run_arg_free_p (run_argc, run_argv);
     66     run_argc = 0;
     67 
     68     run_prog = xstrdup (prog);
     69 
     70     s = run_prog;
     71     d = buf = NULL;
     72     length = 0;
     73     dolastarg = 1;
     74     inquotes = '\0';
     75     doff = d - buf;
     76     expand_string(&buf, &length, doff + 1);
     77     d = buf + doff;
     78     while ((*d = *s++) != '\0')
     79     {
     80 	switch (*d)
     81 	{
     82 	    case '\\':
     83 		if (*s) *d = *s++;
     84 		d++;
     85 		break;
     86 	    case '"':
     87 	    case '\'':
     88 		if (inquotes == *d) inquotes = '\0';
     89 		else inquotes = *d;
     90 		break;
     91 	    case ' ':
     92 	    case '\t':
     93 		if (inquotes) d++;
     94 		else
     95 		{
     96 		    *d = '\0';
     97 		    run_add_arg (buf);
     98 		    d = buf;
     99 		    while (isspace(*s)) s++;
    100 		    if (!*s) dolastarg = 0;
    101 		}
    102 		break;
    103 	    default:
    104 		d++;
    105 		break;
    106 	}
    107 	doff = d - buf;
    108 	expand_string(&buf, &length, doff + 1);
    109 	d = buf + doff;
    110     }
    111     if (dolastarg) run_add_arg (buf);
    112     /* put each word into run_argv, allocating it as we go */
    113     if (buf) free (buf);
    114     free (run_prog);
    115 }
    116 
    117 
    118 
    119 void
    120 run_add_arg_p (int *iargc, size_t *iarg_allocated, char ***iargv,
    121 	       const char *s)
    122 {
    123     /* allocate more argv entries if we've run out */
    124     if (*iargc >= *iarg_allocated)
    125     {
    126 	*iarg_allocated += 50;
    127 	*iargv = xnrealloc (*iargv, *iarg_allocated, sizeof (char **));
    128     }
    129 
    130     if (s)
    131 	(*iargv)[(*iargc)++] = xstrdup (s);
    132     else
    133 	(*iargv)[*iargc] = NULL;	/* not post-incremented on purpose! */
    134 }
    135 
    136 
    137 
    138 void
    139 run_add_arg (const char *s)
    140 {
    141     run_add_arg_p (&run_argc, &run_arg_allocated, &run_argv, s);
    142 }
    143 
    144 
    145 
    146 int
    147 run_exec (const char *stin, const char *stout, const char *sterr, int flags)
    148 {
    149     int shin, shout, sherr;
    150     int mode_out, mode_err;
    151     int status;
    152     int rc = -1;
    153     int rerrno = 0;
    154     int pid, w;
    155 
    156 #ifdef POSIX_SIGNALS
    157     sigset_t sigset_mask, sigset_omask;
    158     struct sigaction act, iact, qact;
    159 
    160 #else
    161 #ifdef BSD_SIGNALS
    162     int mask;
    163     struct sigvec vec, ivec, qvec;
    164 
    165 #else
    166     RETSIGTYPE (*istat) (), (*qstat) ();
    167 #endif
    168 #endif
    169 
    170     if (trace)
    171     {
    172 	cvs_outerr (
    173 #ifdef SERVER_SUPPORT
    174 		    server_active ? "S" :
    175 #endif
    176 		    " ", 1);
    177 	cvs_outerr (" -> system (", 0);
    178 	run_print (stderr);
    179 	cvs_outerr (")\n", 0);
    180     }
    181     if (noexec && (flags & RUN_REALLY) == 0)
    182 	return 0;
    183 
    184     /* make sure that we are null terminated, since we didn't calloc */
    185     run_add_arg (NULL);
    186 
    187     /* setup default file descriptor numbers */
    188     shin = 0;
    189     shout = 1;
    190     sherr = 2;
    191 
    192     /* set the file modes for stdout and stderr */
    193     mode_out = mode_err = O_WRONLY | O_CREAT;
    194     mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
    195     mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
    196 
    197     if (stin && (shin = open (stin, O_RDONLY)) == -1)
    198     {
    199 	rerrno = errno;
    200 	error (0, errno, "cannot open %s for reading (prog %s)",
    201 	       stin, run_argv[0]);
    202 	goto out0;
    203     }
    204     if (stout && (shout = open (stout, mode_out, 0666)) == -1)
    205     {
    206 	rerrno = errno;
    207 	error (0, errno, "cannot open %s for writing (prog %s)",
    208 	       stout, run_argv[0]);
    209 	goto out1;
    210     }
    211     if (sterr && (flags & RUN_COMBINED) == 0)
    212     {
    213 	if ((sherr = open (sterr, mode_err, 0666)) == -1)
    214 	{
    215 	    rerrno = errno;
    216 	    error (0, errno, "cannot open %s for writing (prog %s)",
    217 		   sterr, run_argv[0]);
    218 	    goto out2;
    219 	}
    220     }
    221 
    222     /* Make sure we don't flush this twice, once in the subprocess.  */
    223     cvs_flushout();
    224     cvs_flusherr();
    225 
    226     /* The output files, if any, are now created.  Do the fork and dups.
    227 
    228        We use vfork not so much for a performance boost (the
    229        performance boost, if any, is modest on most modern unices),
    230        but for the sake of systems without a memory management unit,
    231        which find it difficult or impossible to implement fork at all
    232        (e.g. Amiga).  The other solution is spawn (see
    233        windows-NT/run.c).  */
    234 
    235 #ifdef HAVE_VFORK
    236     pid = vfork ();
    237 #else
    238     pid = fork ();
    239 #endif
    240     if (pid == 0)
    241     {
    242 #ifdef SIGINFO
    243        signal (SIGINFO, SIG_DFL);
    244 #endif
    245 #ifdef SETXID_SUPPORT
    246 	if (flags & RUN_UNSETXID) {
    247 	    (void) setgid (getgid ());
    248 	    (void) setuid (getuid ());
    249 	}
    250 #endif
    251 
    252 	if (shin != 0)
    253 	{
    254 	    (void) dup2 (shin, 0);
    255 	    (void) close (shin);
    256 	}
    257 	if (shout != 1)
    258 	{
    259 	    (void) dup2 (shout, 1);
    260 	    (void) close (shout);
    261 	}
    262 	if (flags & RUN_COMBINED)
    263 	    (void) dup2 (1, 2);
    264 	else if (sherr != 2)
    265 	{
    266 	    (void) dup2 (sherr, 2);
    267 	    (void) close (sherr);
    268 	}
    269 
    270 #ifdef SETXID_SUPPORT
    271 	/*
    272 	** This prevents a user from creating a privileged shell
    273 	** from the text editor when the SETXID_SUPPORT option is selected.
    274 	*/
    275 	if (!strcmp (run_argv[0], Editor) && setegid (getgid ()))
    276 	{
    277 	    error (0, errno, "cannot set egid to gid");
    278 	    _exit (127);
    279 	}
    280 #endif
    281 
    282 	/* dup'ing is done.  try to run it now */
    283 	(void) execvp (run_argv[0], run_argv);
    284 	error (0, errno, "cannot exec %s", run_argv[0]);
    285 	_exit (127);
    286     }
    287     else if (pid == -1)
    288     {
    289 	rerrno = errno;
    290 	goto out;
    291     }
    292 
    293     /* the parent.  Ignore some signals for now */
    294 #ifdef POSIX_SIGNALS
    295     if (flags & RUN_SIGIGNORE)
    296     {
    297 	act.sa_handler = SIG_IGN;
    298 	(void) sigemptyset (&act.sa_mask);
    299 	act.sa_flags = 0;
    300 	(void) sigaction (SIGINT, &act, &iact);
    301 	(void) sigaction (SIGQUIT, &act, &qact);
    302     }
    303     else
    304     {
    305 	(void) sigemptyset (&sigset_mask);
    306 	(void) sigaddset (&sigset_mask, SIGINT);
    307 	(void) sigaddset (&sigset_mask, SIGQUIT);
    308 	(void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
    309     }
    310 #else
    311 #ifdef BSD_SIGNALS
    312     if (flags & RUN_SIGIGNORE)
    313     {
    314 	memset (&vec, 0, sizeof vec);
    315 	vec.sv_handler = SIG_IGN;
    316 	(void) sigvec (SIGINT, &vec, &ivec);
    317 	(void) sigvec (SIGQUIT, &vec, &qvec);
    318     }
    319     else
    320 	mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
    321 #else
    322     istat = signal (SIGINT, SIG_IGN);
    323     qstat = signal (SIGQUIT, SIG_IGN);
    324 #endif
    325 #endif
    326 
    327     /* wait for our process to die and munge return status */
    328 #ifdef POSIX_SIGNALS
    329     while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
    330 	;
    331 #else
    332     while ((w = wait (&status)) != pid)
    333     {
    334 	if (w == -1 && errno != EINTR)
    335 	    break;
    336     }
    337 #endif
    338 
    339     if (w == -1)
    340     {
    341 	rc = -1;
    342 	rerrno = errno;
    343     }
    344 #ifndef VMS /* status is return status */
    345     else if (WIFEXITED (status))
    346 	rc = WEXITSTATUS (status);
    347     else if (WIFSIGNALED (status))
    348     {
    349 	if (WTERMSIG (status) == SIGPIPE)
    350 	    error (1, 0, "broken pipe");
    351 	rc = 2;
    352     }
    353     else
    354 	rc = 1;
    355 #else /* VMS */
    356     rc = WEXITSTATUS (status);
    357 #endif /* VMS */
    358 
    359     /* restore the signals */
    360 #ifdef POSIX_SIGNALS
    361     if (flags & RUN_SIGIGNORE)
    362     {
    363 	(void) sigaction (SIGINT, &iact, NULL);
    364 	(void) sigaction (SIGQUIT, &qact, NULL);
    365     }
    366     else
    367 	(void) sigprocmask (SIG_SETMASK, &sigset_omask, NULL);
    368 #else
    369 #ifdef BSD_SIGNALS
    370     if (flags & RUN_SIGIGNORE)
    371     {
    372 	(void) sigvec (SIGINT, &ivec, NULL);
    373 	(void) sigvec (SIGQUIT, &qvec, NULL);
    374     }
    375     else
    376 	(void) sigsetmask (mask);
    377 #else
    378     (void) signal (SIGINT, istat);
    379     (void) signal (SIGQUIT, qstat);
    380 #endif
    381 #endif
    382 
    383     /* cleanup the open file descriptors */
    384   out:
    385     if (sterr)
    386 	(void) close (sherr);
    387     else
    388 	/* ensure things are received by the parent in the correct order
    389 	 * relative to the protocol pipe
    390 	 */
    391 	cvs_flusherr();
    392   out2:
    393     if (stout)
    394 	(void) close (shout);
    395     else
    396 	/* ensure things are received by the parent in the correct order
    397 	 * relative to the protocol pipe
    398 	 */
    399 	cvs_flushout();
    400   out1:
    401     if (stin)
    402 	(void) close (shin);
    403 
    404   out0:
    405     if (rerrno)
    406 	errno = rerrno;
    407     return rc;
    408 }
    409 
    410 
    411 
    412 void
    413 run_print (FILE *fp)
    414 {
    415     int i;
    416     void (*outfn) (const char *, size_t);
    417 
    418     if (fp == stderr)
    419 	outfn = cvs_outerr;
    420     else if (fp == stdout)
    421 	outfn = cvs_output;
    422     else
    423     {
    424 	error (1, 0, "internal error: bad argument to run_print");
    425 	/* Solely to placate gcc -Wall.
    426 	   FIXME: it'd be better to use a function named `fatal' that
    427 	   is known never to return.  Then kludges wouldn't be necessary.  */
    428 	outfn = NULL;
    429     }
    430 
    431     for (i = 0; i < run_argc; i++)
    432     {
    433 	(*outfn) ("'", 1);
    434 	(*outfn) (run_argv[i], 0);
    435 	(*outfn) ("'", 1);
    436 	if (i != run_argc - 1)
    437 	    (*outfn) (" ", 1);
    438     }
    439 }
    440 
    441 
    442 
    443 /* Return value is NULL for error, or if noexec was set.  If there was an
    444    error, return NULL and I'm not sure whether errno was set (the Red Hat
    445    Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec
    446    case complicates this even aside from popen behavior).  */
    447 FILE *
    448 run_popen (const char *cmd, const char *mode)
    449 {
    450     TRACE (TRACE_FUNCTION, "run_popen (%s,%s)", cmd, mode);
    451     if (noexec)
    452 	return NULL;
    453 
    454     return popen (cmd, mode);
    455 }
    456 
    457 
    458 
    459 /* Work around an OpenSSH problem: it can put its standard file
    460    descriptors into nonblocking mode, which will mess us up if we
    461    share file descriptions with it.  The simplest workaround is
    462    to create an intervening process between OpenSSH and the
    463    actual stderr.  */
    464 
    465 static void
    466 work_around_openssh_glitch (void)
    467 {
    468     pid_t pid;
    469     int stderr_pipe[2];
    470     struct stat sb;
    471 
    472     /* Do nothing unless stderr is a file that is affected by
    473        nonblocking mode.  */
    474     if (!(fstat (STDERR_FILENO, &sb) == 0
    475           && (S_ISFIFO (sb.st_mode) || S_ISSOCK (sb.st_mode)
    476               || S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode))))
    477        return;
    478 
    479     if (pipe (stderr_pipe) < 0)
    480        error (1, errno, "cannot create pipe");
    481     pid = fork ();
    482     if (pid < 0)
    483        error (1, errno, "cannot fork");
    484     if (pid != 0)
    485     {
    486        /* Still in child of original process.  Act like "cat -u".  */
    487        char buf[1 << 13];
    488        ssize_t inbytes;
    489        pid_t w;
    490        int status;
    491 
    492        if (close (stderr_pipe[1]) < 0)
    493            error (1, errno, "cannot close pipe");
    494 
    495        while ((inbytes = read (stderr_pipe[0], buf, sizeof buf)) != 0)
    496        {
    497            size_t outbytes = 0;
    498 
    499            if (inbytes < 0)
    500            {
    501                if (errno == EINTR)
    502                    continue;
    503                error (1, errno, "reading from pipe");
    504            }
    505 
    506            do
    507            {
    508                ssize_t w = write (STDERR_FILENO,
    509                                   buf + outbytes, inbytes - outbytes);
    510                if (w < 0)
    511                {
    512                    if (errno == EINTR)
    513                      w = 0;
    514                    if (w < 0)
    515                      _exit (1);
    516                }
    517                outbytes += w;
    518            }
    519            while (inbytes != outbytes);
    520        }
    521 
    522        /* Done processing output from grandchild.  Propagate
    523           its exit status back to the parent.  */
    524        while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
    525            continue;
    526        if (w < 0)
    527            error (1, errno, "waiting for child");
    528        if (!WIFEXITED (status))
    529        {
    530            if (WIFSIGNALED (status))
    531                raise (WTERMSIG (status));
    532            error (1, errno, "child did not exit cleanly");
    533        }
    534        _exit (WEXITSTATUS (status));
    535     }
    536 
    537     /* Grandchild of original process.  */
    538     if (close (stderr_pipe[0]) < 0)
    539        error (1, errno, "cannot close pipe");
    540 
    541     if (stderr_pipe[1] != STDERR_FILENO)
    542     {
    543        if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
    544            error (1, errno, "cannot dup2 pipe");
    545        if (close (stderr_pipe[1]) < 0)
    546            error (1, errno, "cannot close pipe");
    547     }
    548 }
    549 
    550 
    551 
    552 int
    553 piped_child (char *const *command, int *tofdp, int *fromfdp, bool fix_stderr)
    554 {
    555     int pid;
    556     int to_child_pipe[2];
    557     int from_child_pipe[2];
    558 
    559     if (pipe (to_child_pipe) < 0)
    560 	error (1, errno, "cannot create pipe");
    561     if (pipe (from_child_pipe) < 0)
    562 	error (1, errno, "cannot create pipe");
    563 
    564 #ifdef USE_SETMODE_BINARY
    565     setmode (to_child_pipe[0], O_BINARY);
    566     setmode (to_child_pipe[1], O_BINARY);
    567     setmode (from_child_pipe[0], O_BINARY);
    568     setmode (from_child_pipe[1], O_BINARY);
    569 #endif
    570 
    571     pid = fork ();
    572     if (pid < 0)
    573 	error (1, errno, "cannot fork");
    574     if (pid == 0)
    575     {
    576 #ifdef SIGINFO
    577 	signal (SIGINFO, SIG_DFL);
    578 #endif
    579 	if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
    580 	    error (1, errno, "cannot dup2 pipe");
    581 	if (close (to_child_pipe[1]) < 0)
    582 	    error (1, errno, "cannot close pipe");
    583 	if (close (from_child_pipe[0]) < 0)
    584 	    error (1, errno, "cannot close pipe");
    585 	if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
    586 	    error (1, errno, "cannot dup2 pipe");
    587 
    588         if (fix_stderr)
    589 	    work_around_openssh_glitch ();
    590 
    591 	/* Okay to cast out const below - execvp don't return nohow.  */
    592 	execvp ((char *)command[0], (char **)command);
    593 	error (1, errno, "cannot exec %s", command[0]);
    594     }
    595     if (close (to_child_pipe[0]) < 0)
    596 	error (1, errno, "cannot close pipe");
    597     if (close (from_child_pipe[1]) < 0)
    598 	error (1, errno, "cannot close pipe");
    599 
    600     *tofdp = to_child_pipe[1];
    601     *fromfdp = from_child_pipe[0];
    602     return pid;
    603 }
    604 
    605 
    606 
    607 int
    608 run_piped (int *tofdp, int *fromfdp)
    609 {
    610     run_add_arg (NULL);
    611     return piped_child (run_argv, tofdp, fromfdp, false);
    612 }
    613 
    614 
    615 
    616 void
    617 close_on_exec (int fd)
    618 {
    619 #ifdef F_SETFD
    620     if (fcntl (fd, F_SETFD, 1) == -1)
    621 	error (1, errno, "can't set close-on-exec flag on %d", fd);
    622 #endif
    623 }
    624