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