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