]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/cvs/src/run.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / cvs / src / run.c
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 PROTO((char *file, char **argv));
19 #endif
20
21 static void run_add_arg PROTO((const char *s));
22
23 extern 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  */
37 static char **run_argv;
38 static int run_argc;
39 static size_t run_argc_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 (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
73 void
74 run_arg (s)
75     const char *s;
76 {
77     run_add_arg (s);
78 }
79
80
81
82 void
83 run_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
104 static void
105 run_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
113 int
114 run_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
371 void
372 run_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
406 FILE *
407 run_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
428 static void
429 work_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
515 int
516 piped_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
570 void
571 close_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 }