xref: /openbsd/gnu/usr.bin/cvs/src/run.c (revision d415bd75)
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 int run_argc_allocated;
40 
41 /* VARARGS */
42 void
43 run_setup (prog)
44     const char *prog;
45 {
46     char *cp;
47     int i;
48     char *run_prog;
49 
50     /* clean out any malloc'ed values from run_argv */
51     for (i = 0; i < run_argc; i++)
52     {
53 	if (run_argv[i])
54 	{
55 	    free (run_argv[i]);
56 	    run_argv[i] = (char *) 0;
57 	}
58     }
59     run_argc = 0;
60 
61     run_prog = xstrdup (prog);
62 
63     /* put each word into run_argv, allocating it as we go */
64     for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
65 	run_add_arg (cp);
66     free (run_prog);
67 }
68 
69 void
70 run_arg (s)
71     const char *s;
72 {
73     run_add_arg (s);
74 }
75 
76 static void
77 run_add_arg (s)
78     const char *s;
79 {
80     /* allocate more argv entries if we've run out */
81     if (run_argc >= run_argc_allocated)
82     {
83 	run_argc_allocated += 50;
84 	run_argv = (char **) xrealloc ((char *) run_argv,
85 				     run_argc_allocated * sizeof (char **));
86     }
87 
88     if (s)
89 	run_argv[run_argc++] = xstrdup (s);
90     else
91 	run_argv[run_argc] = (char *) 0;	/* not post-incremented on purpose! */
92 }
93 
94 int
95 run_exec (stin, stout, sterr, flags)
96     const char *stin;
97     const char *stout;
98     const char *sterr;
99     int flags;
100 {
101     int shin, shout, sherr;
102     int mode_out, mode_err;
103     int status;
104     int rc = -1;
105     int rerrno = 0;
106     int pid, w;
107 
108 #ifdef POSIX_SIGNALS
109     sigset_t sigset_mask, sigset_omask;
110     struct sigaction act, iact, qact;
111 
112 #else
113 #ifdef BSD_SIGNALS
114     int mask;
115     struct sigvec vec, ivec, qvec;
116 
117 #else
118     RETSIGTYPE (*istat) (), (*qstat) ();
119 #endif
120 #endif
121 
122     if (trace)
123     {
124 #ifdef SERVER_SUPPORT
125 	cvs_outerr (server_active ? "S" : " ", 1);
126 #endif
127 	cvs_outerr ("-> system(", 0);
128 	run_print (stderr);
129 	cvs_outerr (")\n", 0);
130     }
131     if (noexec && (flags & RUN_REALLY) == 0)
132 	return (0);
133 
134     /* make sure that we are null terminated, since we didn't calloc */
135     run_add_arg ((char *) 0);
136 
137     /* setup default file descriptor numbers */
138     shin = 0;
139     shout = 1;
140     sherr = 2;
141 
142     /* set the file modes for stdout and stderr */
143     mode_out = mode_err = O_WRONLY | O_CREAT;
144     mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
145     mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
146 
147     if (stin && (shin = open (stin, O_RDONLY)) == -1)
148     {
149 	rerrno = errno;
150 	error (0, errno, "cannot open %s for reading (prog %s)",
151 	       stin, run_argv[0]);
152 	goto out0;
153     }
154     if (stout && (shout = open (stout, mode_out, 0666)) == -1)
155     {
156 	rerrno = errno;
157 	error (0, errno, "cannot open %s for writing (prog %s)",
158 	       stout, run_argv[0]);
159 	goto out1;
160     }
161     if (sterr && (flags & RUN_COMBINED) == 0)
162     {
163 	if ((sherr = open (sterr, mode_err, 0666)) == -1)
164 	{
165 	    rerrno = errno;
166 	    error (0, errno, "cannot open %s for writing (prog %s)",
167 		   sterr, run_argv[0]);
168 	    goto out2;
169 	}
170     }
171 
172     /* Make sure we don't flush this twice, once in the subprocess.  */
173     fflush (stdout);
174     fflush (stderr);
175 
176     /* The output files, if any, are now created.  Do the fork and dups.
177 
178        We use vfork not so much for a performance boost (the
179        performance boost, if any, is modest on most modern unices),
180        but for the sake of systems without a memory management unit,
181        which find it difficult or impossible to implement fork at all
182        (e.g. Amiga).  The other solution is spawn (see
183        windows-NT/run.c).  */
184 
185 #ifdef HAVE_VFORK
186     pid = vfork ();
187 #else
188     pid = fork ();
189 #endif
190     if (pid == 0)
191     {
192 	if (shin != 0)
193 	{
194 	    (void) dup2 (shin, 0);
195 	    (void) close (shin);
196 	}
197 	if (shout != 1)
198 	{
199 	    (void) dup2 (shout, 1);
200 	    (void) close (shout);
201 	}
202 	if (flags & RUN_COMBINED)
203 	    (void) dup2 (1, 2);
204 	else if (sherr != 2)
205 	{
206 	    (void) dup2 (sherr, 2);
207 	    (void) close (sherr);
208 	}
209 
210 #ifdef SETXID_SUPPORT
211 	/*
212 	** This prevents a user from creating a privileged shell
213 	** from the text editor when the SETXID_SUPPORT option is selected.
214 	*/
215 	if (!strcmp (run_argv[0], Editor) && setegid (getgid ()))
216 	{
217 	    error (0, errno, "cannot set egid to gid");
218 	    _exit (127);
219 	}
220 #endif
221 
222 	/* dup'ing is done.  try to run it now */
223 	(void) execvp (run_argv[0], run_argv);
224 	error (0, errno, "cannot exec %s", run_argv[0]);
225 	_exit (127);
226     }
227     else if (pid == -1)
228     {
229 	rerrno = errno;
230 	goto out;
231     }
232 
233     /* the parent.  Ignore some signals for now */
234 #ifdef POSIX_SIGNALS
235     if (flags & RUN_SIGIGNORE)
236     {
237 	act.sa_handler = SIG_IGN;
238 	(void) sigemptyset (&act.sa_mask);
239 	act.sa_flags = 0;
240 	(void) sigaction (SIGINT, &act, &iact);
241 	(void) sigaction (SIGQUIT, &act, &qact);
242     }
243     else
244     {
245 	(void) sigemptyset (&sigset_mask);
246 	(void) sigaddset (&sigset_mask, SIGINT);
247 	(void) sigaddset (&sigset_mask, SIGQUIT);
248 	(void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
249     }
250 #else
251 #ifdef BSD_SIGNALS
252     if (flags & RUN_SIGIGNORE)
253     {
254 	memset ((char *) &vec, 0, sizeof (vec));
255 	vec.sv_handler = SIG_IGN;
256 	(void) sigvec (SIGINT, &vec, &ivec);
257 	(void) sigvec (SIGQUIT, &vec, &qvec);
258     }
259     else
260 	mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
261 #else
262     istat = signal (SIGINT, SIG_IGN);
263     qstat = signal (SIGQUIT, SIG_IGN);
264 #endif
265 #endif
266 
267     /* wait for our process to die and munge return status */
268 #ifdef POSIX_SIGNALS
269     while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
270 	;
271 #else
272     while ((w = wait (&status)) != pid)
273     {
274 	if (w == -1 && errno != EINTR)
275 	    break;
276     }
277 #endif
278 
279     if (w == -1)
280     {
281 	rc = -1;
282 	rerrno = errno;
283     }
284 #ifndef VMS /* status is return status */
285     else if (WIFEXITED (status))
286 	rc = WEXITSTATUS (status);
287     else if (WIFSIGNALED (status))
288     {
289 	if (WTERMSIG (status) == SIGPIPE)
290 	    error (1, 0, "broken pipe");
291 	rc = 2;
292     }
293     else
294 	rc = 1;
295 #else /* VMS */
296     rc = WEXITSTATUS (status);
297 #endif /* VMS */
298 
299     /* restore the signals */
300 #ifdef POSIX_SIGNALS
301     if (flags & RUN_SIGIGNORE)
302     {
303 	(void) sigaction (SIGINT, &iact, (struct sigaction *) NULL);
304 	(void) sigaction (SIGQUIT, &qact, (struct sigaction *) NULL);
305     }
306     else
307 	(void) sigprocmask (SIG_SETMASK, &sigset_omask, (sigset_t *) NULL);
308 #else
309 #ifdef BSD_SIGNALS
310     if (flags & RUN_SIGIGNORE)
311     {
312 	(void) sigvec (SIGINT, &ivec, (struct sigvec *) NULL);
313 	(void) sigvec (SIGQUIT, &qvec, (struct sigvec *) NULL);
314     }
315     else
316 	(void) sigsetmask (mask);
317 #else
318     (void) signal (SIGINT, istat);
319     (void) signal (SIGQUIT, qstat);
320 #endif
321 #endif
322 
323     /* cleanup the open file descriptors */
324   out:
325     if (sterr)
326 	(void) close (sherr);
327     else
328 	/* ensure things are received by the parent in the correct order
329 	 * relative to the protocol pipe
330 	 */
331 	cvs_flusherr();
332   out2:
333     if (stout)
334 	(void) close (shout);
335     else
336 	/* ensure things are received by the parent in the correct order
337 	 * relative to the protocol pipe
338 	 */
339 	cvs_flushout();
340   out1:
341     if (stin)
342 	(void) close (shin);
343 
344   out0:
345     if (rerrno)
346 	errno = rerrno;
347     return (rc);
348 }
349 
350 void
351 run_print (fp)
352     FILE *fp;
353 {
354     int i;
355     void (*outfn) PROTO ((const char *, size_t));
356 
357     if (fp == stderr)
358 	outfn = cvs_outerr;
359     else if (fp == stdout)
360 	outfn = cvs_output;
361     else
362     {
363 	error (1, 0, "internal error: bad argument to run_print");
364 	/* Solely to placate gcc -Wall.
365 	   FIXME: it'd be better to use a function named `fatal' that
366 	   is known never to return.  Then kludges wouldn't be necessary.  */
367 	outfn = NULL;
368     }
369 
370     for (i = 0; i < run_argc; i++)
371     {
372 	(*outfn) ("'", 1);
373 	(*outfn) (run_argv[i], 0);
374 	(*outfn) ("'", 1);
375 	if (i != run_argc - 1)
376 	    (*outfn) (" ", 1);
377     }
378 }
379 
380 /* Return value is NULL for error, or if noexec was set.  If there was an
381    error, return NULL and I'm not sure whether errno was set (the Red Hat
382    Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec
383    case complicates this even aside from popen behavior).  */
384 
385 FILE *
386 run_popen (cmd, mode)
387     const char *cmd;
388     const char *mode;
389 {
390     if (trace)
391 	(void) fprintf (stderr, "%s-> run_popen(%s,%s)\n",
392 			CLIENT_SERVER_STR, cmd, mode);
393     if (noexec)
394 	return (NULL);
395 
396     return (popen (cmd, mode));
397 }
398 
399 int
400 piped_child (command, tofdp, fromfdp)
401      char **command;
402      int *tofdp;
403      int *fromfdp;
404 {
405     int pid;
406     int to_child_pipe[2];
407     int from_child_pipe[2];
408 
409     if (pipe (to_child_pipe) < 0)
410 	error (1, errno, "cannot create pipe");
411     if (pipe (from_child_pipe) < 0)
412 	error (1, errno, "cannot create pipe");
413 
414 #ifdef USE_SETMODE_BINARY
415     setmode (to_child_pipe[0], O_BINARY);
416     setmode (to_child_pipe[1], O_BINARY);
417     setmode (from_child_pipe[0], O_BINARY);
418     setmode (from_child_pipe[1], O_BINARY);
419 #endif
420 
421 #ifdef HAVE_VFORK
422     pid = vfork ();
423 #else
424     pid = fork ();
425 #endif
426     if (pid < 0)
427 	error (1, errno, "cannot fork");
428     if (pid == 0)
429     {
430 	if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
431 	    error (1, errno, "cannot dup2 pipe");
432 	if (close (to_child_pipe[1]) < 0)
433 	    error (1, errno, "cannot close pipe");
434 	if (close (from_child_pipe[0]) < 0)
435 	    error (1, errno, "cannot close pipe");
436 	if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
437 	    error (1, errno, "cannot dup2 pipe");
438 
439 	execvp (command[0], command);
440 	error (1, errno, "cannot exec %s", command[0]);
441     }
442     if (close (to_child_pipe[0]) < 0)
443 	error (1, errno, "cannot close pipe");
444     if (close (from_child_pipe[1]) < 0)
445 	error (1, errno, "cannot close pipe");
446 
447     *tofdp = to_child_pipe[1];
448     *fromfdp = from_child_pipe[0];
449     return pid;
450 }
451 
452 
453 void
454 close_on_exec (fd)
455      int fd;
456 {
457 #ifdef F_SETFD
458     if (fcntl (fd, F_SETFD, 1))
459 	error (1, errno, "can't set close-on-exec flag on %d", fd);
460 #endif
461 }
462