1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                  David Korn <dgk@research.att.com>                   *
19*4887Schin *                   Phong Vo <kpv@research.att.com>                    *
20*4887Schin *                                                                      *
21*4887Schin ***********************************************************************/
22*4887Schin #pragma prototyped
23*4887Schin /*
24*4887Schin  * Glenn Fowler
25*4887Schin  * AT&T Research
26*4887Schin  *
27*4887Schin  * common process execution support with
28*4887Schin  * proper sfio, signal and wait() syncronization
29*4887Schin  *
30*4887Schin  * _ contains the process path name and is
31*4887Schin  * placed at the top of the environment
32*4887Schin  */
33*4887Schin 
34*4887Schin #include "proclib.h"
35*4887Schin 
36*4887Schin #include <ls.h>
37*4887Schin 
38*4887Schin /*
39*4887Schin  * not quite ready for _use_spawnveg
40*4887Schin  */
41*4887Schin 
42*4887Schin #if _use_spawnveg && _lib_fork
43*4887Schin #undef	_use_spawnveg
44*4887Schin #endif
45*4887Schin 
46*4887Schin #ifndef DEBUG_PROC
47*4887Schin #define DEBUG_PROC	1
48*4887Schin #endif
49*4887Schin 
50*4887Schin #if _lib_socketpair
51*4887Schin #if _sys_socket
52*4887Schin #include <sys/types.h>
53*4887Schin #include <sys/socket.h>
54*4887Schin #else
55*4887Schin #undef	_lib_socketpair
56*4887Schin #endif
57*4887Schin #endif
58*4887Schin 
59*4887Schin Proc_t			proc_default = { -1 };
60*4887Schin 
61*4887Schin #if DEBUG_PROC
62*4887Schin 
63*4887Schin #include <namval.h>
64*4887Schin 
65*4887Schin #define PROC_ENV_OPTIONS	"PROC_OPTIONS"
66*4887Schin 
67*4887Schin #define PROC_OPT_ENVIRONMENT	(1<<0)
68*4887Schin #define PROC_OPT_EXEC		(1<<1)
69*4887Schin #define PROC_OPT_TRACE		(1<<2)
70*4887Schin #define PROC_OPT_VERBOSE	(1<<3)
71*4887Schin 
72*4887Schin static const Namval_t		options[] =
73*4887Schin {
74*4887Schin 	"debug",	PROC_OPT_VERBOSE,
75*4887Schin 	"environment",	PROC_OPT_ENVIRONMENT,
76*4887Schin 	"exec",		PROC_OPT_EXEC,
77*4887Schin 	"trace",	PROC_OPT_TRACE,
78*4887Schin 	"verbose",	PROC_OPT_VERBOSE,
79*4887Schin 	0,		0
80*4887Schin };
81*4887Schin 
82*4887Schin /*
83*4887Schin  * called by stropt() to set options
84*4887Schin  */
85*4887Schin 
86*4887Schin static int
87*4887Schin setopt(register void* a, register const void* p, register int n, const char* v)
88*4887Schin {
89*4887Schin 	NoP(v);
90*4887Schin 	if (p)
91*4887Schin 	{
92*4887Schin 		if (n)
93*4887Schin 			*((int*)a) |= ((Namval_t*)p)->value;
94*4887Schin 		else
95*4887Schin 			*((int*)a) &= ~((Namval_t*)p)->value;
96*4887Schin 	}
97*4887Schin 	return 0;
98*4887Schin }
99*4887Schin 
100*4887Schin #endif
101*4887Schin 
102*4887Schin #if _use_spawnveg
103*4887Schin 
104*4887Schin typedef struct Fd_s
105*4887Schin {
106*4887Schin 	short		fd;
107*4887Schin 	short		flag;
108*4887Schin } Fd_t;
109*4887Schin 
110*4887Schin typedef struct Mod_s
111*4887Schin {
112*4887Schin 	struct Mod_s*	next;
113*4887Schin 	short		op;
114*4887Schin 	short		save;
115*4887Schin 
116*4887Schin 	union
117*4887Schin 	{
118*4887Schin 
119*4887Schin 	struct
120*4887Schin 	{
121*4887Schin 	Fd_t		parent;
122*4887Schin 	Fd_t		child;
123*4887Schin 	}		fd;
124*4887Schin 
125*4887Schin 	Handler_t	handler;
126*4887Schin 
127*4887Schin 	}		arg;
128*4887Schin 
129*4887Schin } Modify_t;
130*4887Schin 
131*4887Schin #endif
132*4887Schin 
133*4887Schin #ifdef SIGPIPE
134*4887Schin 
135*4887Schin /*
136*4887Schin  * catch but ignore sig
137*4887Schin  * avoids SIG_IGN being passed to children
138*4887Schin  */
139*4887Schin 
140*4887Schin static void
141*4887Schin ignoresig(int sig)
142*4887Schin {
143*4887Schin 	signal(sig, ignoresig);
144*4887Schin }
145*4887Schin 
146*4887Schin #endif
147*4887Schin 
148*4887Schin /*
149*4887Schin  * do modification op and save previous state for restore()
150*4887Schin  */
151*4887Schin 
152*4887Schin static int
153*4887Schin modify(Proc_t* proc, int forked, int op, long arg1, long arg2)
154*4887Schin {
155*4887Schin #if _lib_fork
156*4887Schin 	if (forked)
157*4887Schin 	{
158*4887Schin 		switch (op)
159*4887Schin 		{
160*4887Schin 		case PROC_fd_dup:
161*4887Schin 		case PROC_fd_dup|PROC_FD_PARENT:
162*4887Schin 		case PROC_fd_dup|PROC_FD_CHILD:
163*4887Schin 		case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
164*4887Schin 			if (arg1 != arg2)
165*4887Schin 			{
166*4887Schin 				if (arg2 != PROC_ARG_NULL)
167*4887Schin 				{
168*4887Schin 					close(arg2);
169*4887Schin 					if (fcntl(arg1, F_DUPFD, arg2) != arg2)
170*4887Schin 						return -1;
171*4887Schin 				}
172*4887Schin 				if (op & PROC_FD_CHILD)
173*4887Schin 					close(arg1);
174*4887Schin 			}
175*4887Schin 			break;
176*4887Schin 		case PROC_sig_dfl:
177*4887Schin 			signal(arg1, SIG_DFL);
178*4887Schin 			break;
179*4887Schin 		case PROC_sig_ign:
180*4887Schin 			signal(arg1, SIG_IGN);
181*4887Schin 			break;
182*4887Schin 		case PROC_sys_pgrp:
183*4887Schin 			if (arg1 < 0)
184*4887Schin 				setsid();
185*4887Schin 			else if (arg1 > 0)
186*4887Schin 			{
187*4887Schin 				if (arg1 == 1)
188*4887Schin 					arg1 = 0;
189*4887Schin 				if (setpgid(0, arg1) < 0 && arg1 && errno == EPERM)
190*4887Schin 					setpgid(0, 0);
191*4887Schin 			}
192*4887Schin 			break;
193*4887Schin 		case PROC_sys_umask:
194*4887Schin 			umask(arg1);
195*4887Schin 			break;
196*4887Schin 		default:
197*4887Schin 			return -1;
198*4887Schin 		}
199*4887Schin 	}
200*4887Schin #if _use_spawnveg
201*4887Schin 	else
202*4887Schin #endif
203*4887Schin #else
204*4887Schin 	NoP(forked);
205*4887Schin #endif
206*4887Schin #if _use_spawnveg
207*4887Schin 	{
208*4887Schin 		register Modify_t*	m;
209*4887Schin 
210*4887Schin 		if (!(m = newof(NiL, Modify_t, 1, 0)))
211*4887Schin 			return -1;
212*4887Schin 		m->next = proc->mods;
213*4887Schin 		proc->mods = m;
214*4887Schin 		switch (m->op = op)
215*4887Schin 		{
216*4887Schin 		case PROC_fd_dup:
217*4887Schin 		case PROC_fd_dup|PROC_FD_PARENT:
218*4887Schin 		case PROC_fd_dup|PROC_FD_CHILD:
219*4887Schin 		case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
220*4887Schin 			m->arg.fd.parent.fd = (short)arg1;
221*4887Schin 			m->arg.fd.parent.flag = fcntl(arg1, F_GETFD, 0);
222*4887Schin 			if ((m->arg.fd.child.fd = (short)arg2) != arg1)
223*4887Schin 			{
224*4887Schin 				if (arg2 != PROC_ARG_NULL)
225*4887Schin 				{
226*4887Schin 					m->arg.fd.child.flag = fcntl(arg2, F_GETFD, 0);
227*4887Schin 					if ((m->save = fcntl(arg2, F_DUPFD, 3)) < 0)
228*4887Schin 					{
229*4887Schin 						m->op = 0;
230*4887Schin 						return -1;
231*4887Schin 					}
232*4887Schin 					fcntl(m->save, F_SETFD, FD_CLOEXEC);
233*4887Schin 					close(arg2);
234*4887Schin 					if (fcntl(arg1, F_DUPFD, arg2) != arg2)
235*4887Schin 						return -1;
236*4887Schin 					if (op & PROC_FD_CHILD)
237*4887Schin 						close(arg1);
238*4887Schin 				}
239*4887Schin 				else if (op & PROC_FD_CHILD)
240*4887Schin 				{
241*4887Schin 					if (m->arg.fd.parent.flag)
242*4887Schin 						break;
243*4887Schin 					fcntl(arg1, F_SETFD, FD_CLOEXEC);
244*4887Schin 				}
245*4887Schin 				else if (!m->arg.fd.parent.flag)
246*4887Schin 					break;
247*4887Schin 				else
248*4887Schin 					fcntl(arg1, F_SETFD, 0);
249*4887Schin 				return 0;
250*4887Schin 			}
251*4887Schin 			break;
252*4887Schin 		case PROC_sig_dfl:
253*4887Schin 			if ((m->arg.handler = signal(arg1, SIG_DFL)) == SIG_DFL)
254*4887Schin 				break;
255*4887Schin 			m->save = (short)arg1;
256*4887Schin 			return 0;
257*4887Schin 		case PROC_sig_ign:
258*4887Schin 			if ((m->arg.handler = signal(arg1, SIG_IGN)) == SIG_IGN)
259*4887Schin 				break;
260*4887Schin 			m->save = (short)arg1;
261*4887Schin 			return 0;
262*4887Schin 		case PROC_sys_pgrp:
263*4887Schin 			proc->pgrp = arg1;
264*4887Schin 			break;
265*4887Schin 		case PROC_sys_umask:
266*4887Schin 			if ((m->save = (short)umask(arg1)) == arg1)
267*4887Schin 				break;
268*4887Schin 			return 0;
269*4887Schin 		default:
270*4887Schin 			proc->mods = m->next;
271*4887Schin 			free(m);
272*4887Schin 			return -1;
273*4887Schin 		}
274*4887Schin 		proc->mods = m->next;
275*4887Schin 		free(m);
276*4887Schin 	}
277*4887Schin #else
278*4887Schin 	NoP(proc);
279*4887Schin #endif
280*4887Schin 	return 0;
281*4887Schin }
282*4887Schin 
283*4887Schin #if _use_spawnveg
284*4887Schin 
285*4887Schin /*
286*4887Schin  * restore modifications
287*4887Schin  */
288*4887Schin 
289*4887Schin static void
290*4887Schin restore(Proc_t* proc)
291*4887Schin {
292*4887Schin 	register Modify_t*	m;
293*4887Schin 	register Modify_t*	p;
294*4887Schin 	int			oerrno;
295*4887Schin 
296*4887Schin 	NoP(proc);
297*4887Schin 	oerrno = errno;
298*4887Schin 	m = proc->mods;
299*4887Schin 	proc->mods = 0;
300*4887Schin 	while (m)
301*4887Schin 	{
302*4887Schin 		switch (m->op)
303*4887Schin 		{
304*4887Schin 		case PROC_fd_dup:
305*4887Schin 		case PROC_fd_dup|PROC_FD_PARENT:
306*4887Schin 		case PROC_fd_dup|PROC_FD_CHILD:
307*4887Schin 		case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
308*4887Schin 			if (m->op & PROC_FD_PARENT)
309*4887Schin 				close(m->arg.fd.parent.fd);
310*4887Schin 			if (m->arg.fd.child.fd != m->arg.fd.parent.fd && m->arg.fd.child.fd != PROC_ARG_NULL)
311*4887Schin 			{
312*4887Schin 				if (!(m->op & PROC_FD_PARENT))
313*4887Schin 				{
314*4887Schin 					if (m->op & PROC_FD_CHILD)
315*4887Schin 					{
316*4887Schin 						close(m->arg.fd.parent.fd);
317*4887Schin 						fcntl(m->arg.fd.child.fd, F_DUPFD, m->arg.fd.parent.fd);
318*4887Schin 					}
319*4887Schin 					fcntl(m->arg.fd.parent.fd, F_SETFD, m->arg.fd.parent.flag);
320*4887Schin 				}
321*4887Schin 				close(m->arg.fd.child.fd);
322*4887Schin 				fcntl(m->save, F_DUPFD, m->arg.fd.child.fd);
323*4887Schin 				close(m->save);
324*4887Schin 				if (m->arg.fd.child.flag)
325*4887Schin 					fcntl(m->arg.fd.child.fd, F_SETFD, FD_CLOEXEC);
326*4887Schin 			}
327*4887Schin 			else if ((m->op & (PROC_FD_PARENT|PROC_FD_CHILD)) == PROC_FD_CHILD)
328*4887Schin 				fcntl(m->arg.fd.parent.fd, F_SETFD, 0);
329*4887Schin 			break;
330*4887Schin 		case PROC_sig_dfl:
331*4887Schin 		case PROC_sig_ign:
332*4887Schin 			signal(m->save, m->arg.handler);
333*4887Schin 			break;
334*4887Schin 		case PROC_sys_umask:
335*4887Schin 			umask(m->save);
336*4887Schin 			break;
337*4887Schin 		}
338*4887Schin 		p = m;
339*4887Schin 		m = m->next;
340*4887Schin 		free(p);
341*4887Schin 	}
342*4887Schin 	errno = oerrno;
343*4887Schin }
344*4887Schin 
345*4887Schin #else
346*4887Schin 
347*4887Schin #define restore(p)
348*4887Schin 
349*4887Schin #endif
350*4887Schin 
351*4887Schin /*
352*4887Schin  * fork and exec or spawn proc(argv) and return a Proc_t handle
353*4887Schin  *
354*4887Schin  * pipe not used when PROC_READ|PROC_WRITE omitted
355*4887Schin  * argv==0 duplicates current process if possible
356*4887Schin  * cmd==0 names the current shell
357*4887Schin  * cmd=="" does error cleanup
358*4887Schin  * envv is the child environment
359*4887Schin  * modv is the child modification vector of PROC_*() ops
360*4887Schin  */
361*4887Schin 
362*4887Schin Proc_t*
363*4887Schin procopen(const char* cmd, char** argv, char** envv, long* modv, long flags)
364*4887Schin {
365*4887Schin 	register Proc_t*	proc = 0;
366*4887Schin 	register int		procfd;
367*4887Schin 	register char**		p;
368*4887Schin 	char**			v;
369*4887Schin 	int			i;
370*4887Schin 	int			forked = 0;
371*4887Schin 	long			n;
372*4887Schin 	char			path[PATH_MAX];
373*4887Schin 	char			env[PATH_MAX + 2];
374*4887Schin 	int			pio[2];
375*4887Schin #if !_pipe_rw && !_lib_socketpair
376*4887Schin 	int			poi[2];
377*4887Schin #endif
378*4887Schin #if defined(SIGCHLD) && ( _lib_sigprocmask || _lib_sigsetmask )
379*4887Schin 	Sig_mask_t		mask;
380*4887Schin #endif
381*4887Schin #if _use_spawnveg
382*4887Schin 	int			newenv = 0;
383*4887Schin #endif
384*4887Schin #if DEBUG_PROC
385*4887Schin 	int			debug = PROC_OPT_EXEC;
386*4887Schin #endif
387*4887Schin 
388*4887Schin #if _lib_fork
389*4887Schin 	if (!argv && (flags & PROC_OVERLAY))
390*4887Schin #else
391*4887Schin 	if (!argv)
392*4887Schin #endif
393*4887Schin 	{
394*4887Schin 		errno = ENOEXEC;
395*4887Schin 		return 0;
396*4887Schin 	}
397*4887Schin 	pio[0] = pio[1] = -1;
398*4887Schin #if !_pipe_rw && !_lib_socketpair
399*4887Schin 	poi[0] = poi[1] = -1;
400*4887Schin #endif
401*4887Schin 	if (cmd && (!*cmd || !pathpath(path, cmd, NiL, PATH_REGULAR|PATH_EXECUTE)))
402*4887Schin 		goto bad;
403*4887Schin 	switch (flags & (PROC_READ|PROC_WRITE))
404*4887Schin 	{
405*4887Schin 	case 0:
406*4887Schin 		procfd = -1;
407*4887Schin 		break;
408*4887Schin 	case PROC_READ:
409*4887Schin 		procfd = 1;
410*4887Schin 		break;
411*4887Schin 	case PROC_WRITE:
412*4887Schin 		procfd = 0;
413*4887Schin 		break;
414*4887Schin 	case PROC_READ|PROC_WRITE:
415*4887Schin 		procfd = 2;
416*4887Schin 		break;
417*4887Schin 	}
418*4887Schin 	if (proc_default.pid == -1)
419*4887Schin 		proc = &proc_default;
420*4887Schin 	else if (!(proc = newof(0, Proc_t, 1, 0)))
421*4887Schin 		goto bad;
422*4887Schin 	proc->pid = -1;
423*4887Schin 	proc->pgrp = 0;
424*4887Schin 	proc->rfd = -1;
425*4887Schin 	proc->wfd = -1;
426*4887Schin 	proc->flags = flags;
427*4887Schin 	sfsync(NiL);
428*4887Schin 	if (environ && envv != (char**)environ && (envv || (flags & PROC_PARANOID) || argv && (environ[0][0] != '_' || environ[0][1] != '=')))
429*4887Schin 	{
430*4887Schin 		if (!setenviron(NiL))
431*4887Schin 			goto bad;
432*4887Schin #if _use_spawnveg
433*4887Schin 		newenv = 1;
434*4887Schin #endif
435*4887Schin 	}
436*4887Schin 	if (procfd >= 0)
437*4887Schin 	{
438*4887Schin #if _pipe_rw
439*4887Schin 		if (pipe(pio))
440*4887Schin 			goto bad;
441*4887Schin #else
442*4887Schin 		if (procfd > 1)
443*4887Schin 		{
444*4887Schin #if _lib_socketpair
445*4887Schin 			if (socketpair(AF_UNIX, SOCK_STREAM, 0, pio))
446*4887Schin 				goto bad;
447*4887Schin #else
448*4887Schin 			if (pipe(pio) || pipe(poi))
449*4887Schin 				goto bad;
450*4887Schin #endif
451*4887Schin 		}
452*4887Schin 		else if (pipe(pio))
453*4887Schin 			goto bad;
454*4887Schin #endif
455*4887Schin 	}
456*4887Schin 	if (flags & PROC_OVERLAY)
457*4887Schin 	{
458*4887Schin 		proc->pid = 0;
459*4887Schin 		forked = 1;
460*4887Schin 	}
461*4887Schin #if _use_spawnveg
462*4887Schin 	else if (argv)
463*4887Schin 		proc->pid = 0;
464*4887Schin #endif
465*4887Schin #if _lib_fork
466*4887Schin 	else
467*4887Schin 	{
468*4887Schin 		if (!(flags & PROC_FOREGROUND))
469*4887Schin 			sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
470*4887Schin 		else
471*4887Schin 		{
472*4887Schin 			proc->sigint = signal(SIGINT, SIG_IGN);
473*4887Schin 			proc->sigquit = signal(SIGQUIT, SIG_IGN);
474*4887Schin #if defined(SIGCHLD)
475*4887Schin 			proc->sigchld = signal(SIGCHLD, SIG_DFL);
476*4887Schin #if _lib_sigprocmask
477*4887Schin 			sigemptyset(&mask);
478*4887Schin 			sigaddset(&mask, SIGCHLD);
479*4887Schin 			sigprocmask(SIG_BLOCK, &mask, &proc->mask);
480*4887Schin #else
481*4887Schin #if _lib_sigsetmask
482*4887Schin 			mask = sigmask(SIGCHLD);
483*4887Schin 			proc->mask = sigblock(mask);
484*4887Schin #endif
485*4887Schin #endif
486*4887Schin #endif
487*4887Schin 		}
488*4887Schin 		proc->pid = fork();
489*4887Schin 		if (!(flags & PROC_FOREGROUND))
490*4887Schin 			sigcritical(0);
491*4887Schin 		else if (!proc->pid)
492*4887Schin 		{
493*4887Schin 			if (proc->sigint != SIG_IGN)
494*4887Schin 				proc->sigint = SIG_DFL;
495*4887Schin 			signal(SIGINT, proc->sigint);
496*4887Schin 			if (proc->sigquit != SIG_IGN)
497*4887Schin 				proc->sigquit = SIG_DFL;
498*4887Schin 			signal(SIGQUIT, proc->sigquit);
499*4887Schin #if defined(SIGCHLD)
500*4887Schin 			if (proc->sigchld != SIG_IGN)
501*4887Schin 				proc->sigchld = SIG_DFL;
502*4887Schin 			signal(SIGCHLD, proc->sigchld);
503*4887Schin #endif
504*4887Schin 		}
505*4887Schin 		if (proc->pid == -1)
506*4887Schin 			goto bad;
507*4887Schin 		forked = 1;
508*4887Schin 	}
509*4887Schin #endif
510*4887Schin 	if (!proc->pid)
511*4887Schin 	{
512*4887Schin 		char*		s;
513*4887Schin #if _use_spawnveg
514*4887Schin 		char**		oenviron = 0;
515*4887Schin 		char*		oenviron0 = 0;
516*4887Schin 
517*4887Schin 		v = 0;
518*4887Schin #endif
519*4887Schin #if DEBUG_PROC
520*4887Schin 		stropt(getenv(PROC_ENV_OPTIONS), options, sizeof(*options), setopt, &debug);
521*4887Schin #if _lib_fork
522*4887Schin 		if (debug & PROC_OPT_TRACE)
523*4887Schin 		{
524*4887Schin 			if (!fork())
525*4887Schin 			{
526*4887Schin 				sfsprintf(path, sizeof(path), "%d", getppid());
527*4887Schin 				execlp("trace", "trace", "-p", path, NiL);
528*4887Schin 				_exit(EXIT_NOTFOUND);
529*4887Schin 			}
530*4887Schin 			sleep(2);
531*4887Schin 		}
532*4887Schin #endif
533*4887Schin #endif
534*4887Schin 		if (flags & PROC_DAEMON)
535*4887Schin 		{
536*4887Schin #ifdef SIGHUP
537*4887Schin 			modify(proc, forked, PROC_sig_ign, SIGHUP, 0);
538*4887Schin #endif
539*4887Schin 			modify(proc, forked, PROC_sig_dfl, SIGTERM, 0);
540*4887Schin #ifdef SIGTSTP
541*4887Schin 			modify(proc, forked, PROC_sig_ign, SIGTSTP, 0);
542*4887Schin #endif
543*4887Schin #ifdef SIGTTIN
544*4887Schin 			modify(proc, forked, PROC_sig_ign, SIGTTIN, 0);
545*4887Schin #endif
546*4887Schin #ifdef SIGTTOU
547*4887Schin 			modify(proc, forked, PROC_sig_ign, SIGTTOU, 0);
548*4887Schin #endif
549*4887Schin 		}
550*4887Schin 		if (flags & (PROC_BACKGROUND|PROC_DAEMON))
551*4887Schin 		{
552*4887Schin 			modify(proc, forked, PROC_sig_ign, SIGINT, 0);
553*4887Schin #ifdef SIGQUIT
554*4887Schin 			modify(proc, forked, PROC_sig_ign, SIGQUIT, 0);
555*4887Schin #endif
556*4887Schin 		}
557*4887Schin 		if (flags & (PROC_DAEMON|PROC_SESSION))
558*4887Schin 			modify(proc, forked, PROC_sys_pgrp, -1, 0);
559*4887Schin 		if (forked || (flags & PROC_OVERLAY))
560*4887Schin 		{
561*4887Schin 			if ((flags & PROC_PRIVELEGED) && !geteuid())
562*4887Schin 			{
563*4887Schin 				setuid(geteuid());
564*4887Schin 				setgid(getegid());
565*4887Schin 			}
566*4887Schin 			if (flags & (PROC_PARANOID|PROC_GID))
567*4887Schin 				setgid(getgid());
568*4887Schin 			if (flags & (PROC_PARANOID|PROC_UID))
569*4887Schin 				setuid(getuid());
570*4887Schin 		}
571*4887Schin 		if (procfd > 1)
572*4887Schin 		{
573*4887Schin 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[0], PROC_ARG_NULL))
574*4887Schin 				goto cleanup;
575*4887Schin 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[1], 1))
576*4887Schin 				goto cleanup;
577*4887Schin #if _pipe_rw || _lib_socketpair
578*4887Schin 			if (modify(proc, forked, PROC_fd_dup, 1, 0))
579*4887Schin 				goto cleanup;
580*4887Schin #else
581*4887Schin 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[0], 0))
582*4887Schin 				goto cleanup;
583*4887Schin 			if (poi[1] != 0 && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[1], PROC_ARG_NULL))
584*4887Schin 				goto cleanup;
585*4887Schin #endif
586*4887Schin 		}
587*4887Schin 		else if (procfd >= 0)
588*4887Schin 		{
589*4887Schin 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!!procfd], !!procfd))
590*4887Schin 				goto cleanup;
591*4887Schin 			if (pio[!procfd] != !!procfd && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!procfd], PROC_ARG_NULL))
592*4887Schin 				goto cleanup;
593*4887Schin 		}
594*4887Schin 		if (modv)
595*4887Schin 			for (i = 0; n = modv[i]; i++)
596*4887Schin 				switch (PROC_OP(n))
597*4887Schin 				{
598*4887Schin 				case PROC_fd_dup:
599*4887Schin 				case PROC_fd_dup|PROC_FD_PARENT:
600*4887Schin 				case PROC_fd_dup|PROC_FD_CHILD:
601*4887Schin 				case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
602*4887Schin 					if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), PROC_ARG(n, 2)))
603*4887Schin 						goto cleanup;
604*4887Schin 					break;
605*4887Schin 				default:
606*4887Schin 					if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), 0))
607*4887Schin 						goto cleanup;
608*4887Schin 					break;
609*4887Schin 				}
610*4887Schin #if _lib_fork
611*4887Schin 		if (forked && (flags & PROC_ENVCLEAR))
612*4887Schin 			environ = 0;
613*4887Schin #if _use_spawnveg
614*4887Schin 		else
615*4887Schin #endif
616*4887Schin #endif
617*4887Schin #if _use_spawnveg
618*4887Schin 		if (newenv)
619*4887Schin 		{
620*4887Schin 			p = environ;
621*4887Schin 			while (*p++);
622*4887Schin 			if (!(oenviron = (char**)memdup(environ, (p - environ) * sizeof(char*))))
623*4887Schin 				goto cleanup;
624*4887Schin 		}
625*4887Schin #endif
626*4887Schin 		if (argv && envv != (char**)environ)
627*4887Schin 		{
628*4887Schin #if _use_spawnveg
629*4887Schin 			if (!newenv && environ[0][0] == '_' && environ[0][1] == '=')
630*4887Schin 				oenviron0 = environ[0];
631*4887Schin #endif
632*4887Schin 			env[0] = '_';
633*4887Schin 			env[1] = '=';
634*4887Schin 			env[2] = 0;
635*4887Schin 			if (!setenviron(env))
636*4887Schin 				goto cleanup;
637*4887Schin 		}
638*4887Schin 		if ((flags & PROC_PARANOID) && setenv("PATH", astconf("PATH", NiL, NiL), 1))
639*4887Schin 			goto cleanup;
640*4887Schin 		if ((p = envv) && p != (char**)environ)
641*4887Schin 			while (*p)
642*4887Schin 				if (!setenviron(*p++))
643*4887Schin 					goto cleanup;
644*4887Schin 		p = argv;
645*4887Schin #if _lib_fork
646*4887Schin 		if (forked && !p)
647*4887Schin 			return proc;
648*4887Schin #endif
649*4887Schin #if DEBUG_PROC
650*4887Schin 		if (!(debug & PROC_OPT_EXEC) || (debug & PROC_OPT_VERBOSE))
651*4887Schin 		{
652*4887Schin 			if ((debug & PROC_OPT_ENVIRONMENT) && (p = environ))
653*4887Schin 				while (*p)
654*4887Schin 					sfprintf(sfstderr, "%s\n", *p++);
655*4887Schin 			sfprintf(sfstderr, "+ %s", cmd ? path : "sh");
656*4887Schin 			if ((p = argv) && *p)
657*4887Schin 				while (*++p)
658*4887Schin 					sfprintf(sfstderr, " %s", *p);
659*4887Schin 			sfprintf(sfstderr, "\n");
660*4887Schin sfsync(sfstderr);
661*4887Schin 			if (!(debug & PROC_OPT_EXEC))
662*4887Schin 				_exit(0);
663*4887Schin 			p = argv;
664*4887Schin 		}
665*4887Schin #endif
666*4887Schin 		if (cmd)
667*4887Schin 		{
668*4887Schin 			strcpy(env + 2, path);
669*4887Schin 			if (forked || (flags & PROC_OVERLAY))
670*4887Schin 				execve(path, p, environ);
671*4887Schin #if _use_spawnveg
672*4887Schin 			else if ((proc->pid = spawnveg(path, p, environ, proc->pgrp)) != -1)
673*4887Schin 				goto cleanup;
674*4887Schin #endif
675*4887Schin 			if (errno != ENOEXEC)
676*4887Schin 				goto cleanup;
677*4887Schin 
678*4887Schin 			/*
679*4887Schin 			 * try cmd as a shell script
680*4887Schin 			 */
681*4887Schin 
682*4887Schin 			if (!(flags & PROC_ARGMOD))
683*4887Schin 			{
684*4887Schin 				while (*p++);
685*4887Schin 				if (!(v = newof(0, char*, p - argv + 2, 0)))
686*4887Schin 					goto cleanup;
687*4887Schin 				p = v + 2;
688*4887Schin 				if (*argv)
689*4887Schin 					argv++;
690*4887Schin 				while (*p++ = *argv++);
691*4887Schin 				p = v + 1;
692*4887Schin 			}
693*4887Schin 			*p = path;
694*4887Schin 			*--p = "sh";
695*4887Schin 		}
696*4887Schin 		strcpy(env + 2, (flags & PROC_PARANOID) ? astconf("SH", NiL, NiL) : pathshell());
697*4887Schin 		if (forked || (flags & PROC_OVERLAY))
698*4887Schin 			execve(env + 2, p, environ);
699*4887Schin #if _use_spawnveg
700*4887Schin 		else
701*4887Schin 			proc->pid = spawnveg(env + 2, p, environ, proc->pgrp);
702*4887Schin #endif
703*4887Schin 	cleanup:
704*4887Schin 		if (forked)
705*4887Schin 		{
706*4887Schin 			if (!(flags & PROC_OVERLAY))
707*4887Schin 				_exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
708*4887Schin 			goto bad;
709*4887Schin 		}
710*4887Schin #if _use_spawnveg
711*4887Schin 		if (v)
712*4887Schin 			free(v);
713*4887Schin 		if (p = oenviron)
714*4887Schin 		{
715*4887Schin 			environ = 0;
716*4887Schin 			while (*p)
717*4887Schin 				if (!setenviron(*p++))
718*4887Schin 					goto bad;
719*4887Schin 			free(oenviron);
720*4887Schin 		}
721*4887Schin 		else if (oenviron0)
722*4887Schin 			environ[0] = oenviron0;
723*4887Schin 		restore(proc);
724*4887Schin 		if (flags & PROC_OVERLAY)
725*4887Schin 			exit(0);
726*4887Schin #endif
727*4887Schin 	}
728*4887Schin 	if (proc->pid != -1)
729*4887Schin 	{
730*4887Schin 		if (!forked)
731*4887Schin 		{
732*4887Schin 			if (flags & PROC_FOREGROUND)
733*4887Schin 			{
734*4887Schin 				proc->sigint = signal(SIGINT, SIG_IGN);
735*4887Schin 				proc->sigquit = signal(SIGQUIT, SIG_IGN);
736*4887Schin #if defined(SIGCHLD)
737*4887Schin 				proc->sigchld = signal(SIGCHLD, SIG_DFL);
738*4887Schin #endif
739*4887Schin 			}
740*4887Schin 		}
741*4887Schin 		else if (modv)
742*4887Schin 			for (i = 0; n = modv[i]; i++)
743*4887Schin 				switch (PROC_OP(n))
744*4887Schin 				{
745*4887Schin 				case PROC_fd_dup|PROC_FD_PARENT:
746*4887Schin 				case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
747*4887Schin 					close(PROC_ARG(n, 1));
748*4887Schin 					break;
749*4887Schin 				case PROC_sys_pgrp:
750*4887Schin 					if (proc->pgrp < 0)
751*4887Schin 						proc->pgrp = proc->pid;
752*4887Schin 					else if (proc->pgrp > 0)
753*4887Schin 					{
754*4887Schin 						if (proc->pgrp == 1)
755*4887Schin 							proc->pgrp = proc->pid;
756*4887Schin 						if (setpgid(proc->pid, proc->pgrp) < 0 && proc->pid != proc->pgrp && errno == EPERM)
757*4887Schin 							setpgid(proc->pid, proc->pid);
758*4887Schin 					}
759*4887Schin 					break;
760*4887Schin 				}
761*4887Schin 		if (procfd >= 0)
762*4887Schin 		{
763*4887Schin #ifdef SIGPIPE
764*4887Schin 			if ((flags & (PROC_WRITE|PROC_IGNORE)) == (PROC_WRITE|PROC_IGNORE))
765*4887Schin 			{
766*4887Schin 				Handler_t	handler;
767*4887Schin 
768*4887Schin 				if ((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && handler != ignoresig)
769*4887Schin 					signal(SIGPIPE, handler);
770*4887Schin 			}
771*4887Schin #endif
772*4887Schin 			switch (procfd)
773*4887Schin 			{
774*4887Schin 			case 0:
775*4887Schin 				proc->wfd = pio[1];
776*4887Schin 				close(pio[0]);
777*4887Schin 				break;
778*4887Schin 			default:
779*4887Schin #if _pipe_rw || _lib_socketpair
780*4887Schin 				proc->wfd = pio[0];
781*4887Schin #else
782*4887Schin 				proc->wfd = poi[1];
783*4887Schin 				close(poi[0]);
784*4887Schin #endif
785*4887Schin 				/*FALLTHROUGH*/
786*4887Schin 			case 1:
787*4887Schin 				proc->rfd = pio[0];
788*4887Schin 				close(pio[1]);
789*4887Schin 				break;
790*4887Schin 			}
791*4887Schin 			if (proc->rfd > 2)
792*4887Schin 				fcntl(proc->rfd, F_SETFD, FD_CLOEXEC);
793*4887Schin 			if (proc->wfd > 2)
794*4887Schin 				fcntl(proc->wfd, F_SETFD, FD_CLOEXEC);
795*4887Schin 		}
796*4887Schin 		if (!proc->pid)
797*4887Schin 			proc->pid = getpid();
798*4887Schin 		return proc;
799*4887Schin 	}
800*4887Schin  bad:
801*4887Schin 	if ((flags & PROC_CLEANUP) && modv)
802*4887Schin 		for (i = 0; n = modv[i]; i++)
803*4887Schin 			switch (PROC_OP(n))
804*4887Schin 			{
805*4887Schin 			case PROC_fd_dup:
806*4887Schin 			case PROC_fd_dup|PROC_FD_PARENT:
807*4887Schin 			case PROC_fd_dup|PROC_FD_CHILD:
808*4887Schin 			case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
809*4887Schin 				if (PROC_ARG(n, 2) != PROC_ARG_NULL)
810*4887Schin 					close(PROC_ARG(n, 1));
811*4887Schin 				break;
812*4887Schin 			}
813*4887Schin 	if (pio[0] >= 0)
814*4887Schin 		close(pio[0]);
815*4887Schin 	if (pio[1] >= 0)
816*4887Schin 		close(pio[1]);
817*4887Schin #if !_pipe_rw && !_lib_socketpair
818*4887Schin 	if (poi[0] >= 0)
819*4887Schin 		close(poi[0]);
820*4887Schin 	if (poi[1] >= 0)
821*4887Schin 		close(poi[1]);
822*4887Schin #endif
823*4887Schin 	procfree(proc);
824*4887Schin 	return 0;
825*4887Schin }
826