run.c revision 54427
117721Speter/* run.c --- routines for executing subprocesses.
217721Speter
317721Speter   This file is part of GNU CVS.
417721Speter
517721Speter   GNU CVS is free software; you can redistribute it and/or modify it
617721Speter   under the terms of the GNU General Public License as published by the
717721Speter   Free Software Foundation; either version 2, or (at your option) any
817721Speter   later version.
917721Speter
1017721Speter   This program is distributed in the hope that it will be useful,
1117721Speter   but WITHOUT ANY WARRANTY; without even the implied warranty of
1217721Speter   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1325839Speter   GNU General Public License for more details.  */
1417721Speter
1517721Speter#include "cvs.h"
1617721Speter
1732785Speter#ifndef HAVE_UNISTD_H
1832785Speterextern int execvp PROTO((char *file, char **argv));
1917721Speter#endif
2017721Speter
2117721Speterstatic void run_add_arg PROTO((const char *s));
2217721Speter
2317721Speterextern char *strtok ();
2417721Speter
2517721Speter/*
2632785Speter * To exec a program under CVS, first call run_setup() to setup initial
2732785Speter * arguments.  The argument to run_setup will be parsed into whitespace
2832785Speter * separated words and added to the global run_argv list.
2917721Speter *
3017721Speter * Then, optionally call run_arg() for each additional argument that you'd like
3117721Speter * to pass to the executed program.
3217721Speter *
3317721Speter * Finally, call run_exec() to execute the program with the specified arguments.
3417721Speter * The execvp() syscall will be used, so that the PATH is searched correctly.
3517721Speter * File redirections can be performed in the call to run_exec().
3617721Speter */
3717721Speterstatic char **run_argv;
3817721Speterstatic int run_argc;
3917721Speterstatic int run_argc_allocated;
4017721Speter
4117721Speter/* VARARGS */
4217721Spetervoid
4332785Speterrun_setup (prog)
4432785Speter    const char *prog;
4517721Speter{
4617721Speter    char *cp;
4717721Speter    int i;
4825839Speter    char *run_prog;
4917721Speter
5017721Speter    /* clean out any malloc'ed values from run_argv */
5117721Speter    for (i = 0; i < run_argc; i++)
5217721Speter    {
5317721Speter	if (run_argv[i])
5417721Speter	{
5517721Speter	    free (run_argv[i]);
5617721Speter	    run_argv[i] = (char *) 0;
5717721Speter	}
5817721Speter    }
5917721Speter    run_argc = 0;
6017721Speter
6132785Speter    run_prog = xstrdup (prog);
6217721Speter
6317721Speter    /* put each word into run_argv, allocating it as we go */
6417721Speter    for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
6517721Speter	run_add_arg (cp);
6625839Speter    free (run_prog);
6717721Speter}
6817721Speter
6917721Spetervoid
7017721Speterrun_arg (s)
7117721Speter    const char *s;
7217721Speter{
7317721Speter    run_add_arg (s);
7417721Speter}
7517721Speter
7617721Speterstatic void
7717721Speterrun_add_arg (s)
7817721Speter    const char *s;
7917721Speter{
8017721Speter    /* allocate more argv entries if we've run out */
8117721Speter    if (run_argc >= run_argc_allocated)
8217721Speter    {
8317721Speter	run_argc_allocated += 50;
8417721Speter	run_argv = (char **) xrealloc ((char *) run_argv,
8517721Speter				     run_argc_allocated * sizeof (char **));
8617721Speter    }
8717721Speter
8817721Speter    if (s)
8917721Speter	run_argv[run_argc++] = xstrdup (s);
9017721Speter    else
9117721Speter	run_argv[run_argc] = (char *) 0;	/* not post-incremented on purpose! */
9217721Speter}
9317721Speter
9417721Speterint
9517721Speterrun_exec (stin, stout, sterr, flags)
9632785Speter    const char *stin;
9732785Speter    const char *stout;
9832785Speter    const char *sterr;
9917721Speter    int flags;
10017721Speter{
10117721Speter    int shin, shout, sherr;
10217721Speter    int mode_out, mode_err;
10317721Speter    int status;
10417721Speter    int rc = -1;
10517721Speter    int rerrno = 0;
10617721Speter    int pid, w;
10717721Speter
10817721Speter#ifdef POSIX_SIGNALS
10917721Speter    sigset_t sigset_mask, sigset_omask;
11017721Speter    struct sigaction act, iact, qact;
11117721Speter
11217721Speter#else
11317721Speter#ifdef BSD_SIGNALS
11417721Speter    int mask;
11517721Speter    struct sigvec vec, ivec, qvec;
11617721Speter
11717721Speter#else
11817721Speter    RETSIGTYPE (*istat) (), (*qstat) ();
11917721Speter#endif
12017721Speter#endif
12117721Speter
12217721Speter    if (trace)
12317721Speter    {
12417721Speter#ifdef SERVER_SUPPORT
12525839Speter	cvs_outerr (server_active ? "S" : " ", 1);
12617721Speter#endif
12725839Speter	cvs_outerr ("-> system(", 0);
12817721Speter	run_print (stderr);
12925839Speter	cvs_outerr (")\n", 0);
13017721Speter    }
13117721Speter    if (noexec && (flags & RUN_REALLY) == 0)
13217721Speter	return (0);
13317721Speter
13417721Speter    /* make sure that we are null terminated, since we didn't calloc */
13517721Speter    run_add_arg ((char *) 0);
13617721Speter
13717721Speter    /* setup default file descriptor numbers */
13817721Speter    shin = 0;
13917721Speter    shout = 1;
14017721Speter    sherr = 2;
14117721Speter
14217721Speter    /* set the file modes for stdout and stderr */
14317721Speter    mode_out = mode_err = O_WRONLY | O_CREAT;
14417721Speter    mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
14517721Speter    mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
14617721Speter
14717721Speter    if (stin && (shin = open (stin, O_RDONLY)) == -1)
14817721Speter    {
14917721Speter	rerrno = errno;
15017721Speter	error (0, errno, "cannot open %s for reading (prog %s)",
15117721Speter	       stin, run_argv[0]);
15217721Speter	goto out0;
15317721Speter    }
15417721Speter    if (stout && (shout = open (stout, mode_out, 0666)) == -1)
15517721Speter    {
15617721Speter	rerrno = errno;
15717721Speter	error (0, errno, "cannot open %s for writing (prog %s)",
15817721Speter	       stout, run_argv[0]);
15917721Speter	goto out1;
16017721Speter    }
16117721Speter    if (sterr && (flags & RUN_COMBINED) == 0)
16217721Speter    {
16317721Speter	if ((sherr = open (sterr, mode_err, 0666)) == -1)
16417721Speter	{
16517721Speter	    rerrno = errno;
16617721Speter	    error (0, errno, "cannot open %s for writing (prog %s)",
16717721Speter		   sterr, run_argv[0]);
16817721Speter	    goto out2;
16917721Speter	}
17017721Speter    }
17117721Speter
17217721Speter    /* Make sure we don't flush this twice, once in the subprocess.  */
17317721Speter    fflush (stdout);
17417721Speter    fflush (stderr);
17517721Speter
17625839Speter    /* The output files, if any, are now created.  Do the fork and dups.
17725839Speter
17854427Speter       We use vfork not so much for a performance boost (the
17954427Speter       performance boost, if any, is modest on most modern unices),
18054427Speter       but for the sake of systems without a memory management unit,
18154427Speter       which find it difficult or impossible to implement fork at all
18254427Speter       (e.g. Amiga).  The other solution is spawn (see
18325839Speter       windows-NT/run.c).  */
18425839Speter
18517721Speter#ifdef HAVE_VFORK
18617721Speter    pid = vfork ();
18717721Speter#else
18817721Speter    pid = fork ();
18917721Speter#endif
19017721Speter    if (pid == 0)
19117721Speter    {
19217721Speter	if (shin != 0)
19317721Speter	{
19417721Speter	    (void) dup2 (shin, 0);
19517721Speter	    (void) close (shin);
19617721Speter	}
19717721Speter	if (shout != 1)
19817721Speter	{
19917721Speter	    (void) dup2 (shout, 1);
20017721Speter	    (void) close (shout);
20117721Speter	}
20217721Speter	if (flags & RUN_COMBINED)
20317721Speter	    (void) dup2 (1, 2);
20417721Speter	else if (sherr != 2)
20517721Speter	{
20617721Speter	    (void) dup2 (sherr, 2);
20717721Speter	    (void) close (sherr);
20817721Speter	}
20917721Speter
21017721Speter	/* dup'ing is done.  try to run it now */
21117721Speter	(void) execvp (run_argv[0], run_argv);
21217721Speter	error (0, errno, "cannot exec %s", run_argv[0]);
21317721Speter	_exit (127);
21417721Speter    }
21517721Speter    else if (pid == -1)
21617721Speter    {
21717721Speter	rerrno = errno;
21817721Speter	goto out;
21917721Speter    }
22017721Speter
22117721Speter    /* the parent.  Ignore some signals for now */
22217721Speter#ifdef POSIX_SIGNALS
22317721Speter    if (flags & RUN_SIGIGNORE)
22417721Speter    {
22517721Speter	act.sa_handler = SIG_IGN;
22617721Speter	(void) sigemptyset (&act.sa_mask);
22717721Speter	act.sa_flags = 0;
22817721Speter	(void) sigaction (SIGINT, &act, &iact);
22917721Speter	(void) sigaction (SIGQUIT, &act, &qact);
23017721Speter    }
23117721Speter    else
23217721Speter    {
23317721Speter	(void) sigemptyset (&sigset_mask);
23417721Speter	(void) sigaddset (&sigset_mask, SIGINT);
23517721Speter	(void) sigaddset (&sigset_mask, SIGQUIT);
23617721Speter	(void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
23717721Speter    }
23817721Speter#else
23917721Speter#ifdef BSD_SIGNALS
24017721Speter    if (flags & RUN_SIGIGNORE)
24117721Speter    {
24217721Speter	memset ((char *) &vec, 0, sizeof (vec));
24317721Speter	vec.sv_handler = SIG_IGN;
24417721Speter	(void) sigvec (SIGINT, &vec, &ivec);
24517721Speter	(void) sigvec (SIGQUIT, &vec, &qvec);
24617721Speter    }
24717721Speter    else
24817721Speter	mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
24917721Speter#else
25017721Speter    istat = signal (SIGINT, SIG_IGN);
25117721Speter    qstat = signal (SIGQUIT, SIG_IGN);
25217721Speter#endif
25317721Speter#endif
25417721Speter
25517721Speter    /* wait for our process to die and munge return status */
25617721Speter#ifdef POSIX_SIGNALS
25717721Speter    while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
25817721Speter	;
25917721Speter#else
26017721Speter    while ((w = wait (&status)) != pid)
26117721Speter    {
26217721Speter	if (w == -1 && errno != EINTR)
26317721Speter	    break;
26417721Speter    }
26517721Speter#endif
26617721Speter
26717721Speter    if (w == -1)
26817721Speter    {
26917721Speter	rc = -1;
27017721Speter	rerrno = errno;
27117721Speter    }
27217721Speter#ifndef VMS /* status is return status */
27317721Speter    else if (WIFEXITED (status))
27417721Speter	rc = WEXITSTATUS (status);
27517721Speter    else if (WIFSIGNALED (status))
27617721Speter    {
27717721Speter	if (WTERMSIG (status) == SIGPIPE)
27817721Speter	    error (1, 0, "broken pipe");
27917721Speter	rc = 2;
28017721Speter    }
28117721Speter    else
28217721Speter	rc = 1;
28317721Speter#else /* VMS */
28417721Speter    rc = WEXITSTATUS (status);
28517721Speter#endif /* VMS */
28617721Speter
28717721Speter    /* restore the signals */
28817721Speter#ifdef POSIX_SIGNALS
28917721Speter    if (flags & RUN_SIGIGNORE)
29017721Speter    {
29117721Speter	(void) sigaction (SIGINT, &iact, (struct sigaction *) NULL);
29217721Speter	(void) sigaction (SIGQUIT, &qact, (struct sigaction *) NULL);
29317721Speter    }
29417721Speter    else
29517721Speter	(void) sigprocmask (SIG_SETMASK, &sigset_omask, (sigset_t *) NULL);
29617721Speter#else
29717721Speter#ifdef BSD_SIGNALS
29817721Speter    if (flags & RUN_SIGIGNORE)
29917721Speter    {
30017721Speter	(void) sigvec (SIGINT, &ivec, (struct sigvec *) NULL);
30117721Speter	(void) sigvec (SIGQUIT, &qvec, (struct sigvec *) NULL);
30217721Speter    }
30317721Speter    else
30417721Speter	(void) sigsetmask (mask);
30517721Speter#else
30617721Speter    (void) signal (SIGINT, istat);
30717721Speter    (void) signal (SIGQUIT, qstat);
30817721Speter#endif
30917721Speter#endif
31017721Speter
31117721Speter    /* cleanup the open file descriptors */
31217721Speter  out:
31317721Speter    if (sterr)
31417721Speter	(void) close (sherr);
31517721Speter  out2:
31617721Speter    if (stout)
31717721Speter	(void) close (shout);
31817721Speter  out1:
31917721Speter    if (stin)
32017721Speter	(void) close (shin);
32117721Speter
32217721Speter  out0:
32317721Speter    if (rerrno)
32417721Speter	errno = rerrno;
32517721Speter    return (rc);
32617721Speter}
32717721Speter
32817721Spetervoid
32917721Speterrun_print (fp)
33017721Speter    FILE *fp;
33117721Speter{
33217721Speter    int i;
33325839Speter    void (*outfn) PROTO ((const char *, size_t));
33417721Speter
33525839Speter    if (fp == stderr)
33625839Speter	outfn = cvs_outerr;
33725839Speter    else if (fp == stdout)
33825839Speter	outfn = cvs_output;
33925839Speter    else
34032785Speter    {
34125839Speter	error (1, 0, "internal error: bad argument to run_print");
34232785Speter	/* Solely to placate gcc -Wall.
34332785Speter	   FIXME: it'd be better to use a function named `fatal' that
34432785Speter	   is known never to return.  Then kludges wouldn't be necessary.  */
34532785Speter	outfn = NULL;
34632785Speter    }
34725839Speter
34817721Speter    for (i = 0; i < run_argc; i++)
34917721Speter    {
35025839Speter	(*outfn) ("'", 1);
35125839Speter	(*outfn) (run_argv[i], 0);
35225839Speter	(*outfn) ("'", 1);
35317721Speter	if (i != run_argc - 1)
35425839Speter	    (*outfn) (" ", 1);
35517721Speter    }
35617721Speter}
35717721Speter
35832785Speter/* Return value is NULL for error, or if noexec was set.  If there was an
35932785Speter   error, return NULL and I'm not sure whether errno was set (the Red Hat
36032785Speter   Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec
36132785Speter   case complicates this even aside from popen behavior).  */
36232785Speter
36317721SpeterFILE *
36417721Speterrun_popen (cmd, mode)
36517721Speter    const char *cmd;
36617721Speter    const char *mode;
36717721Speter{
36817721Speter    if (trace)
36954427Speter	(void) fprintf (stderr, "%s-> run_popen(%s,%s)\n",
37054427Speter			CLIENT_SERVER_STR, cmd, mode);
37117721Speter    if (noexec)
37217721Speter	return (NULL);
37317721Speter
37417721Speter    return (popen (cmd, mode));
37517721Speter}
37617721Speter
37717721Speterint
37817721Speterpiped_child (command, tofdp, fromfdp)
37917721Speter     char **command;
38017721Speter     int *tofdp;
38117721Speter     int *fromfdp;
38217721Speter{
38317721Speter    int pid;
38417721Speter    int to_child_pipe[2];
38517721Speter    int from_child_pipe[2];
38617721Speter
38717721Speter    if (pipe (to_child_pipe) < 0)
38817721Speter	error (1, errno, "cannot create pipe");
38917721Speter    if (pipe (from_child_pipe) < 0)
39017721Speter	error (1, errno, "cannot create pipe");
39117721Speter
39226801Speter#ifdef USE_SETMODE_BINARY
39326801Speter    setmode (to_child_pipe[0], O_BINARY);
39426801Speter    setmode (to_child_pipe[1], O_BINARY);
39526801Speter    setmode (from_child_pipe[0], O_BINARY);
39626801Speter    setmode (from_child_pipe[1], O_BINARY);
39726801Speter#endif
39826801Speter
39925839Speter#ifdef HAVE_VFORK
40025839Speter    pid = vfork ();
40125839Speter#else
40217721Speter    pid = fork ();
40325839Speter#endif
40417721Speter    if (pid < 0)
40517721Speter	error (1, errno, "cannot fork");
40617721Speter    if (pid == 0)
40717721Speter    {
40817721Speter	if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
40954427Speter	    error (1, errno, "cannot dup2 pipe");
41017721Speter	if (close (to_child_pipe[1]) < 0)
41154427Speter	    error (1, errno, "cannot close pipe");
41217721Speter	if (close (from_child_pipe[0]) < 0)
41354427Speter	    error (1, errno, "cannot close pipe");
41417721Speter	if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
41554427Speter	    error (1, errno, "cannot dup2 pipe");
41617721Speter
41717721Speter	execvp (command[0], command);
41854427Speter	error (1, errno, "cannot exec %s", command[0]);
41917721Speter    }
42017721Speter    if (close (to_child_pipe[0]) < 0)
42154427Speter	error (1, errno, "cannot close pipe");
42217721Speter    if (close (from_child_pipe[1]) < 0)
42354427Speter	error (1, errno, "cannot close pipe");
42417721Speter
42517721Speter    *tofdp = to_child_pipe[1];
42617721Speter    *fromfdp = from_child_pipe[0];
42717721Speter    return pid;
42817721Speter}
42917721Speter
43017721Speter
43117721Spetervoid
43217721Speterclose_on_exec (fd)
43317721Speter     int fd;
43417721Speter{
43517721Speter#if defined (FD_CLOEXEC) && defined (F_SETFD)
43654427Speter    if (fcntl (fd, F_SETFD, 1))
43754427Speter	error (1, errno, "can't set close-on-exec flag on %d", fd);
43817721Speter#endif
43917721Speter}
440