PageRenderTime 75ms CodeModel.GetById 11ms app.highlight 59ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/cvs/src/run.c

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