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