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