xref: /netbsd-src/external/gpl2/xcvs/dist/src/run.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
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
18 extern 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  */
35 static char **run_argv;
36 static int run_argc;
37 static size_t run_arg_allocated;
38 
39 
40 
41 void
42 run_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 */
52 void
53 run_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 
117 void
118 run_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 
136 void
137 run_add_arg (const char *s)
138 {
139     run_add_arg_p (&run_argc, &run_arg_allocated, &run_argv, s);
140 }
141 
142 
143 
144 int
145 run_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 
407 void
408 run_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).  */
442 FILE *
443 run_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 
460 static void
461 work_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 
547 int
548 piped_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 
599 int
600 run_piped (int *tofdp, int *fromfdp)
601 {
602     run_add_arg (NULL);
603     return piped_child (run_argv, tofdp, fromfdp, false);
604 }
605 
606 
607 
608 void
609 close_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