1*86d7f5d3SJohn Marino /* run.c --- routines for executing subprocesses.
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino This file is part of GNU CVS.
4*86d7f5d3SJohn Marino
5*86d7f5d3SJohn Marino GNU CVS is free software; you can redistribute it and/or modify it
6*86d7f5d3SJohn Marino under the terms of the GNU General Public License as published by the
7*86d7f5d3SJohn Marino Free Software Foundation; either version 2, or (at your option) any
8*86d7f5d3SJohn Marino later version.
9*86d7f5d3SJohn Marino
10*86d7f5d3SJohn Marino This program is distributed in the hope that it will be useful,
11*86d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
12*86d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*86d7f5d3SJohn Marino GNU General Public License for more details. */
14*86d7f5d3SJohn Marino
15*86d7f5d3SJohn Marino #include "cvs.h"
16*86d7f5d3SJohn Marino
17*86d7f5d3SJohn Marino #ifndef HAVE_UNISTD_H
18*86d7f5d3SJohn Marino extern int execvp (char *file, char **argv);
19*86d7f5d3SJohn Marino #endif
20*86d7f5d3SJohn Marino
21*86d7f5d3SJohn Marino
22*86d7f5d3SJohn Marino
23*86d7f5d3SJohn Marino /*
24*86d7f5d3SJohn Marino * To exec a program under CVS, first call run_setup() to setup initial
25*86d7f5d3SJohn Marino * arguments. The argument to run_setup will be parsed into whitespace
26*86d7f5d3SJohn Marino * separated words and added to the global run_argv list.
27*86d7f5d3SJohn Marino *
28*86d7f5d3SJohn Marino * Then, optionally call run_add_arg() for each additional argument that you'd
29*86d7f5d3SJohn Marino * like to pass to the executed program.
30*86d7f5d3SJohn Marino *
31*86d7f5d3SJohn Marino * Finally, call run_exec() to execute the program with the specified arguments.
32*86d7f5d3SJohn Marino * The execvp() syscall will be used, so that the PATH is searched correctly.
33*86d7f5d3SJohn Marino * File redirections can be performed in the call to run_exec().
34*86d7f5d3SJohn Marino */
35*86d7f5d3SJohn Marino static char **run_argv;
36*86d7f5d3SJohn Marino static int run_argc;
37*86d7f5d3SJohn Marino static size_t run_arg_allocated;
38*86d7f5d3SJohn Marino
39*86d7f5d3SJohn Marino
40*86d7f5d3SJohn Marino
41*86d7f5d3SJohn Marino void
run_arg_free_p(int argc,char ** argv)42*86d7f5d3SJohn Marino run_arg_free_p (int argc, char **argv)
43*86d7f5d3SJohn Marino {
44*86d7f5d3SJohn Marino int i;
45*86d7f5d3SJohn Marino for (i = 0; i < argc; i++)
46*86d7f5d3SJohn Marino free (argv[i]);
47*86d7f5d3SJohn Marino }
48*86d7f5d3SJohn Marino
49*86d7f5d3SJohn Marino
50*86d7f5d3SJohn Marino
51*86d7f5d3SJohn Marino /* VARARGS */
52*86d7f5d3SJohn Marino void
run_setup(const char * prog)53*86d7f5d3SJohn Marino run_setup (const char *prog)
54*86d7f5d3SJohn Marino {
55*86d7f5d3SJohn Marino char *run_prog;
56*86d7f5d3SJohn Marino char *buf, *d, *s;
57*86d7f5d3SJohn Marino size_t length;
58*86d7f5d3SJohn Marino size_t doff;
59*86d7f5d3SJohn Marino char inquotes;
60*86d7f5d3SJohn Marino int dolastarg;
61*86d7f5d3SJohn Marino
62*86d7f5d3SJohn Marino /* clean out any malloc'ed values from run_argv */
63*86d7f5d3SJohn Marino run_arg_free_p (run_argc, run_argv);
64*86d7f5d3SJohn Marino run_argc = 0;
65*86d7f5d3SJohn Marino
66*86d7f5d3SJohn Marino run_prog = xstrdup (prog);
67*86d7f5d3SJohn Marino
68*86d7f5d3SJohn Marino s = run_prog;
69*86d7f5d3SJohn Marino d = buf = NULL;
70*86d7f5d3SJohn Marino length = 0;
71*86d7f5d3SJohn Marino dolastarg = 1;
72*86d7f5d3SJohn Marino inquotes = '\0';
73*86d7f5d3SJohn Marino doff = d - buf;
74*86d7f5d3SJohn Marino expand_string(&buf, &length, doff + 1);
75*86d7f5d3SJohn Marino d = buf + doff;
76*86d7f5d3SJohn Marino while ((*d = *s++) != '\0')
77*86d7f5d3SJohn Marino {
78*86d7f5d3SJohn Marino switch (*d)
79*86d7f5d3SJohn Marino {
80*86d7f5d3SJohn Marino case '\\':
81*86d7f5d3SJohn Marino if (*s) *d = *s++;
82*86d7f5d3SJohn Marino d++;
83*86d7f5d3SJohn Marino break;
84*86d7f5d3SJohn Marino case '"':
85*86d7f5d3SJohn Marino case '\'':
86*86d7f5d3SJohn Marino if (inquotes == *d) inquotes = '\0';
87*86d7f5d3SJohn Marino else inquotes = *d;
88*86d7f5d3SJohn Marino break;
89*86d7f5d3SJohn Marino case ' ':
90*86d7f5d3SJohn Marino case '\t':
91*86d7f5d3SJohn Marino if (inquotes) d++;
92*86d7f5d3SJohn Marino else
93*86d7f5d3SJohn Marino {
94*86d7f5d3SJohn Marino *d = '\0';
95*86d7f5d3SJohn Marino run_add_arg (buf);
96*86d7f5d3SJohn Marino d = buf;
97*86d7f5d3SJohn Marino while (isspace(*s)) s++;
98*86d7f5d3SJohn Marino if (!*s) dolastarg = 0;
99*86d7f5d3SJohn Marino }
100*86d7f5d3SJohn Marino break;
101*86d7f5d3SJohn Marino default:
102*86d7f5d3SJohn Marino d++;
103*86d7f5d3SJohn Marino break;
104*86d7f5d3SJohn Marino }
105*86d7f5d3SJohn Marino doff = d - buf;
106*86d7f5d3SJohn Marino expand_string(&buf, &length, doff + 1);
107*86d7f5d3SJohn Marino d = buf + doff;
108*86d7f5d3SJohn Marino }
109*86d7f5d3SJohn Marino if (dolastarg) run_add_arg (buf);
110*86d7f5d3SJohn Marino /* put each word into run_argv, allocating it as we go */
111*86d7f5d3SJohn Marino if (buf) free (buf);
112*86d7f5d3SJohn Marino free (run_prog);
113*86d7f5d3SJohn Marino }
114*86d7f5d3SJohn Marino
115*86d7f5d3SJohn Marino
116*86d7f5d3SJohn Marino
117*86d7f5d3SJohn Marino void
run_add_arg_p(int * iargc,size_t * iarg_allocated,char *** iargv,const char * s)118*86d7f5d3SJohn Marino run_add_arg_p (int *iargc, size_t *iarg_allocated, char ***iargv,
119*86d7f5d3SJohn Marino const char *s)
120*86d7f5d3SJohn Marino {
121*86d7f5d3SJohn Marino /* allocate more argv entries if we've run out */
122*86d7f5d3SJohn Marino if (*iargc >= *iarg_allocated)
123*86d7f5d3SJohn Marino {
124*86d7f5d3SJohn Marino *iarg_allocated += 50;
125*86d7f5d3SJohn Marino *iargv = xnrealloc (*iargv, *iarg_allocated, sizeof (char **));
126*86d7f5d3SJohn Marino }
127*86d7f5d3SJohn Marino
128*86d7f5d3SJohn Marino if (s)
129*86d7f5d3SJohn Marino (*iargv)[(*iargc)++] = xstrdup (s);
130*86d7f5d3SJohn Marino else
131*86d7f5d3SJohn Marino (*iargv)[*iargc] = NULL; /* not post-incremented on purpose! */
132*86d7f5d3SJohn Marino }
133*86d7f5d3SJohn Marino
134*86d7f5d3SJohn Marino
135*86d7f5d3SJohn Marino
136*86d7f5d3SJohn Marino void
run_add_arg(const char * s)137*86d7f5d3SJohn Marino run_add_arg (const char *s)
138*86d7f5d3SJohn Marino {
139*86d7f5d3SJohn Marino run_add_arg_p (&run_argc, &run_arg_allocated, &run_argv, s);
140*86d7f5d3SJohn Marino }
141*86d7f5d3SJohn Marino
142*86d7f5d3SJohn Marino
143*86d7f5d3SJohn Marino
144*86d7f5d3SJohn Marino int
run_exec(const char * stin,const char * stout,const char * sterr,int flags)145*86d7f5d3SJohn Marino run_exec (const char *stin, const char *stout, const char *sterr, int flags)
146*86d7f5d3SJohn Marino {
147*86d7f5d3SJohn Marino int shin, shout, sherr;
148*86d7f5d3SJohn Marino int mode_out, mode_err;
149*86d7f5d3SJohn Marino int status;
150*86d7f5d3SJohn Marino int rc = -1;
151*86d7f5d3SJohn Marino int rerrno = 0;
152*86d7f5d3SJohn Marino int pid, w;
153*86d7f5d3SJohn Marino
154*86d7f5d3SJohn Marino #ifdef POSIX_SIGNALS
155*86d7f5d3SJohn Marino sigset_t sigset_mask, sigset_omask;
156*86d7f5d3SJohn Marino struct sigaction act, iact, qact;
157*86d7f5d3SJohn Marino
158*86d7f5d3SJohn Marino #else
159*86d7f5d3SJohn Marino #ifdef BSD_SIGNALS
160*86d7f5d3SJohn Marino int mask;
161*86d7f5d3SJohn Marino struct sigvec vec, ivec, qvec;
162*86d7f5d3SJohn Marino
163*86d7f5d3SJohn Marino #else
164*86d7f5d3SJohn Marino RETSIGTYPE (*istat) (), (*qstat) ();
165*86d7f5d3SJohn Marino #endif
166*86d7f5d3SJohn Marino #endif
167*86d7f5d3SJohn Marino
168*86d7f5d3SJohn Marino if (trace)
169*86d7f5d3SJohn Marino {
170*86d7f5d3SJohn Marino cvs_outerr (
171*86d7f5d3SJohn Marino #ifdef SERVER_SUPPORT
172*86d7f5d3SJohn Marino server_active ? "S" :
173*86d7f5d3SJohn Marino #endif
174*86d7f5d3SJohn Marino " ", 1);
175*86d7f5d3SJohn Marino cvs_outerr (" -> system (", 0);
176*86d7f5d3SJohn Marino run_print (stderr);
177*86d7f5d3SJohn Marino cvs_outerr (")\n", 0);
178*86d7f5d3SJohn Marino }
179*86d7f5d3SJohn Marino if (noexec && (flags & RUN_REALLY) == 0)
180*86d7f5d3SJohn Marino return 0;
181*86d7f5d3SJohn Marino
182*86d7f5d3SJohn Marino /* make sure that we are null terminated, since we didn't calloc */
183*86d7f5d3SJohn Marino run_add_arg (NULL);
184*86d7f5d3SJohn Marino
185*86d7f5d3SJohn Marino /* setup default file descriptor numbers */
186*86d7f5d3SJohn Marino shin = 0;
187*86d7f5d3SJohn Marino shout = 1;
188*86d7f5d3SJohn Marino sherr = 2;
189*86d7f5d3SJohn Marino
190*86d7f5d3SJohn Marino /* set the file modes for stdout and stderr */
191*86d7f5d3SJohn Marino mode_out = mode_err = O_WRONLY | O_CREAT;
192*86d7f5d3SJohn Marino mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
193*86d7f5d3SJohn Marino mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
194*86d7f5d3SJohn Marino
195*86d7f5d3SJohn Marino if (stin && (shin = open (stin, O_RDONLY)) == -1)
196*86d7f5d3SJohn Marino {
197*86d7f5d3SJohn Marino rerrno = errno;
198*86d7f5d3SJohn Marino error (0, errno, "cannot open %s for reading (prog %s)",
199*86d7f5d3SJohn Marino stin, run_argv[0]);
200*86d7f5d3SJohn Marino goto out0;
201*86d7f5d3SJohn Marino }
202*86d7f5d3SJohn Marino if (stout && (shout = open (stout, mode_out, 0666)) == -1)
203*86d7f5d3SJohn Marino {
204*86d7f5d3SJohn Marino rerrno = errno;
205*86d7f5d3SJohn Marino error (0, errno, "cannot open %s for writing (prog %s)",
206*86d7f5d3SJohn Marino stout, run_argv[0]);
207*86d7f5d3SJohn Marino goto out1;
208*86d7f5d3SJohn Marino }
209*86d7f5d3SJohn Marino if (sterr && (flags & RUN_COMBINED) == 0)
210*86d7f5d3SJohn Marino {
211*86d7f5d3SJohn Marino if ((sherr = open (sterr, mode_err, 0666)) == -1)
212*86d7f5d3SJohn Marino {
213*86d7f5d3SJohn Marino rerrno = errno;
214*86d7f5d3SJohn Marino error (0, errno, "cannot open %s for writing (prog %s)",
215*86d7f5d3SJohn Marino sterr, run_argv[0]);
216*86d7f5d3SJohn Marino goto out2;
217*86d7f5d3SJohn Marino }
218*86d7f5d3SJohn Marino }
219*86d7f5d3SJohn Marino
220*86d7f5d3SJohn Marino /* Make sure we don't flush this twice, once in the subprocess. */
221*86d7f5d3SJohn Marino cvs_flushout();
222*86d7f5d3SJohn Marino cvs_flusherr();
223*86d7f5d3SJohn Marino
224*86d7f5d3SJohn Marino /* The output files, if any, are now created. Do the fork and dups.
225*86d7f5d3SJohn Marino
226*86d7f5d3SJohn Marino We use vfork not so much for a performance boost (the
227*86d7f5d3SJohn Marino performance boost, if any, is modest on most modern unices),
228*86d7f5d3SJohn Marino but for the sake of systems without a memory management unit,
229*86d7f5d3SJohn Marino which find it difficult or impossible to implement fork at all
230*86d7f5d3SJohn Marino (e.g. Amiga). The other solution is spawn (see
231*86d7f5d3SJohn Marino windows-NT/run.c). */
232*86d7f5d3SJohn Marino
233*86d7f5d3SJohn Marino #ifdef HAVE_VFORK
234*86d7f5d3SJohn Marino pid = vfork ();
235*86d7f5d3SJohn Marino #else
236*86d7f5d3SJohn Marino pid = fork ();
237*86d7f5d3SJohn Marino #endif
238*86d7f5d3SJohn Marino if (pid == 0)
239*86d7f5d3SJohn Marino {
240*86d7f5d3SJohn Marino if (shin != 0)
241*86d7f5d3SJohn Marino {
242*86d7f5d3SJohn Marino (void) dup2 (shin, 0);
243*86d7f5d3SJohn Marino (void) close (shin);
244*86d7f5d3SJohn Marino }
245*86d7f5d3SJohn Marino if (shout != 1)
246*86d7f5d3SJohn Marino {
247*86d7f5d3SJohn Marino (void) dup2 (shout, 1);
248*86d7f5d3SJohn Marino (void) close (shout);
249*86d7f5d3SJohn Marino }
250*86d7f5d3SJohn Marino if (flags & RUN_COMBINED)
251*86d7f5d3SJohn Marino (void) dup2 (1, 2);
252*86d7f5d3SJohn Marino else if (sherr != 2)
253*86d7f5d3SJohn Marino {
254*86d7f5d3SJohn Marino (void) dup2 (sherr, 2);
255*86d7f5d3SJohn Marino (void) close (sherr);
256*86d7f5d3SJohn Marino }
257*86d7f5d3SJohn Marino
258*86d7f5d3SJohn Marino #ifdef SETXID_SUPPORT
259*86d7f5d3SJohn Marino /*
260*86d7f5d3SJohn Marino ** This prevents a user from creating a privileged shell
261*86d7f5d3SJohn Marino ** from the text editor when the SETXID_SUPPORT option is selected.
262*86d7f5d3SJohn Marino */
263*86d7f5d3SJohn Marino if (!strcmp (run_argv[0], Editor) && setegid (getgid ()))
264*86d7f5d3SJohn Marino {
265*86d7f5d3SJohn Marino error (0, errno, "cannot set egid to gid");
266*86d7f5d3SJohn Marino _exit (127);
267*86d7f5d3SJohn Marino }
268*86d7f5d3SJohn Marino #endif
269*86d7f5d3SJohn Marino
270*86d7f5d3SJohn Marino /* dup'ing is done. try to run it now */
271*86d7f5d3SJohn Marino (void) execvp (run_argv[0], run_argv);
272*86d7f5d3SJohn Marino error (0, errno, "cannot exec %s", run_argv[0]);
273*86d7f5d3SJohn Marino _exit (127);
274*86d7f5d3SJohn Marino }
275*86d7f5d3SJohn Marino else if (pid == -1)
276*86d7f5d3SJohn Marino {
277*86d7f5d3SJohn Marino rerrno = errno;
278*86d7f5d3SJohn Marino goto out;
279*86d7f5d3SJohn Marino }
280*86d7f5d3SJohn Marino
281*86d7f5d3SJohn Marino /* the parent. Ignore some signals for now */
282*86d7f5d3SJohn Marino #ifdef POSIX_SIGNALS
283*86d7f5d3SJohn Marino if (flags & RUN_SIGIGNORE)
284*86d7f5d3SJohn Marino {
285*86d7f5d3SJohn Marino act.sa_handler = SIG_IGN;
286*86d7f5d3SJohn Marino (void) sigemptyset (&act.sa_mask);
287*86d7f5d3SJohn Marino act.sa_flags = 0;
288*86d7f5d3SJohn Marino (void) sigaction (SIGINT, &act, &iact);
289*86d7f5d3SJohn Marino (void) sigaction (SIGQUIT, &act, &qact);
290*86d7f5d3SJohn Marino }
291*86d7f5d3SJohn Marino else
292*86d7f5d3SJohn Marino {
293*86d7f5d3SJohn Marino (void) sigemptyset (&sigset_mask);
294*86d7f5d3SJohn Marino (void) sigaddset (&sigset_mask, SIGINT);
295*86d7f5d3SJohn Marino (void) sigaddset (&sigset_mask, SIGQUIT);
296*86d7f5d3SJohn Marino (void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
297*86d7f5d3SJohn Marino }
298*86d7f5d3SJohn Marino #else
299*86d7f5d3SJohn Marino #ifdef BSD_SIGNALS
300*86d7f5d3SJohn Marino if (flags & RUN_SIGIGNORE)
301*86d7f5d3SJohn Marino {
302*86d7f5d3SJohn Marino memset (&vec, 0, sizeof vec);
303*86d7f5d3SJohn Marino vec.sv_handler = SIG_IGN;
304*86d7f5d3SJohn Marino (void) sigvec (SIGINT, &vec, &ivec);
305*86d7f5d3SJohn Marino (void) sigvec (SIGQUIT, &vec, &qvec);
306*86d7f5d3SJohn Marino }
307*86d7f5d3SJohn Marino else
308*86d7f5d3SJohn Marino mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
309*86d7f5d3SJohn Marino #else
310*86d7f5d3SJohn Marino istat = signal (SIGINT, SIG_IGN);
311*86d7f5d3SJohn Marino qstat = signal (SIGQUIT, SIG_IGN);
312*86d7f5d3SJohn Marino #endif
313*86d7f5d3SJohn Marino #endif
314*86d7f5d3SJohn Marino
315*86d7f5d3SJohn Marino /* wait for our process to die and munge return status */
316*86d7f5d3SJohn Marino #ifdef POSIX_SIGNALS
317*86d7f5d3SJohn Marino while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
318*86d7f5d3SJohn Marino ;
319*86d7f5d3SJohn Marino #else
320*86d7f5d3SJohn Marino while ((w = wait (&status)) != pid)
321*86d7f5d3SJohn Marino {
322*86d7f5d3SJohn Marino if (w == -1 && errno != EINTR)
323*86d7f5d3SJohn Marino break;
324*86d7f5d3SJohn Marino }
325*86d7f5d3SJohn Marino #endif
326*86d7f5d3SJohn Marino
327*86d7f5d3SJohn Marino if (w == -1)
328*86d7f5d3SJohn Marino {
329*86d7f5d3SJohn Marino rc = -1;
330*86d7f5d3SJohn Marino rerrno = errno;
331*86d7f5d3SJohn Marino }
332*86d7f5d3SJohn Marino #ifndef VMS /* status is return status */
333*86d7f5d3SJohn Marino else if (WIFEXITED (status))
334*86d7f5d3SJohn Marino rc = WEXITSTATUS (status);
335*86d7f5d3SJohn Marino else if (WIFSIGNALED (status))
336*86d7f5d3SJohn Marino {
337*86d7f5d3SJohn Marino if (WTERMSIG (status) == SIGPIPE)
338*86d7f5d3SJohn Marino error (1, 0, "broken pipe");
339*86d7f5d3SJohn Marino rc = 2;
340*86d7f5d3SJohn Marino }
341*86d7f5d3SJohn Marino else
342*86d7f5d3SJohn Marino rc = 1;
343*86d7f5d3SJohn Marino #else /* VMS */
344*86d7f5d3SJohn Marino rc = WEXITSTATUS (status);
345*86d7f5d3SJohn Marino #endif /* VMS */
346*86d7f5d3SJohn Marino
347*86d7f5d3SJohn Marino /* restore the signals */
348*86d7f5d3SJohn Marino #ifdef POSIX_SIGNALS
349*86d7f5d3SJohn Marino if (flags & RUN_SIGIGNORE)
350*86d7f5d3SJohn Marino {
351*86d7f5d3SJohn Marino (void) sigaction (SIGINT, &iact, NULL);
352*86d7f5d3SJohn Marino (void) sigaction (SIGQUIT, &qact, NULL);
353*86d7f5d3SJohn Marino }
354*86d7f5d3SJohn Marino else
355*86d7f5d3SJohn Marino (void) sigprocmask (SIG_SETMASK, &sigset_omask, NULL);
356*86d7f5d3SJohn Marino #else
357*86d7f5d3SJohn Marino #ifdef BSD_SIGNALS
358*86d7f5d3SJohn Marino if (flags & RUN_SIGIGNORE)
359*86d7f5d3SJohn Marino {
360*86d7f5d3SJohn Marino (void) sigvec (SIGINT, &ivec, NULL);
361*86d7f5d3SJohn Marino (void) sigvec (SIGQUIT, &qvec, NULL);
362*86d7f5d3SJohn Marino }
363*86d7f5d3SJohn Marino else
364*86d7f5d3SJohn Marino (void) sigsetmask (mask);
365*86d7f5d3SJohn Marino #else
366*86d7f5d3SJohn Marino (void) signal (SIGINT, istat);
367*86d7f5d3SJohn Marino (void) signal (SIGQUIT, qstat);
368*86d7f5d3SJohn Marino #endif
369*86d7f5d3SJohn Marino #endif
370*86d7f5d3SJohn Marino
371*86d7f5d3SJohn Marino /* cleanup the open file descriptors */
372*86d7f5d3SJohn Marino out:
373*86d7f5d3SJohn Marino if (sterr)
374*86d7f5d3SJohn Marino (void) close (sherr);
375*86d7f5d3SJohn Marino else
376*86d7f5d3SJohn Marino /* ensure things are received by the parent in the correct order
377*86d7f5d3SJohn Marino * relative to the protocol pipe
378*86d7f5d3SJohn Marino */
379*86d7f5d3SJohn Marino cvs_flusherr();
380*86d7f5d3SJohn Marino out2:
381*86d7f5d3SJohn Marino if (stout)
382*86d7f5d3SJohn Marino (void) close (shout);
383*86d7f5d3SJohn Marino else
384*86d7f5d3SJohn Marino /* ensure things are received by the parent in the correct order
385*86d7f5d3SJohn Marino * relative to the protocol pipe
386*86d7f5d3SJohn Marino */
387*86d7f5d3SJohn Marino cvs_flushout();
388*86d7f5d3SJohn Marino out1:
389*86d7f5d3SJohn Marino if (stin)
390*86d7f5d3SJohn Marino (void) close (shin);
391*86d7f5d3SJohn Marino
392*86d7f5d3SJohn Marino out0:
393*86d7f5d3SJohn Marino if (rerrno)
394*86d7f5d3SJohn Marino errno = rerrno;
395*86d7f5d3SJohn Marino return rc;
396*86d7f5d3SJohn Marino }
397*86d7f5d3SJohn Marino
398*86d7f5d3SJohn Marino
399*86d7f5d3SJohn Marino
400*86d7f5d3SJohn Marino void
run_print(FILE * fp)401*86d7f5d3SJohn Marino run_print (FILE *fp)
402*86d7f5d3SJohn Marino {
403*86d7f5d3SJohn Marino int i;
404*86d7f5d3SJohn Marino void (*outfn) (const char *, size_t);
405*86d7f5d3SJohn Marino
406*86d7f5d3SJohn Marino if (fp == stderr)
407*86d7f5d3SJohn Marino outfn = cvs_outerr;
408*86d7f5d3SJohn Marino else if (fp == stdout)
409*86d7f5d3SJohn Marino outfn = cvs_output;
410*86d7f5d3SJohn Marino else
411*86d7f5d3SJohn Marino {
412*86d7f5d3SJohn Marino error (1, 0, "internal error: bad argument to run_print");
413*86d7f5d3SJohn Marino /* Solely to placate gcc -Wall.
414*86d7f5d3SJohn Marino FIXME: it'd be better to use a function named `fatal' that
415*86d7f5d3SJohn Marino is known never to return. Then kludges wouldn't be necessary. */
416*86d7f5d3SJohn Marino outfn = NULL;
417*86d7f5d3SJohn Marino }
418*86d7f5d3SJohn Marino
419*86d7f5d3SJohn Marino for (i = 0; i < run_argc; i++)
420*86d7f5d3SJohn Marino {
421*86d7f5d3SJohn Marino (*outfn) ("'", 1);
422*86d7f5d3SJohn Marino (*outfn) (run_argv[i], 0);
423*86d7f5d3SJohn Marino (*outfn) ("'", 1);
424*86d7f5d3SJohn Marino if (i != run_argc - 1)
425*86d7f5d3SJohn Marino (*outfn) (" ", 1);
426*86d7f5d3SJohn Marino }
427*86d7f5d3SJohn Marino }
428*86d7f5d3SJohn Marino
429*86d7f5d3SJohn Marino
430*86d7f5d3SJohn Marino
431*86d7f5d3SJohn Marino /* Return value is NULL for error, or if noexec was set. If there was an
432*86d7f5d3SJohn Marino error, return NULL and I'm not sure whether errno was set (the Red Hat
433*86d7f5d3SJohn Marino Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec
434*86d7f5d3SJohn Marino case complicates this even aside from popen behavior). */
435*86d7f5d3SJohn Marino FILE *
run_popen(const char * cmd,const char * mode)436*86d7f5d3SJohn Marino run_popen (const char *cmd, const char *mode)
437*86d7f5d3SJohn Marino {
438*86d7f5d3SJohn Marino TRACE (TRACE_FUNCTION, "run_popen (%s,%s)", cmd, mode);
439*86d7f5d3SJohn Marino if (noexec)
440*86d7f5d3SJohn Marino return NULL;
441*86d7f5d3SJohn Marino
442*86d7f5d3SJohn Marino return popen (cmd, mode);
443*86d7f5d3SJohn Marino }
444*86d7f5d3SJohn Marino
445*86d7f5d3SJohn Marino
446*86d7f5d3SJohn Marino
447*86d7f5d3SJohn Marino /* Work around an OpenSSH problem: it can put its standard file
448*86d7f5d3SJohn Marino descriptors into nonblocking mode, which will mess us up if we
449*86d7f5d3SJohn Marino share file descriptions with it. The simplest workaround is
450*86d7f5d3SJohn Marino to create an intervening process between OpenSSH and the
451*86d7f5d3SJohn Marino actual stderr. */
452*86d7f5d3SJohn Marino
453*86d7f5d3SJohn Marino static void
work_around_openssh_glitch(void)454*86d7f5d3SJohn Marino work_around_openssh_glitch (void)
455*86d7f5d3SJohn Marino {
456*86d7f5d3SJohn Marino pid_t pid;
457*86d7f5d3SJohn Marino int stderr_pipe[2];
458*86d7f5d3SJohn Marino struct stat sb;
459*86d7f5d3SJohn Marino
460*86d7f5d3SJohn Marino /* Do nothing unless stderr is a file that is affected by
461*86d7f5d3SJohn Marino nonblocking mode. */
462*86d7f5d3SJohn Marino if (!(fstat (STDERR_FILENO, &sb) == 0
463*86d7f5d3SJohn Marino && (S_ISFIFO (sb.st_mode) || S_ISSOCK (sb.st_mode)
464*86d7f5d3SJohn Marino || S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode))))
465*86d7f5d3SJohn Marino return;
466*86d7f5d3SJohn Marino
467*86d7f5d3SJohn Marino if (pipe (stderr_pipe) < 0)
468*86d7f5d3SJohn Marino error (1, errno, "cannot create pipe");
469*86d7f5d3SJohn Marino pid = fork ();
470*86d7f5d3SJohn Marino if (pid < 0)
471*86d7f5d3SJohn Marino error (1, errno, "cannot fork");
472*86d7f5d3SJohn Marino if (pid != 0)
473*86d7f5d3SJohn Marino {
474*86d7f5d3SJohn Marino /* Still in child of original process. Act like "cat -u". */
475*86d7f5d3SJohn Marino char buf[1 << 13];
476*86d7f5d3SJohn Marino ssize_t inbytes;
477*86d7f5d3SJohn Marino pid_t w;
478*86d7f5d3SJohn Marino int status;
479*86d7f5d3SJohn Marino
480*86d7f5d3SJohn Marino if (close (stderr_pipe[1]) < 0)
481*86d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
482*86d7f5d3SJohn Marino
483*86d7f5d3SJohn Marino while ((inbytes = read (stderr_pipe[0], buf, sizeof buf)) != 0)
484*86d7f5d3SJohn Marino {
485*86d7f5d3SJohn Marino size_t outbytes = 0;
486*86d7f5d3SJohn Marino
487*86d7f5d3SJohn Marino if (inbytes < 0)
488*86d7f5d3SJohn Marino {
489*86d7f5d3SJohn Marino if (errno == EINTR)
490*86d7f5d3SJohn Marino continue;
491*86d7f5d3SJohn Marino error (1, errno, "reading from pipe");
492*86d7f5d3SJohn Marino }
493*86d7f5d3SJohn Marino
494*86d7f5d3SJohn Marino do
495*86d7f5d3SJohn Marino {
496*86d7f5d3SJohn Marino ssize_t w = write (STDERR_FILENO,
497*86d7f5d3SJohn Marino buf + outbytes, inbytes - outbytes);
498*86d7f5d3SJohn Marino if (w < 0)
499*86d7f5d3SJohn Marino {
500*86d7f5d3SJohn Marino if (errno == EINTR)
501*86d7f5d3SJohn Marino w = 0;
502*86d7f5d3SJohn Marino if (w < 0)
503*86d7f5d3SJohn Marino _exit (1);
504*86d7f5d3SJohn Marino }
505*86d7f5d3SJohn Marino outbytes += w;
506*86d7f5d3SJohn Marino }
507*86d7f5d3SJohn Marino while (inbytes != outbytes);
508*86d7f5d3SJohn Marino }
509*86d7f5d3SJohn Marino
510*86d7f5d3SJohn Marino /* Done processing output from grandchild. Propagate
511*86d7f5d3SJohn Marino its exit status back to the parent. */
512*86d7f5d3SJohn Marino while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
513*86d7f5d3SJohn Marino continue;
514*86d7f5d3SJohn Marino if (w < 0)
515*86d7f5d3SJohn Marino error (1, errno, "waiting for child");
516*86d7f5d3SJohn Marino if (!WIFEXITED (status))
517*86d7f5d3SJohn Marino {
518*86d7f5d3SJohn Marino if (WIFSIGNALED (status))
519*86d7f5d3SJohn Marino raise (WTERMSIG (status));
520*86d7f5d3SJohn Marino error (1, errno, "child did not exit cleanly");
521*86d7f5d3SJohn Marino }
522*86d7f5d3SJohn Marino _exit (WEXITSTATUS (status));
523*86d7f5d3SJohn Marino }
524*86d7f5d3SJohn Marino
525*86d7f5d3SJohn Marino /* Grandchild of original process. */
526*86d7f5d3SJohn Marino if (close (stderr_pipe[0]) < 0)
527*86d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
528*86d7f5d3SJohn Marino
529*86d7f5d3SJohn Marino if (stderr_pipe[1] != STDERR_FILENO)
530*86d7f5d3SJohn Marino {
531*86d7f5d3SJohn Marino if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
532*86d7f5d3SJohn Marino error (1, errno, "cannot dup2 pipe");
533*86d7f5d3SJohn Marino if (close (stderr_pipe[1]) < 0)
534*86d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
535*86d7f5d3SJohn Marino }
536*86d7f5d3SJohn Marino }
537*86d7f5d3SJohn Marino
538*86d7f5d3SJohn Marino
539*86d7f5d3SJohn Marino
540*86d7f5d3SJohn Marino int
piped_child(char * const * command,int * tofdp,int * fromfdp,bool fix_stderr)541*86d7f5d3SJohn Marino piped_child (char *const *command, int *tofdp, int *fromfdp, bool fix_stderr)
542*86d7f5d3SJohn Marino {
543*86d7f5d3SJohn Marino int pid;
544*86d7f5d3SJohn Marino int to_child_pipe[2];
545*86d7f5d3SJohn Marino int from_child_pipe[2];
546*86d7f5d3SJohn Marino
547*86d7f5d3SJohn Marino if (pipe (to_child_pipe) < 0)
548*86d7f5d3SJohn Marino error (1, errno, "cannot create pipe");
549*86d7f5d3SJohn Marino if (pipe (from_child_pipe) < 0)
550*86d7f5d3SJohn Marino error (1, errno, "cannot create pipe");
551*86d7f5d3SJohn Marino
552*86d7f5d3SJohn Marino #ifdef USE_SETMODE_BINARY
553*86d7f5d3SJohn Marino setmode (to_child_pipe[0], O_BINARY);
554*86d7f5d3SJohn Marino setmode (to_child_pipe[1], O_BINARY);
555*86d7f5d3SJohn Marino setmode (from_child_pipe[0], O_BINARY);
556*86d7f5d3SJohn Marino setmode (from_child_pipe[1], O_BINARY);
557*86d7f5d3SJohn Marino #endif
558*86d7f5d3SJohn Marino
559*86d7f5d3SJohn Marino pid = fork ();
560*86d7f5d3SJohn Marino if (pid < 0)
561*86d7f5d3SJohn Marino error (1, errno, "cannot fork");
562*86d7f5d3SJohn Marino if (pid == 0)
563*86d7f5d3SJohn Marino {
564*86d7f5d3SJohn Marino if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
565*86d7f5d3SJohn Marino error (1, errno, "cannot dup2 pipe");
566*86d7f5d3SJohn Marino if (close (to_child_pipe[1]) < 0)
567*86d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
568*86d7f5d3SJohn Marino if (close (from_child_pipe[0]) < 0)
569*86d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
570*86d7f5d3SJohn Marino if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
571*86d7f5d3SJohn Marino error (1, errno, "cannot dup2 pipe");
572*86d7f5d3SJohn Marino
573*86d7f5d3SJohn Marino if (fix_stderr)
574*86d7f5d3SJohn Marino work_around_openssh_glitch ();
575*86d7f5d3SJohn Marino
576*86d7f5d3SJohn Marino /* Okay to cast out const below - execvp don't return nohow. */
577*86d7f5d3SJohn Marino execvp ((char *)command[0], (char **)command);
578*86d7f5d3SJohn Marino error (1, errno, "cannot exec %s", command[0]);
579*86d7f5d3SJohn Marino }
580*86d7f5d3SJohn Marino if (close (to_child_pipe[0]) < 0)
581*86d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
582*86d7f5d3SJohn Marino if (close (from_child_pipe[1]) < 0)
583*86d7f5d3SJohn Marino error (1, errno, "cannot close pipe");
584*86d7f5d3SJohn Marino
585*86d7f5d3SJohn Marino *tofdp = to_child_pipe[1];
586*86d7f5d3SJohn Marino *fromfdp = from_child_pipe[0];
587*86d7f5d3SJohn Marino return pid;
588*86d7f5d3SJohn Marino }
589*86d7f5d3SJohn Marino
590*86d7f5d3SJohn Marino
591*86d7f5d3SJohn Marino
592*86d7f5d3SJohn Marino int
run_piped(int * tofdp,int * fromfdp)593*86d7f5d3SJohn Marino run_piped (int *tofdp, int *fromfdp)
594*86d7f5d3SJohn Marino {
595*86d7f5d3SJohn Marino run_add_arg (NULL);
596*86d7f5d3SJohn Marino return piped_child (run_argv, tofdp, fromfdp, false);
597*86d7f5d3SJohn Marino }
598*86d7f5d3SJohn Marino
599*86d7f5d3SJohn Marino
600*86d7f5d3SJohn Marino
601*86d7f5d3SJohn Marino void
close_on_exec(int fd)602*86d7f5d3SJohn Marino close_on_exec (int fd)
603*86d7f5d3SJohn Marino {
604*86d7f5d3SJohn Marino #ifdef F_SETFD
605*86d7f5d3SJohn Marino if (fcntl (fd, F_SETFD, 1) == -1)
606*86d7f5d3SJohn Marino error (1, errno, "can't set close-on-exec flag on %d", fd);
607*86d7f5d3SJohn Marino #endif
608*86d7f5d3SJohn Marino }
609