xref: /openbsd-src/gnu/usr.bin/cvs/src/run.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
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   out2:
328     if (stout)
329 	(void) close (shout);
330   out1:
331     if (stin)
332 	(void) close (shin);
333 
334   out0:
335     if (rerrno)
336 	errno = rerrno;
337     return (rc);
338 }
339 
340 void
341 run_print (fp)
342     FILE *fp;
343 {
344     int i;
345     void (*outfn) PROTO ((const char *, size_t));
346 
347     if (fp == stderr)
348 	outfn = cvs_outerr;
349     else if (fp == stdout)
350 	outfn = cvs_output;
351     else
352     {
353 	error (1, 0, "internal error: bad argument to run_print");
354 	/* Solely to placate gcc -Wall.
355 	   FIXME: it'd be better to use a function named `fatal' that
356 	   is known never to return.  Then kludges wouldn't be necessary.  */
357 	outfn = NULL;
358     }
359 
360     for (i = 0; i < run_argc; i++)
361     {
362 	(*outfn) ("'", 1);
363 	(*outfn) (run_argv[i], 0);
364 	(*outfn) ("'", 1);
365 	if (i != run_argc - 1)
366 	    (*outfn) (" ", 1);
367     }
368 }
369 
370 /* Return value is NULL for error, or if noexec was set.  If there was an
371    error, return NULL and I'm not sure whether errno was set (the Red Hat
372    Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec
373    case complicates this even aside from popen behavior).  */
374 
375 FILE *
376 run_popen (cmd, mode)
377     const char *cmd;
378     const char *mode;
379 {
380     if (trace)
381 	(void) fprintf (stderr, "%s-> run_popen(%s,%s)\n",
382 			CLIENT_SERVER_STR, cmd, mode);
383     if (noexec)
384 	return (NULL);
385 
386     return (popen (cmd, mode));
387 }
388 
389 int
390 piped_child (command, tofdp, fromfdp)
391      char **command;
392      int *tofdp;
393      int *fromfdp;
394 {
395     int pid;
396     int to_child_pipe[2];
397     int from_child_pipe[2];
398 
399     if (pipe (to_child_pipe) < 0)
400 	error (1, errno, "cannot create pipe");
401     if (pipe (from_child_pipe) < 0)
402 	error (1, errno, "cannot create pipe");
403 
404 #ifdef USE_SETMODE_BINARY
405     setmode (to_child_pipe[0], O_BINARY);
406     setmode (to_child_pipe[1], O_BINARY);
407     setmode (from_child_pipe[0], O_BINARY);
408     setmode (from_child_pipe[1], O_BINARY);
409 #endif
410 
411 #ifdef HAVE_VFORK
412     pid = vfork ();
413 #else
414     pid = fork ();
415 #endif
416     if (pid < 0)
417 	error (1, errno, "cannot fork");
418     if (pid == 0)
419     {
420 	if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
421 	    error (1, errno, "cannot dup2 pipe");
422 	if (close (to_child_pipe[1]) < 0)
423 	    error (1, errno, "cannot close pipe");
424 	if (close (from_child_pipe[0]) < 0)
425 	    error (1, errno, "cannot close pipe");
426 	if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
427 	    error (1, errno, "cannot dup2 pipe");
428 
429 	execvp (command[0], command);
430 	error (1, errno, "cannot exec %s", command[0]);
431     }
432     if (close (to_child_pipe[0]) < 0)
433 	error (1, errno, "cannot close pipe");
434     if (close (from_child_pipe[1]) < 0)
435 	error (1, errno, "cannot close pipe");
436 
437     *tofdp = to_child_pipe[1];
438     *fromfdp = from_child_pipe[0];
439     return pid;
440 }
441 
442 
443 void
444 close_on_exec (fd)
445      int fd;
446 {
447 #if defined (FD_CLOEXEC) && defined (F_SETFD)
448     if (fcntl (fd, F_SETFD, 1))
449 	error (1, errno, "can't set close-on-exec flag on %d", fd);
450 #endif
451 }
452