xref: /dflybsd-src/contrib/cvs-1.12/src/run.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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