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