run.c revision 1.1
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	if (shin != 0)
241	{
242	    (void) dup2 (shin, 0);
243	    (void) close (shin);
244	}
245	if (shout != 1)
246	{
247	    (void) dup2 (shout, 1);
248	    (void) close (shout);
249	}
250	if (flags & RUN_COMBINED)
251	    (void) dup2 (1, 2);
252	else if (sherr != 2)
253	{
254	    (void) dup2 (sherr, 2);
255	    (void) close (sherr);
256	}
257
258#ifdef SETXID_SUPPORT
259	/*
260	** This prevents a user from creating a privileged shell
261	** from the text editor when the SETXID_SUPPORT option is selected.
262	*/
263	if (!strcmp (run_argv[0], Editor) && setegid (getgid ()))
264	{
265	    error (0, errno, "cannot set egid to gid");
266	    _exit (127);
267	}
268#endif
269
270	/* dup'ing is done.  try to run it now */
271	(void) execvp (run_argv[0], run_argv);
272	error (0, errno, "cannot exec %s", run_argv[0]);
273	_exit (127);
274    }
275    else if (pid == -1)
276    {
277	rerrno = errno;
278	goto out;
279    }
280
281    /* the parent.  Ignore some signals for now */
282#ifdef POSIX_SIGNALS
283    if (flags & RUN_SIGIGNORE)
284    {
285	act.sa_handler = SIG_IGN;
286	(void) sigemptyset (&act.sa_mask);
287	act.sa_flags = 0;
288	(void) sigaction (SIGINT, &act, &iact);
289	(void) sigaction (SIGQUIT, &act, &qact);
290    }
291    else
292    {
293	(void) sigemptyset (&sigset_mask);
294	(void) sigaddset (&sigset_mask, SIGINT);
295	(void) sigaddset (&sigset_mask, SIGQUIT);
296	(void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
297    }
298#else
299#ifdef BSD_SIGNALS
300    if (flags & RUN_SIGIGNORE)
301    {
302	memset (&vec, 0, sizeof vec);
303	vec.sv_handler = SIG_IGN;
304	(void) sigvec (SIGINT, &vec, &ivec);
305	(void) sigvec (SIGQUIT, &vec, &qvec);
306    }
307    else
308	mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
309#else
310    istat = signal (SIGINT, SIG_IGN);
311    qstat = signal (SIGQUIT, SIG_IGN);
312#endif
313#endif
314
315    /* wait for our process to die and munge return status */
316#ifdef POSIX_SIGNALS
317    while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
318	;
319#else
320    while ((w = wait (&status)) != pid)
321    {
322	if (w == -1 && errno != EINTR)
323	    break;
324    }
325#endif
326
327    if (w == -1)
328    {
329	rc = -1;
330	rerrno = errno;
331    }
332#ifndef VMS /* status is return status */
333    else if (WIFEXITED (status))
334	rc = WEXITSTATUS (status);
335    else if (WIFSIGNALED (status))
336    {
337	if (WTERMSIG (status) == SIGPIPE)
338	    error (1, 0, "broken pipe");
339	rc = 2;
340    }
341    else
342	rc = 1;
343#else /* VMS */
344    rc = WEXITSTATUS (status);
345#endif /* VMS */
346
347    /* restore the signals */
348#ifdef POSIX_SIGNALS
349    if (flags & RUN_SIGIGNORE)
350    {
351	(void) sigaction (SIGINT, &iact, NULL);
352	(void) sigaction (SIGQUIT, &qact, NULL);
353    }
354    else
355	(void) sigprocmask (SIG_SETMASK, &sigset_omask, NULL);
356#else
357#ifdef BSD_SIGNALS
358    if (flags & RUN_SIGIGNORE)
359    {
360	(void) sigvec (SIGINT, &ivec, NULL);
361	(void) sigvec (SIGQUIT, &qvec, NULL);
362    }
363    else
364	(void) sigsetmask (mask);
365#else
366    (void) signal (SIGINT, istat);
367    (void) signal (SIGQUIT, qstat);
368#endif
369#endif
370
371    /* cleanup the open file descriptors */
372  out:
373    if (sterr)
374	(void) close (sherr);
375    else
376	/* ensure things are received by the parent in the correct order
377	 * relative to the protocol pipe
378	 */
379	cvs_flusherr();
380  out2:
381    if (stout)
382	(void) close (shout);
383    else
384	/* ensure things are received by the parent in the correct order
385	 * relative to the protocol pipe
386	 */
387	cvs_flushout();
388  out1:
389    if (stin)
390	(void) close (shin);
391
392  out0:
393    if (rerrno)
394	errno = rerrno;
395    return rc;
396}
397
398
399
400void
401run_print (FILE *fp)
402{
403    int i;
404    void (*outfn) (const char *, size_t);
405
406    if (fp == stderr)
407	outfn = cvs_outerr;
408    else if (fp == stdout)
409	outfn = cvs_output;
410    else
411    {
412	error (1, 0, "internal error: bad argument to run_print");
413	/* Solely to placate gcc -Wall.
414	   FIXME: it'd be better to use a function named `fatal' that
415	   is known never to return.  Then kludges wouldn't be necessary.  */
416	outfn = NULL;
417    }
418
419    for (i = 0; i < run_argc; i++)
420    {
421	(*outfn) ("'", 1);
422	(*outfn) (run_argv[i], 0);
423	(*outfn) ("'", 1);
424	if (i != run_argc - 1)
425	    (*outfn) (" ", 1);
426    }
427}
428
429
430
431/* Return value is NULL for error, or if noexec was set.  If there was an
432   error, return NULL and I'm not sure whether errno was set (the Red Hat
433   Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec
434   case complicates this even aside from popen behavior).  */
435FILE *
436run_popen (const char *cmd, const char *mode)
437{
438    TRACE (TRACE_FUNCTION, "run_popen (%s,%s)", cmd, mode);
439    if (noexec)
440	return NULL;
441
442    return popen (cmd, mode);
443}
444
445
446
447/* Work around an OpenSSH problem: it can put its standard file
448   descriptors into nonblocking mode, which will mess us up if we
449   share file descriptions with it.  The simplest workaround is
450   to create an intervening process between OpenSSH and the
451   actual stderr.  */
452
453static void
454work_around_openssh_glitch (void)
455{
456    pid_t pid;
457    int stderr_pipe[2];
458    struct stat sb;
459
460    /* Do nothing unless stderr is a file that is affected by
461       nonblocking mode.  */
462    if (!(fstat (STDERR_FILENO, &sb) == 0
463          && (S_ISFIFO (sb.st_mode) || S_ISSOCK (sb.st_mode)
464              || S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode))))
465       return;
466
467    if (pipe (stderr_pipe) < 0)
468       error (1, errno, "cannot create pipe");
469    pid = fork ();
470    if (pid < 0)
471       error (1, errno, "cannot fork");
472    if (pid != 0)
473    {
474       /* Still in child of original process.  Act like "cat -u".  */
475       char buf[1 << 13];
476       ssize_t inbytes;
477       pid_t w;
478       int status;
479
480       if (close (stderr_pipe[1]) < 0)
481           error (1, errno, "cannot close pipe");
482
483       while ((inbytes = read (stderr_pipe[0], buf, sizeof buf)) != 0)
484       {
485           size_t outbytes = 0;
486
487           if (inbytes < 0)
488           {
489               if (errno == EINTR)
490                   continue;
491               error (1, errno, "reading from pipe");
492           }
493
494           do
495           {
496               ssize_t w = write (STDERR_FILENO,
497                                  buf + outbytes, inbytes - outbytes);
498               if (w < 0)
499               {
500                   if (errno == EINTR)
501                     w = 0;
502                   if (w < 0)
503                     _exit (1);
504               }
505               outbytes += w;
506           }
507           while (inbytes != outbytes);
508       }
509
510       /* Done processing output from grandchild.  Propagate
511          its exit status back to the parent.  */
512       while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
513           continue;
514       if (w < 0)
515           error (1, errno, "waiting for child");
516       if (!WIFEXITED (status))
517       {
518           if (WIFSIGNALED (status))
519               raise (WTERMSIG (status));
520           error (1, errno, "child did not exit cleanly");
521       }
522       _exit (WEXITSTATUS (status));
523    }
524
525    /* Grandchild of original process.  */
526    if (close (stderr_pipe[0]) < 0)
527       error (1, errno, "cannot close pipe");
528
529    if (stderr_pipe[1] != STDERR_FILENO)
530    {
531       if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
532           error (1, errno, "cannot dup2 pipe");
533       if (close (stderr_pipe[1]) < 0)
534           error (1, errno, "cannot close pipe");
535    }
536}
537
538
539
540int
541piped_child (char *const *command, int *tofdp, int *fromfdp, bool fix_stderr)
542{
543    int pid;
544    int to_child_pipe[2];
545    int from_child_pipe[2];
546
547    if (pipe (to_child_pipe) < 0)
548	error (1, errno, "cannot create pipe");
549    if (pipe (from_child_pipe) < 0)
550	error (1, errno, "cannot create pipe");
551
552#ifdef USE_SETMODE_BINARY
553    setmode (to_child_pipe[0], O_BINARY);
554    setmode (to_child_pipe[1], O_BINARY);
555    setmode (from_child_pipe[0], O_BINARY);
556    setmode (from_child_pipe[1], O_BINARY);
557#endif
558
559    pid = fork ();
560    if (pid < 0)
561	error (1, errno, "cannot fork");
562    if (pid == 0)
563    {
564	if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
565	    error (1, errno, "cannot dup2 pipe");
566	if (close (to_child_pipe[1]) < 0)
567	    error (1, errno, "cannot close pipe");
568	if (close (from_child_pipe[0]) < 0)
569	    error (1, errno, "cannot close pipe");
570	if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
571	    error (1, errno, "cannot dup2 pipe");
572
573        if (fix_stderr)
574	    work_around_openssh_glitch ();
575
576	/* Okay to cast out const below - execvp don't return nohow.  */
577	execvp ((char *)command[0], (char **)command);
578	error (1, errno, "cannot exec %s", command[0]);
579    }
580    if (close (to_child_pipe[0]) < 0)
581	error (1, errno, "cannot close pipe");
582    if (close (from_child_pipe[1]) < 0)
583	error (1, errno, "cannot close pipe");
584
585    *tofdp = to_child_pipe[1];
586    *fromfdp = from_child_pipe[0];
587    return pid;
588}
589
590
591
592int
593run_piped (int *tofdp, int *fromfdp)
594{
595    run_add_arg (NULL);
596    return piped_child (run_argv, tofdp, fromfdp, false);
597}
598
599
600
601void
602close_on_exec (int fd)
603{
604#ifdef F_SETFD
605    if (fcntl (fd, F_SETFD, 1) == -1)
606	error (1, errno, "can't set close-on-exec flag on %d", fd);
607#endif
608}
609