186d7f5d3SJohn Marino /* run.c --- routines for executing subprocesses.
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino This file is part of GNU CVS.
486d7f5d3SJohn Marino
586d7f5d3SJohn Marino GNU CVS is free software; you can redistribute it and/or modify it
686d7f5d3SJohn Marino under the terms of the GNU General Public License as published by the
786d7f5d3SJohn Marino Free Software Foundation; either version 2, or (at your option) any
886d7f5d3SJohn Marino later version.
986d7f5d3SJohn Marino
1086d7f5d3SJohn Marino This program is distributed in the hope that it will be useful,
1186d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1286d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1386d7f5d3SJohn Marino GNU General Public License for more details. */
1486d7f5d3SJohn Marino
1586d7f5d3SJohn Marino #include "cvs.h"
1686d7f5d3SJohn Marino
1786d7f5d3SJohn Marino #ifndef HAVE_UNISTD_H
1886d7f5d3SJohn Marino extern int execvp (char *file, char **argv);
1986d7f5d3SJohn Marino #endif
2086d7f5d3SJohn Marino
2186d7f5d3SJohn Marino
2286d7f5d3SJohn Marino
2386d7f5d3SJohn Marino /*
2486d7f5d3SJohn Marino * To exec a program under CVS, first call run_setup() to setup initial
2586d7f5d3SJohn Marino * arguments. The argument to run_setup will be parsed into whitespace
2686d7f5d3SJohn Marino * separated words and added to the global run_argv list.
2786d7f5d3SJohn Marino *
2886d7f5d3SJohn Marino * Then, optionally call run_add_arg() for each additional argument that you'd
2986d7f5d3SJohn Marino * like to pass to the executed program.
3086d7f5d3SJohn Marino *
3186d7f5d3SJohn Marino * Finally, call run_exec() to execute the program with the specified arguments.
3286d7f5d3SJohn Marino * The execvp() syscall will be used, so that the PATH is searched correctly.
3386d7f5d3SJohn Marino * File redirections can be performed in the call to run_exec().
3486d7f5d3SJohn Marino */
3586d7f5d3SJohn Marino static char **run_argv;
3686d7f5d3SJohn Marino static int run_argc;
3786d7f5d3SJohn Marino static size_t run_arg_allocated;
3886d7f5d3SJohn Marino
3986d7f5d3SJohn Marino
4086d7f5d3SJohn Marino
4186d7f5d3SJohn Marino void
run_arg_free_p(int argc,char ** argv)4286d7f5d3SJohn Marino run_arg_free_p (int argc, char **argv)
4386d7f5d3SJohn Marino {
4486d7f5d3SJohn Marino int i;
4586d7f5d3SJohn Marino for (i = 0; i < argc; i++)
4686d7f5d3SJohn Marino free (argv[i]);
4786d7f5d3SJohn Marino }
4886d7f5d3SJohn Marino
4986d7f5d3SJohn Marino
5086d7f5d3SJohn Marino
5186d7f5d3SJohn Marino /* VARARGS */
5286d7f5d3SJohn Marino void
run_setup(const char * prog)5386d7f5d3SJohn Marino run_setup (const char *prog)
5486d7f5d3SJohn Marino {
5586d7f5d3SJohn Marino char *run_prog;
5686d7f5d3SJohn Marino char *buf, *d, *s;
5786d7f5d3SJohn Marino size_t length;
5886d7f5d3SJohn Marino size_t doff;
5986d7f5d3SJohn Marino char inquotes;
6086d7f5d3SJohn Marino int dolastarg;
6186d7f5d3SJohn Marino
6286d7f5d3SJohn Marino /* clean out any malloc'ed values from run_argv */
6386d7f5d3SJohn Marino run_arg_free_p (run_argc, run_argv);
6486d7f5d3SJohn Marino run_argc = 0;
6586d7f5d3SJohn Marino
6686d7f5d3SJohn Marino run_prog = xstrdup (prog);
6786d7f5d3SJohn Marino
6886d7f5d3SJohn Marino s = run_prog;
6986d7f5d3SJohn Marino d = buf = NULL;
7086d7f5d3SJohn Marino length = 0;
7186d7f5d3SJohn Marino dolastarg = 1;
7286d7f5d3SJohn Marino inquotes = '\0';
7386d7f5d3SJohn Marino doff = d - buf;
7486d7f5d3SJohn Marino expand_string(&buf, &length, doff + 1);
7586d7f5d3SJohn Marino d = buf + doff;
7686d7f5d3SJohn Marino while ((*d = *s++) != '\0')
7786d7f5d3SJohn Marino {
7886d7f5d3SJohn Marino switch (*d)
7986d7f5d3SJohn Marino {
8086d7f5d3SJohn Marino case '\\':
8186d7f5d3SJohn Marino if (*s) *d = *s++;
8286d7f5d3SJohn Marino d++;
8386d7f5d3SJohn Marino break;
8486d7f5d3SJohn Marino case '"':
8586d7f5d3SJohn Marino case '\'':
8686d7f5d3SJohn Marino if (inquotes == *d) inquotes = '\0';
8786d7f5d3SJohn Marino else inquotes = *d;
8886d7f5d3SJohn Marino break;
8986d7f5d3SJohn Marino case ' ':
9086d7f5d3SJohn Marino case '\t':
9186d7f5d3SJohn Marino if (inquotes) d++;
9286d7f5d3SJohn Marino else
9386d7f5d3SJohn Marino {
9486d7f5d3SJohn Marino *d = '\0';
9586d7f5d3SJohn Marino run_add_arg (buf);
9686d7f5d3SJohn Marino d = buf;
9786d7f5d3SJohn Marino while (isspace(*s)) s++;
9886d7f5d3SJohn Marino if (!*s) dolastarg = 0;
9986d7f5d3SJohn Marino }
10086d7f5d3SJohn Marino break;
10186d7f5d3SJohn Marino default:
10286d7f5d3SJohn Marino d++;
10386d7f5d3SJohn Marino break;
10486d7f5d3SJohn Marino }
10586d7f5d3SJohn Marino doff = d - buf;
10686d7f5d3SJohn Marino expand_string(&buf, &length, doff + 1);
10786d7f5d3SJohn Marino d = buf + doff;
10886d7f5d3SJohn Marino }
10986d7f5d3SJohn Marino if (dolastarg) run_add_arg (buf);
11086d7f5d3SJohn Marino /* put each word into run_argv, allocating it as we go */
11186d7f5d3SJohn Marino if (buf) free (buf);
11286d7f5d3SJohn Marino free (run_prog);
11386d7f5d3SJohn Marino }
11486d7f5d3SJohn Marino
11586d7f5d3SJohn Marino
11686d7f5d3SJohn Marino
11786d7f5d3SJohn Marino void
run_add_arg_p(int * iargc,size_t * iarg_allocated,char *** iargv,const char * s)11886d7f5d3SJohn Marino run_add_arg_p (int *iargc, size_t *iarg_allocated, char ***iargv,
11986d7f5d3SJohn Marino const char *s)
12086d7f5d3SJohn Marino {
12186d7f5d3SJohn Marino /* allocate more argv entries if we've run out */
12286d7f5d3SJohn Marino if (*iargc >= *iarg_allocated)
12386d7f5d3SJohn Marino {
12486d7f5d3SJohn Marino *iarg_allocated += 50;
12586d7f5d3SJohn Marino *iargv = xnrealloc (*iargv, *iarg_allocated, sizeof (char **));
12686d7f5d3SJohn Marino }
12786d7f5d3SJohn Marino
12886d7f5d3SJohn Marino if (s)
12986d7f5d3SJohn Marino (*iargv)[(*iargc)++] = xstrdup (s);
13086d7f5d3SJohn Marino else
13186d7f5d3SJohn Marino (*iargv)[*iargc] = NULL; /* not post-incremented on purpose! */
13286d7f5d3SJohn Marino }
13386d7f5d3SJohn Marino
13486d7f5d3SJohn Marino
13586d7f5d3SJohn Marino
13686d7f5d3SJohn Marino void
run_add_arg(const char * s)13786d7f5d3SJohn Marino run_add_arg (const char *s)
13886d7f5d3SJohn Marino {
13986d7f5d3SJohn Marino run_add_arg_p (&run_argc, &run_arg_allocated, &run_argv, s);
14086d7f5d3SJohn Marino }
14186d7f5d3SJohn Marino
14286d7f5d3SJohn Marino
14386d7f5d3SJohn Marino
14486d7f5d3SJohn Marino int
run_exec(const char * stin,const char * stout,const char * sterr,int flags)14586d7f5d3SJohn Marino run_exec (const char *stin, const char *stout, const char *sterr, int flags)
14686d7f5d3SJohn Marino {
14786d7f5d3SJohn Marino int shin, shout, sherr;
14886d7f5d3SJohn Marino int mode_out, mode_err;
14986d7f5d3SJohn Marino int status;
15086d7f5d3SJohn Marino int rc = -1;
15186d7f5d3SJohn Marino int rerrno = 0;
15286d7f5d3SJohn Marino int pid, w;
15386d7f5d3SJohn Marino
15486d7f5d3SJohn Marino #ifdef POSIX_SIGNALS
15586d7f5d3SJohn Marino sigset_t sigset_mask, sigset_omask;
15686d7f5d3SJohn Marino struct sigaction act, iact, qact;
15786d7f5d3SJohn Marino
15886d7f5d3SJohn Marino #else
15986d7f5d3SJohn Marino #ifdef BSD_SIGNALS
16086d7f5d3SJohn Marino int mask;
16186d7f5d3SJohn Marino struct sigvec vec, ivec, qvec;
16286d7f5d3SJohn Marino
16386d7f5d3SJohn Marino #else
16486d7f5d3SJohn Marino RETSIGTYPE (*istat) (), (*qstat) ();
16586d7f5d3SJohn Marino #endif
16686d7f5d3SJohn Marino #endif
16786d7f5d3SJohn Marino
16886d7f5d3SJohn Marino if (trace)
16986d7f5d3SJohn Marino {
17086d7f5d3SJohn Marino cvs_outerr (
17186d7f5d3SJohn Marino #ifdef SERVER_SUPPORT
17286d7f5d3SJohn Marino server_active ? "S" :
17386d7f5d3SJohn Marino #endif
17486d7f5d3SJohn Marino " ", 1);
17586d7f5d3SJohn Marino cvs_outerr (" -> system (", 0);
17686d7f5d3SJohn Marino run_print (stderr);
17786d7f5d3SJohn Marino cvs_outerr (")\n", 0);
17886d7f5d3SJohn Marino }
17986d7f5d3SJohn Marino if (noexec && (flags & RUN_REALLY) == 0)
18086d7f5d3SJohn Marino return 0;
18186d7f5d3SJohn Marino
18286d7f5d3SJohn Marino /* make sure that we are null terminated, since we didn't calloc */
18386d7f5d3SJohn Marino run_add_arg (NULL);
18486d7f5d3SJohn Marino
18586d7f5d3SJohn Marino /* setup default file descriptor numbers */
18686d7f5d3SJohn Marino shin = 0;
18786d7f5d3SJohn Marino shout = 1;
18886d7f5d3SJohn Marino sherr = 2;
18986d7f5d3SJohn Marino
19086d7f5d3SJohn Marino /* set the file modes for stdout and stderr */
19186d7f5d3SJohn Marino mode_out = mode_err = O_WRONLY | O_CREAT;
19286d7f5d3SJohn Marino mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
19386d7f5d3SJohn Marino mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
19486d7f5d3SJohn Marino
19586d7f5d3SJohn Marino if (stin && (shin = open (stin, O_RDONLY)) == -1)
19686d7f5d3SJohn Marino {
19786d7f5d3SJohn Marino rerrno = errno;
19886d7f5d3SJohn Marino error (0, errno, "cannot open %s for reading (prog %s)",
19986d7f5d3SJohn Marino stin, run_argv[0]);
20086d7f5d3SJohn Marino goto out0;
20186d7f5d3SJohn Marino }
20286d7f5d3SJohn Marino if (stout && (shout = open (stout, mode_out, 0666)) == -1)
20386d7f5d3SJohn Marino {
20486d7f5d3SJohn Marino rerrno = errno;
20586d7f5d3SJohn Marino error (0, errno, "cannot open %s for writing (prog %s)",
20686d7f5d3SJohn Marino stout, run_argv[0]);
20786d7f5d3SJohn Marino goto out1;
20886d7f5d3SJohn Marino }
20986d7f5d3SJohn Marino if (sterr && (flags & RUN_COMBINED) == 0)
21086d7f5d3SJohn Marino {
21186d7f5d3SJohn Marino if ((sherr = open (sterr, mode_err, 0666)) == -1)
21286d7f5d3SJohn Marino {
21386d7f5d3SJohn Marino rerrno = errno;
21486d7f5d3SJohn Marino error (0, errno, "cannot open %s for writing (prog %s)",
21586d7f5d3SJohn Marino sterr, run_argv[0]);
21686d7f5d3SJohn Marino goto out2;
21786d7f5d3SJohn Marino }
21886d7f5d3SJohn Marino }
21986d7f5d3SJohn Marino
22086d7f5d3SJohn Marino /* Make sure we don't flush this twice, once in the subprocess. */
22186d7f5d3SJohn Marino cvs_flushout();
22286d7f5d3SJohn Marino cvs_flusherr();
22386d7f5d3SJohn Marino
22486d7f5d3SJohn Marino /* The output files, if any, are now created. Do the fork and dups.
22586d7f5d3SJohn Marino
22686d7f5d3SJohn Marino We use vfork not so much for a performance boost (the
22786d7f5d3SJohn Marino performance boost, if any, is modest on most modern unices),
22886d7f5d3SJohn Marino but for the sake of systems without a memory management unit,
22986d7f5d3SJohn Marino which find it difficult or impossible to implement fork at all
23086d7f5d3SJohn Marino (e.g. Amiga). The other solution is spawn (see
23186d7f5d3SJohn Marino windows-NT/run.c). */
23286d7f5d3SJohn Marino
23386d7f5d3SJohn Marino #ifdef HAVE_VFORK
23486d7f5d3SJohn Marino pid = vfork ();
23586d7f5d3SJohn Marino #else
23686d7f5d3SJohn Marino pid = fork ();
23786d7f5d3SJohn Marino #endif
23886d7f5d3SJohn Marino if (pid == 0)
23986d7f5d3SJohn Marino {
24086d7f5d3SJohn Marino if (shin != 0)
24186d7f5d3SJohn Marino {
24286d7f5d3SJohn Marino (void) dup2 (shin, 0);
24386d7f5d3SJohn Marino (void) close (shin);
24486d7f5d3SJohn Marino }
24586d7f5d3SJohn Marino if (shout != 1)
24686d7f5d3SJohn Marino {
24786d7f5d3SJohn Marino (void) dup2 (shout, 1);
24886d7f5d3SJohn Marino (void) close (shout);
24986d7f5d3SJohn Marino }
25086d7f5d3SJohn Marino if (flags & RUN_COMBINED)
25186d7f5d3SJohn Marino (void) dup2 (1, 2);
25286d7f5d3SJohn Marino else if (sherr != 2)
25386d7f5d3SJohn Marino {
25486d7f5d3SJohn Marino (void) dup2 (sherr, 2);
25586d7f5d3SJohn Marino (void) close (sherr);
25686d7f5d3SJohn Marino }
25786d7f5d3SJohn Marino
25886d7f5d3SJohn Marino #ifdef SETXID_SUPPORT
25986d7f5d3SJohn Marino /*
26086d7f5d3SJohn Marino ** This prevents a user from creating a privileged shell
26186d7f5d3SJohn Marino ** from the text editor when the SETXID_SUPPORT option is selected.
26286d7f5d3SJohn Marino */
26386d7f5d3SJohn Marino if (!strcmp (run_argv[0], Editor) && setegid (getgid ()))
26486d7f5d3SJohn Marino {
26586d7f5d3SJohn Marino error (0, errno, "cannot set egid to gid");
26686d7f5d3SJohn Marino _exit (127);
26786d7f5d3SJohn Marino }
26886d7f5d3SJohn Marino #endif
26986d7f5d3SJohn Marino
27086d7f5d3SJohn Marino /* dup'ing is done. try to run it now */
27186d7f5d3SJohn Marino (void) execvp (run_argv[0], run_argv);
27286d7f5d3SJohn Marino error (0, errno, "cannot exec %s", run_argv[0]);
27386d7f5d3SJohn Marino _exit (127);
27486d7f5d3SJohn Marino }
27586d7f5d3SJohn Marino else if (pid == -1)
27686d7f5d3SJohn Marino {
27786d7f5d3SJohn Marino rerrno = errno;
27886d7f5d3SJohn Marino goto out;
27986d7f5d3SJohn Marino }
28086d7f5d3SJohn Marino
28186d7f5d3SJohn Marino /* the parent. Ignore some signals for now */
28286d7f5d3SJohn Marino #ifdef POSIX_SIGNALS
28386d7f5d3SJohn Marino if (flags & RUN_SIGIGNORE)
28486d7f5d3SJohn Marino {
28586d7f5d3SJohn Marino act.sa_handler = SIG_IGN;
28686d7f5d3SJohn Marino (void) sigemptyset (&act.sa_mask);
28786d7f5d3SJohn Marino act.sa_flags = 0;
28886d7f5d3SJohn Marino (void) sigaction (SIGINT, &act, &iact);
28986d7f5d3SJohn Marino (void) sigaction (SIGQUIT, &act, &qact);
29086d7f5d3SJohn Marino }
29186d7f5d3SJohn Marino else
29286d7f5d3SJohn Marino {
29386d7f5d3SJohn Marino (void) sigemptyset (&sigset_mask);
29486d7f5d3SJohn Marino (void) sigaddset (&sigset_mask, SIGINT);
29586d7f5d3SJohn Marino (void) sigaddset (&sigset_mask, SIGQUIT);
29686d7f5d3SJohn Marino (void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
29786d7f5d3SJohn Marino }
29886d7f5d3SJohn Marino #else
29986d7f5d3SJohn Marino #ifdef BSD_SIGNALS
30086d7f5d3SJohn Marino if (flags & RUN_SIGIGNORE)
30186d7f5d3SJohn Marino {
30286d7f5d3SJohn Marino memset (&vec, 0, sizeof vec);
30386d7f5d3SJohn Marino vec.sv_handler = SIG_IGN;
30486d7f5d3SJohn Marino (void) sigvec (SIGINT, &vec, &ivec);
30586d7f5d3SJohn Marino (void) sigvec (SIGQUIT, &vec, &qvec);
30686d7f5d3SJohn Marino }
30786d7f5d3SJohn Marino else
30886d7f5d3SJohn Marino mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
30986d7f5d3SJohn Marino #else
31086d7f5d3SJohn Marino istat = signal (SIGINT, SIG_IGN);
31186d7f5d3SJohn Marino qstat = signal (SIGQUIT, SIG_IGN);
31286d7f5d3SJohn Marino #endif
31386d7f5d3SJohn Marino #endif
31486d7f5d3SJohn Marino
31586d7f5d3SJohn Marino /* wait for our process to die and munge return status */
31686d7f5d3SJohn Marino #ifdef POSIX_SIGNALS
31786d7f5d3SJohn Marino while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
31886d7f5d3SJohn Marino ;
31986d7f5d3SJohn Marino #else
32086d7f5d3SJohn Marino while ((w = wait (&status)) != pid)
32186d7f5d3SJohn Marino {
32286d7f5d3SJohn Marino if (w == -1 && errno != EINTR)
32386d7f5d3SJohn Marino break;
32486d7f5d3SJohn Marino }
32586d7f5d3SJohn Marino #endif
32686d7f5d3SJohn Marino
32786d7f5d3SJohn Marino if (w == -1)
32886d7f5d3SJohn Marino {
32986d7f5d3SJohn Marino rc = -1;
33086d7f5d3SJohn Marino rerrno = errno;
33186d7f5d3SJohn Marino }
33286d7f5d3SJohn Marino #ifndef VMS /* status is return status */
33386d7f5d3SJohn Marino else if (WIFEXITED (status))
33486d7f5d3SJohn Marino rc = WEXITSTATUS (status);
33586d7f5d3SJohn Marino else if (WIFSIGNALED (status))
33686d7f5d3SJohn Marino {
33786d7f5d3SJohn Marino if (WTERMSIG (status) == SIGPIPE)
33886d7f5d3SJohn Marino error (1, 0, "broken pipe");
33986d7f5d3SJohn Marino rc = 2;
34086d7f5d3SJohn Marino }
34186d7f5d3SJohn Marino else
34286d7f5d3SJohn Marino rc = 1;
34386d7f5d3SJohn Marino #else /* VMS */
34486d7f5d3SJohn Marino rc = WEXITSTATUS (status);
34586d7f5d3SJohn Marino #endif /* VMS */
34686d7f5d3SJohn Marino
34786d7f5d3SJohn Marino /* restore the signals */
34886d7f5d3SJohn Marino #ifdef POSIX_SIGNALS
34986d7f5d3SJohn Marino if (flags & RUN_SIGIGNORE)
35086d7f5d3SJohn Marino {
35186d7f5d3SJohn Marino (void) sigaction (SIGINT, &iact, NULL);
35286d7f5d3SJohn Marino (void) sigaction (SIGQUIT, &qact, NULL);
35386d7f5d3SJohn Marino }
35486d7f5d3SJohn Marino else
35586d7f5d3SJohn Marino (void) sigprocmask (SIG_SETMASK, &sigset_omask, NULL);
35686d7f5d3SJohn Marino #else
35786d7f5d3SJohn Marino #ifdef BSD_SIGNALS
35886d7f5d3SJohn Marino if (flags & RUN_SIGIGNORE)
35986d7f5d3SJohn Marino {
36086d7f5d3SJohn Marino (void) sigvec (SIGINT, &ivec, NULL);
36186d7f5d3SJohn Marino (void) sigvec (SIGQUIT, &qvec, NULL);
36286d7f5d3SJohn Marino }
36386d7f5d3SJohn Marino else
36486d7f5d3SJohn Marino (void) sigsetmask (mask);
36586d7f5d3SJohn Marino #else
36686d7f5d3SJohn Marino (void) signal (SIGINT, istat);
36786d7f5d3SJohn Marino (void) signal (SIGQUIT, qstat);
36886d7f5d3SJohn Marino #endif
36986d7f5d3SJohn Marino #endif
37086d7f5d3SJohn Marino
37186d7f5d3SJohn Marino /* cleanup the open file descriptors */
37286d7f5d3SJohn Marino out:
37386d7f5d3SJohn Marino if (sterr)
37486d7f5d3SJohn Marino (void) close (sherr);
37586d7f5d3SJohn Marino else
37686d7f5d3SJohn Marino /* ensure things are received by the parent in the correct order
37786d7f5d3SJohn Marino * relative to the protocol pipe
37886d7f5d3SJohn Marino */
37986d7f5d3SJohn Marino cvs_flusherr();
38086d7f5d3SJohn Marino out2:
38186d7f5d3SJohn Marino if (stout)
38286d7f5d3SJohn Marino (void) close (shout);
38386d7f5d3SJohn Marino else
38486d7f5d3SJohn Marino /* ensure things are received by the parent in the correct order
38586d7f5d3SJohn Marino * relative to the protocol pipe
38686d7f5d3SJohn Marino */
38786d7f5d3SJohn Marino cvs_flushout();
38886d7f5d3SJohn Marino out1:
38986d7f5d3SJohn Marino if (stin)
39086d7f5d3SJohn Marino (void) close (shin);
39186d7f5d3SJohn Marino
39286d7f5d3SJohn Marino out0:
39386d7f5d3SJohn Marino if (rerrno)
39486d7f5d3SJohn Marino errno = rerrno;
39586d7f5d3SJohn Marino return rc;
39686d7f5d3SJohn Marino }
39786d7f5d3SJohn Marino
39886d7f5d3SJohn Marino
39986d7f5d3SJohn Marino
40086d7f5d3SJohn Marino void
run_print(FILE * fp)40186d7f5d3SJohn Marino run_print (FILE *fp)
40286d7f5d3SJohn Marino {
40386d7f5d3SJohn Marino int i;
40486d7f5d3SJohn Marino void (*outfn) (const char *, size_t);
40586d7f5d3SJohn Marino
40686d7f5d3SJohn Marino if (fp == stderr)
40786d7f5d3SJohn Marino outfn = cvs_outerr;
40886d7f5d3SJohn Marino else if (fp == stdout)
40986d7f5d3SJohn Marino outfn = cvs_output;
41086d7f5d3SJohn Marino else
41186d7f5d3SJohn Marino {
41286d7f5d3SJohn Marino error (1, 0, "internal error: bad argument to run_print");
41386d7f5d3SJohn Marino /* Solely to placate gcc -Wall.
41486d7f5d3SJohn Marino FIXME: it'd be better to use a function named `fatal' that
41586d7f5d3SJohn Marino is known never to return. Then kludges wouldn't be necessary. */
41686d7f5d3SJohn Marino outfn = NULL;
41786d7f5d3SJohn Marino }
41886d7f5d3SJohn Marino
41986d7f5d3SJohn Marino for (i = 0; i < run_argc; i++)
42086d7f5d3SJohn Marino {
42186d7f5d3SJohn Marino (*outfn) ("'", 1);
42286d7f5d3SJohn Marino (*outfn) (run_argv[i], 0);
42386d7f5d3SJohn Marino (*outfn) ("'", 1);
42486d7f5d3SJohn Marino if (i != run_argc - 1)
42586d7f5d3SJohn Marino (*outfn) (" ", 1);
42686d7f5d3SJohn Marino }
42786d7f5d3SJohn Marino }
42886d7f5d3SJohn Marino
42986d7f5d3SJohn Marino
43086d7f5d3SJohn Marino
43186d7f5d3SJohn Marino /* Return value is NULL for error, or if noexec was set. If there was an
43286d7f5d3SJohn Marino error, return NULL and I'm not sure whether errno was set (the Red Hat
43386d7f5d3SJohn Marino Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec
43486d7f5d3SJohn Marino case complicates this even aside from popen behavior). */
43586d7f5d3SJohn Marino FILE *
run_popen(const char * cmd,const char * mode)43686d7f5d3SJohn Marino run_popen (const char *cmd, const char *mode)
43786d7f5d3SJohn Marino {
43886d7f5d3SJohn Marino TRACE (TRACE_FUNCTION, "run_popen (%s,%s)", cmd, mode);
43986d7f5d3SJohn Marino if (noexec)
44086d7f5d3SJohn Marino return NULL;
44186d7f5d3SJohn Marino
44286d7f5d3SJohn Marino return popen (cmd, mode);
44386d7f5d3SJohn Marino }
44486d7f5d3SJohn Marino
44586d7f5d3SJohn Marino
44686d7f5d3SJohn Marino
44786d7f5d3SJohn Marino /* Work around an OpenSSH problem: it can put its standard file
44886d7f5d3SJohn Marino descriptors into nonblocking mode, which will mess us up if we
44986d7f5d3SJohn Marino share file descriptions with it. The simplest workaround is
45086d7f5d3SJohn Marino to create an intervening process between OpenSSH and the
45186d7f5d3SJohn Marino actual stderr. */
45286d7f5d3SJohn Marino
45386d7f5d3SJohn Marino static void
work_around_openssh_glitch(void)45486d7f5d3SJohn Marino work_around_openssh_glitch (void)
45586d7f5d3SJohn Marino {
45686d7f5d3SJohn Marino pid_t pid;
45786d7f5d3SJohn Marino int stderr_pipe[2];
45886d7f5d3SJohn Marino struct stat sb;
45986d7f5d3SJohn Marino
46086d7f5d3SJohn Marino /* Do nothing unless stderr is a file that is affected by
46186d7f5d3SJohn Marino nonblocking mode. */
46286d7f5d3SJohn Marino if (!(fstat (STDERR_FILENO, &sb) == 0
46386d7f5d3SJohn Marino && (S_ISFIFO (sb.st_mode) || S_ISSOCK (sb.st_mode)
46486d7f5d3SJohn Marino || S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode))))
46586d7f5d3SJohn Marino return;
46686d7f5d3SJohn Marino
46786d7f5d3SJohn Marino if (pipe (stderr_pipe) < 0)
46886d7f5d3SJohn Marino error (1, errno, "cannot create pipe");
46986d7f5d3SJohn Marino pid = fork ();
47086d7f5d3SJohn Marino if (pid < 0)
47186d7f5d3SJohn Marino error (1, errno, "cannot fork");
47286d7f5d3SJohn Marino if (pid != 0)
47386d7f5d3SJohn Marino {
47486d7f5d3SJohn Marino /* Still in child of original process. Act like "cat -u". */
47586d7f5d3SJohn Marino char buf[1 << 13];
47686d7f5d3SJohn Marino ssize_t inbytes;
47786d7f5d3SJohn Marino pid_t w;
47886d7f5d3SJohn Marino int status;
47986d7f5d3SJohn Marino
48086d7f5d3SJohn Marino if (close (stderr_pipe[1]) < 0)
48186d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
48286d7f5d3SJohn Marino
48386d7f5d3SJohn Marino while ((inbytes = read (stderr_pipe[0], buf, sizeof buf)) != 0)
48486d7f5d3SJohn Marino {
48586d7f5d3SJohn Marino size_t outbytes = 0;
48686d7f5d3SJohn Marino
48786d7f5d3SJohn Marino if (inbytes < 0)
48886d7f5d3SJohn Marino {
48986d7f5d3SJohn Marino if (errno == EINTR)
49086d7f5d3SJohn Marino continue;
49186d7f5d3SJohn Marino error (1, errno, "reading from pipe");
49286d7f5d3SJohn Marino }
49386d7f5d3SJohn Marino
49486d7f5d3SJohn Marino do
49586d7f5d3SJohn Marino {
49686d7f5d3SJohn Marino ssize_t w = write (STDERR_FILENO,
49786d7f5d3SJohn Marino buf + outbytes, inbytes - outbytes);
49886d7f5d3SJohn Marino if (w < 0)
49986d7f5d3SJohn Marino {
50086d7f5d3SJohn Marino if (errno == EINTR)
50186d7f5d3SJohn Marino w = 0;
50286d7f5d3SJohn Marino if (w < 0)
50386d7f5d3SJohn Marino _exit (1);
50486d7f5d3SJohn Marino }
50586d7f5d3SJohn Marino outbytes += w;
50686d7f5d3SJohn Marino }
50786d7f5d3SJohn Marino while (inbytes != outbytes);
50886d7f5d3SJohn Marino }
50986d7f5d3SJohn Marino
51086d7f5d3SJohn Marino /* Done processing output from grandchild. Propagate
51186d7f5d3SJohn Marino its exit status back to the parent. */
51286d7f5d3SJohn Marino while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
51386d7f5d3SJohn Marino continue;
51486d7f5d3SJohn Marino if (w < 0)
51586d7f5d3SJohn Marino error (1, errno, "waiting for child");
51686d7f5d3SJohn Marino if (!WIFEXITED (status))
51786d7f5d3SJohn Marino {
51886d7f5d3SJohn Marino if (WIFSIGNALED (status))
51986d7f5d3SJohn Marino raise (WTERMSIG (status));
52086d7f5d3SJohn Marino error (1, errno, "child did not exit cleanly");
52186d7f5d3SJohn Marino }
52286d7f5d3SJohn Marino _exit (WEXITSTATUS (status));
52386d7f5d3SJohn Marino }
52486d7f5d3SJohn Marino
52586d7f5d3SJohn Marino /* Grandchild of original process. */
52686d7f5d3SJohn Marino if (close (stderr_pipe[0]) < 0)
52786d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
52886d7f5d3SJohn Marino
52986d7f5d3SJohn Marino if (stderr_pipe[1] != STDERR_FILENO)
53086d7f5d3SJohn Marino {
53186d7f5d3SJohn Marino if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
53286d7f5d3SJohn Marino error (1, errno, "cannot dup2 pipe");
53386d7f5d3SJohn Marino if (close (stderr_pipe[1]) < 0)
53486d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
53586d7f5d3SJohn Marino }
53686d7f5d3SJohn Marino }
53786d7f5d3SJohn Marino
53886d7f5d3SJohn Marino
53986d7f5d3SJohn Marino
54086d7f5d3SJohn Marino int
piped_child(char * const * command,int * tofdp,int * fromfdp,bool fix_stderr)54186d7f5d3SJohn Marino piped_child (char *const *command, int *tofdp, int *fromfdp, bool fix_stderr)
54286d7f5d3SJohn Marino {
54386d7f5d3SJohn Marino int pid;
54486d7f5d3SJohn Marino int to_child_pipe[2];
54586d7f5d3SJohn Marino int from_child_pipe[2];
54686d7f5d3SJohn Marino
54786d7f5d3SJohn Marino if (pipe (to_child_pipe) < 0)
54886d7f5d3SJohn Marino error (1, errno, "cannot create pipe");
54986d7f5d3SJohn Marino if (pipe (from_child_pipe) < 0)
55086d7f5d3SJohn Marino error (1, errno, "cannot create pipe");
55186d7f5d3SJohn Marino
55286d7f5d3SJohn Marino #ifdef USE_SETMODE_BINARY
55386d7f5d3SJohn Marino setmode (to_child_pipe[0], O_BINARY);
55486d7f5d3SJohn Marino setmode (to_child_pipe[1], O_BINARY);
55586d7f5d3SJohn Marino setmode (from_child_pipe[0], O_BINARY);
55686d7f5d3SJohn Marino setmode (from_child_pipe[1], O_BINARY);
55786d7f5d3SJohn Marino #endif
55886d7f5d3SJohn Marino
55986d7f5d3SJohn Marino pid = fork ();
56086d7f5d3SJohn Marino if (pid < 0)
56186d7f5d3SJohn Marino error (1, errno, "cannot fork");
56286d7f5d3SJohn Marino if (pid == 0)
56386d7f5d3SJohn Marino {
56486d7f5d3SJohn Marino if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
56586d7f5d3SJohn Marino error (1, errno, "cannot dup2 pipe");
56686d7f5d3SJohn Marino if (close (to_child_pipe[1]) < 0)
56786d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
56886d7f5d3SJohn Marino if (close (from_child_pipe[0]) < 0)
56986d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
57086d7f5d3SJohn Marino if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
57186d7f5d3SJohn Marino error (1, errno, "cannot dup2 pipe");
57286d7f5d3SJohn Marino
57386d7f5d3SJohn Marino if (fix_stderr)
57486d7f5d3SJohn Marino work_around_openssh_glitch ();
57586d7f5d3SJohn Marino
57686d7f5d3SJohn Marino /* Okay to cast out const below - execvp don't return nohow. */
57786d7f5d3SJohn Marino execvp ((char *)command[0], (char **)command);
57886d7f5d3SJohn Marino error (1, errno, "cannot exec %s", command[0]);
57986d7f5d3SJohn Marino }
58086d7f5d3SJohn Marino if (close (to_child_pipe[0]) < 0)
58186d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
58286d7f5d3SJohn Marino if (close (from_child_pipe[1]) < 0)
58386d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
58486d7f5d3SJohn Marino
58586d7f5d3SJohn Marino *tofdp = to_child_pipe[1];
58686d7f5d3SJohn Marino *fromfdp = from_child_pipe[0];
58786d7f5d3SJohn Marino return pid;
58886d7f5d3SJohn Marino }
58986d7f5d3SJohn Marino
59086d7f5d3SJohn Marino
59186d7f5d3SJohn Marino
59286d7f5d3SJohn Marino int
run_piped(int * tofdp,int * fromfdp)59386d7f5d3SJohn Marino run_piped (int *tofdp, int *fromfdp)
59486d7f5d3SJohn Marino {
59586d7f5d3SJohn Marino run_add_arg (NULL);
59686d7f5d3SJohn Marino return piped_child (run_argv, tofdp, fromfdp, false);
59786d7f5d3SJohn Marino }
59886d7f5d3SJohn Marino
59986d7f5d3SJohn Marino
60086d7f5d3SJohn Marino
60186d7f5d3SJohn Marino void
close_on_exec(int fd)60286d7f5d3SJohn Marino close_on_exec (int fd)
60386d7f5d3SJohn Marino {
60486d7f5d3SJohn Marino #ifdef F_SETFD
60586d7f5d3SJohn Marino if (fcntl (fd, F_SETFD, 1) == -1)
60686d7f5d3SJohn Marino error (1, errno, "can't set close-on-exec flag on %d", fd);
60786d7f5d3SJohn Marino #endif
60886d7f5d3SJohn Marino }
609