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