run.c revision 81404
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
21066525Speter#ifdef SETXID_SUPPORT
21166525Speter	/*
21266525Speter	** This prevents a user from creating a privileged shell
21366525Speter	** from the text editor when the SETXID_SUPPORT option is selected.
21466525Speter	*/
21566525Speter	if (!strcmp (run_argv[0], Editor) && setegid (getgid ()))
21666525Speter	{
21766525Speter	    error (0, errno, "cannot set egid to gid");
21866525Speter	    _exit (127);
21966525Speter	}
22066525Speter#endif
22166525Speter
22217721Speter	/* dup'ing is done.  try to run it now */
22317721Speter	(void) execvp (run_argv[0], run_argv);
22417721Speter	error (0, errno, "cannot exec %s", run_argv[0]);
22517721Speter	_exit (127);
22617721Speter    }
22717721Speter    else if (pid == -1)
22817721Speter    {
22917721Speter	rerrno = errno;
23017721Speter	goto out;
23117721Speter    }
23217721Speter
23317721Speter    /* the parent.  Ignore some signals for now */
23417721Speter#ifdef POSIX_SIGNALS
23517721Speter    if (flags & RUN_SIGIGNORE)
23617721Speter    {
23717721Speter	act.sa_handler = SIG_IGN;
23817721Speter	(void) sigemptyset (&act.sa_mask);
23917721Speter	act.sa_flags = 0;
24017721Speter	(void) sigaction (SIGINT, &act, &iact);
24117721Speter	(void) sigaction (SIGQUIT, &act, &qact);
24217721Speter    }
24317721Speter    else
24417721Speter    {
24517721Speter	(void) sigemptyset (&sigset_mask);
24617721Speter	(void) sigaddset (&sigset_mask, SIGINT);
24717721Speter	(void) sigaddset (&sigset_mask, SIGQUIT);
24817721Speter	(void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
24917721Speter    }
25017721Speter#else
25117721Speter#ifdef BSD_SIGNALS
25217721Speter    if (flags & RUN_SIGIGNORE)
25317721Speter    {
25417721Speter	memset ((char *) &vec, 0, sizeof (vec));
25517721Speter	vec.sv_handler = SIG_IGN;
25617721Speter	(void) sigvec (SIGINT, &vec, &ivec);
25717721Speter	(void) sigvec (SIGQUIT, &vec, &qvec);
25817721Speter    }
25917721Speter    else
26017721Speter	mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
26117721Speter#else
26217721Speter    istat = signal (SIGINT, SIG_IGN);
26317721Speter    qstat = signal (SIGQUIT, SIG_IGN);
26417721Speter#endif
26517721Speter#endif
26617721Speter
26717721Speter    /* wait for our process to die and munge return status */
26817721Speter#ifdef POSIX_SIGNALS
26917721Speter    while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
27017721Speter	;
27117721Speter#else
27217721Speter    while ((w = wait (&status)) != pid)
27317721Speter    {
27417721Speter	if (w == -1 && errno != EINTR)
27517721Speter	    break;
27617721Speter    }
27717721Speter#endif
27817721Speter
27917721Speter    if (w == -1)
28017721Speter    {
28117721Speter	rc = -1;
28217721Speter	rerrno = errno;
28317721Speter    }
28417721Speter#ifndef VMS /* status is return status */
28517721Speter    else if (WIFEXITED (status))
28617721Speter	rc = WEXITSTATUS (status);
28717721Speter    else if (WIFSIGNALED (status))
28817721Speter    {
28917721Speter	if (WTERMSIG (status) == SIGPIPE)
29017721Speter	    error (1, 0, "broken pipe");
29117721Speter	rc = 2;
29217721Speter    }
29317721Speter    else
29417721Speter	rc = 1;
29517721Speter#else /* VMS */
29617721Speter    rc = WEXITSTATUS (status);
29717721Speter#endif /* VMS */
29817721Speter
29917721Speter    /* restore the signals */
30017721Speter#ifdef POSIX_SIGNALS
30117721Speter    if (flags & RUN_SIGIGNORE)
30217721Speter    {
30317721Speter	(void) sigaction (SIGINT, &iact, (struct sigaction *) NULL);
30417721Speter	(void) sigaction (SIGQUIT, &qact, (struct sigaction *) NULL);
30517721Speter    }
30617721Speter    else
30717721Speter	(void) sigprocmask (SIG_SETMASK, &sigset_omask, (sigset_t *) NULL);
30817721Speter#else
30917721Speter#ifdef BSD_SIGNALS
31017721Speter    if (flags & RUN_SIGIGNORE)
31117721Speter    {
31217721Speter	(void) sigvec (SIGINT, &ivec, (struct sigvec *) NULL);
31317721Speter	(void) sigvec (SIGQUIT, &qvec, (struct sigvec *) NULL);
31417721Speter    }
31517721Speter    else
31617721Speter	(void) sigsetmask (mask);
31717721Speter#else
31817721Speter    (void) signal (SIGINT, istat);
31917721Speter    (void) signal (SIGQUIT, qstat);
32017721Speter#endif
32117721Speter#endif
32217721Speter
32317721Speter    /* cleanup the open file descriptors */
32417721Speter  out:
32517721Speter    if (sterr)
32617721Speter	(void) close (sherr);
32781404Speter    else
32881404Speter	/* ensure things are received by the parent in the correct order
32981404Speter	 * relative to the protocol pipe
33081404Speter	 */
33181404Speter	cvs_flusherr();
33217721Speter  out2:
33317721Speter    if (stout)
33417721Speter	(void) close (shout);
33581404Speter    else
33681404Speter	/* ensure things are received by the parent in the correct order
33781404Speter	 * relative to the protocol pipe
33881404Speter	 */
33981404Speter	cvs_flushout();
34017721Speter  out1:
34117721Speter    if (stin)
34217721Speter	(void) close (shin);
34317721Speter
34417721Speter  out0:
34517721Speter    if (rerrno)
34617721Speter	errno = rerrno;
34717721Speter    return (rc);
34817721Speter}
34917721Speter
35017721Spetervoid
35117721Speterrun_print (fp)
35217721Speter    FILE *fp;
35317721Speter{
35417721Speter    int i;
35525839Speter    void (*outfn) PROTO ((const char *, size_t));
35617721Speter
35725839Speter    if (fp == stderr)
35825839Speter	outfn = cvs_outerr;
35925839Speter    else if (fp == stdout)
36025839Speter	outfn = cvs_output;
36125839Speter    else
36232785Speter    {
36325839Speter	error (1, 0, "internal error: bad argument to run_print");
36432785Speter	/* Solely to placate gcc -Wall.
36532785Speter	   FIXME: it'd be better to use a function named `fatal' that
36632785Speter	   is known never to return.  Then kludges wouldn't be necessary.  */
36732785Speter	outfn = NULL;
36832785Speter    }
36925839Speter
37017721Speter    for (i = 0; i < run_argc; i++)
37117721Speter    {
37225839Speter	(*outfn) ("'", 1);
37325839Speter	(*outfn) (run_argv[i], 0);
37425839Speter	(*outfn) ("'", 1);
37517721Speter	if (i != run_argc - 1)
37625839Speter	    (*outfn) (" ", 1);
37717721Speter    }
37817721Speter}
37917721Speter
38032785Speter/* Return value is NULL for error, or if noexec was set.  If there was an
38132785Speter   error, return NULL and I'm not sure whether errno was set (the Red Hat
38232785Speter   Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec
38332785Speter   case complicates this even aside from popen behavior).  */
38432785Speter
38517721SpeterFILE *
38617721Speterrun_popen (cmd, mode)
38717721Speter    const char *cmd;
38817721Speter    const char *mode;
38917721Speter{
39017721Speter    if (trace)
39154427Speter	(void) fprintf (stderr, "%s-> run_popen(%s,%s)\n",
39254427Speter			CLIENT_SERVER_STR, cmd, mode);
39317721Speter    if (noexec)
39417721Speter	return (NULL);
39517721Speter
39617721Speter    return (popen (cmd, mode));
39717721Speter}
39817721Speter
39917721Speterint
40017721Speterpiped_child (command, tofdp, fromfdp)
40117721Speter     char **command;
40217721Speter     int *tofdp;
40317721Speter     int *fromfdp;
40417721Speter{
40517721Speter    int pid;
40617721Speter    int to_child_pipe[2];
40717721Speter    int from_child_pipe[2];
40817721Speter
40917721Speter    if (pipe (to_child_pipe) < 0)
41017721Speter	error (1, errno, "cannot create pipe");
41117721Speter    if (pipe (from_child_pipe) < 0)
41217721Speter	error (1, errno, "cannot create pipe");
41317721Speter
41426801Speter#ifdef USE_SETMODE_BINARY
41526801Speter    setmode (to_child_pipe[0], O_BINARY);
41626801Speter    setmode (to_child_pipe[1], O_BINARY);
41726801Speter    setmode (from_child_pipe[0], O_BINARY);
41826801Speter    setmode (from_child_pipe[1], O_BINARY);
41926801Speter#endif
42026801Speter
42125839Speter#ifdef HAVE_VFORK
42225839Speter    pid = vfork ();
42325839Speter#else
42417721Speter    pid = fork ();
42525839Speter#endif
42617721Speter    if (pid < 0)
42717721Speter	error (1, errno, "cannot fork");
42817721Speter    if (pid == 0)
42917721Speter    {
43017721Speter	if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
43154427Speter	    error (1, errno, "cannot dup2 pipe");
43217721Speter	if (close (to_child_pipe[1]) < 0)
43354427Speter	    error (1, errno, "cannot close pipe");
43417721Speter	if (close (from_child_pipe[0]) < 0)
43554427Speter	    error (1, errno, "cannot close pipe");
43617721Speter	if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
43754427Speter	    error (1, errno, "cannot dup2 pipe");
43817721Speter
43917721Speter	execvp (command[0], command);
44054427Speter	error (1, errno, "cannot exec %s", command[0]);
44117721Speter    }
44217721Speter    if (close (to_child_pipe[0]) < 0)
44354427Speter	error (1, errno, "cannot close pipe");
44417721Speter    if (close (from_child_pipe[1]) < 0)
44554427Speter	error (1, errno, "cannot close pipe");
44617721Speter
44717721Speter    *tofdp = to_child_pipe[1];
44817721Speter    *fromfdp = from_child_pipe[0];
44917721Speter    return pid;
45017721Speter}
45117721Speter
45217721Speter
45317721Spetervoid
45417721Speterclose_on_exec (fd)
45517721Speter     int fd;
45617721Speter{
45781404Speter#ifdef F_SETFD
45854427Speter    if (fcntl (fd, F_SETFD, 1))
45954427Speter	error (1, errno, "can't set close-on-exec flag on %d", fd);
46017721Speter#endif
46117721Speter}
462