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