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