xref: /titanic_50/usr/src/lib/libast/common/misc/procopen.c (revision 44743693dce3212f5edba623e0cb0327bd4337a3)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
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 
59 Proc_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 
72 static 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 
86 static int
87 setopt(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 
104 typedef struct Fd_s
105 {
106 	short		fd;
107 	short		flag;
108 } Fd_t;
109 
110 typedef 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 
140 static void
141 ignoresig(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 
152 static int
153 modify(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 
289 static void
290 restore(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 
362 Proc_t*
363 procopen(const char* cmd, char** argv, char** envv, long* modv, long 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 	long			n;
372 	char			path[PATH_MAX];
373 	char			env[PATH_MAX + 2];
374 	int			pio[2];
375 #if !_pipe_rw && !_lib_socketpair
376 	int			poi[2];
377 #endif
378 #if defined(SIGCHLD) && ( _lib_sigprocmask || _lib_sigsetmask )
379 	Sig_mask_t		mask;
380 #endif
381 #if _use_spawnveg
382 	int			newenv = 0;
383 #endif
384 #if DEBUG_PROC
385 	int			debug = PROC_OPT_EXEC;
386 #endif
387 
388 #if _lib_fork
389 	if (!argv && (flags & PROC_OVERLAY))
390 #else
391 	if (!argv)
392 #endif
393 	{
394 		errno = ENOEXEC;
395 		return 0;
396 	}
397 	pio[0] = pio[1] = -1;
398 #if !_pipe_rw && !_lib_socketpair
399 	poi[0] = poi[1] = -1;
400 #endif
401 	if (cmd && (!*cmd || !pathpath(path, cmd, NiL, PATH_REGULAR|PATH_EXECUTE)))
402 		goto bad;
403 	switch (flags & (PROC_READ|PROC_WRITE))
404 	{
405 	case 0:
406 		procfd = -1;
407 		break;
408 	case PROC_READ:
409 		procfd = 1;
410 		break;
411 	case PROC_WRITE:
412 		procfd = 0;
413 		break;
414 	case PROC_READ|PROC_WRITE:
415 		procfd = 2;
416 		break;
417 	}
418 	if (proc_default.pid == -1)
419 		proc = &proc_default;
420 	else if (!(proc = newof(0, Proc_t, 1, 0)))
421 		goto bad;
422 	proc->pid = -1;
423 	proc->pgrp = 0;
424 	proc->rfd = -1;
425 	proc->wfd = -1;
426 	proc->flags = flags;
427 	sfsync(NiL);
428 	if (environ && envv != (char**)environ && (envv || (flags & PROC_PARANOID) || argv && (environ[0][0] != '_' || environ[0][1] != '=')))
429 	{
430 		if (!setenviron(NiL))
431 			goto bad;
432 #if _use_spawnveg
433 		newenv = 1;
434 #endif
435 	}
436 	if (procfd >= 0)
437 	{
438 #if _pipe_rw
439 		if (pipe(pio))
440 			goto bad;
441 #else
442 		if (procfd > 1)
443 		{
444 #if _lib_socketpair
445 			if (socketpair(AF_UNIX, SOCK_STREAM, 0, pio))
446 				goto bad;
447 #else
448 			if (pipe(pio) || pipe(poi))
449 				goto bad;
450 #endif
451 		}
452 		else if (pipe(pio))
453 			goto bad;
454 #endif
455 	}
456 	if (flags & PROC_OVERLAY)
457 	{
458 		proc->pid = 0;
459 		forked = 1;
460 	}
461 #if _use_spawnveg
462 	else if (argv)
463 		proc->pid = 0;
464 #endif
465 #if _lib_fork
466 	else
467 	{
468 		if (!(flags & PROC_FOREGROUND))
469 			sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
470 		else
471 		{
472 			proc->sigint = signal(SIGINT, SIG_IGN);
473 			proc->sigquit = signal(SIGQUIT, SIG_IGN);
474 #if defined(SIGCHLD)
475 			proc->sigchld = signal(SIGCHLD, SIG_DFL);
476 #if _lib_sigprocmask
477 			sigemptyset(&mask);
478 			sigaddset(&mask, SIGCHLD);
479 			sigprocmask(SIG_BLOCK, &mask, &proc->mask);
480 #else
481 #if _lib_sigsetmask
482 			mask = sigmask(SIGCHLD);
483 			proc->mask = sigblock(mask);
484 #endif
485 #endif
486 #endif
487 		}
488 		proc->pid = fork();
489 		if (!(flags & PROC_FOREGROUND))
490 			sigcritical(0);
491 		else if (!proc->pid)
492 		{
493 			if (proc->sigint != SIG_IGN)
494 				proc->sigint = SIG_DFL;
495 			signal(SIGINT, proc->sigint);
496 			if (proc->sigquit != SIG_IGN)
497 				proc->sigquit = SIG_DFL;
498 			signal(SIGQUIT, proc->sigquit);
499 #if defined(SIGCHLD)
500 			if (proc->sigchld != SIG_IGN)
501 				proc->sigchld = SIG_DFL;
502 			signal(SIGCHLD, proc->sigchld);
503 #endif
504 		}
505 		if (proc->pid == -1)
506 			goto bad;
507 		forked = 1;
508 	}
509 #endif
510 	if (!proc->pid)
511 	{
512 		char*		s;
513 #if _use_spawnveg
514 		char**		oenviron = 0;
515 		char*		oenviron0 = 0;
516 
517 		v = 0;
518 #endif
519 #if DEBUG_PROC
520 		stropt(getenv(PROC_ENV_OPTIONS), options, sizeof(*options), setopt, &debug);
521 #if _lib_fork
522 		if (debug & PROC_OPT_TRACE)
523 		{
524 			if (!fork())
525 			{
526 				sfsprintf(path, sizeof(path), "%d", getppid());
527 				execlp("trace", "trace", "-p", path, NiL);
528 				_exit(EXIT_NOTFOUND);
529 			}
530 			sleep(2);
531 		}
532 #endif
533 #endif
534 		if (flags & PROC_DAEMON)
535 		{
536 #ifdef SIGHUP
537 			modify(proc, forked, PROC_sig_ign, SIGHUP, 0);
538 #endif
539 			modify(proc, forked, PROC_sig_dfl, SIGTERM, 0);
540 #ifdef SIGTSTP
541 			modify(proc, forked, PROC_sig_ign, SIGTSTP, 0);
542 #endif
543 #ifdef SIGTTIN
544 			modify(proc, forked, PROC_sig_ign, SIGTTIN, 0);
545 #endif
546 #ifdef SIGTTOU
547 			modify(proc, forked, PROC_sig_ign, SIGTTOU, 0);
548 #endif
549 		}
550 		if (flags & (PROC_BACKGROUND|PROC_DAEMON))
551 		{
552 			modify(proc, forked, PROC_sig_ign, SIGINT, 0);
553 #ifdef SIGQUIT
554 			modify(proc, forked, PROC_sig_ign, SIGQUIT, 0);
555 #endif
556 		}
557 		if (flags & (PROC_DAEMON|PROC_SESSION))
558 			modify(proc, forked, PROC_sys_pgrp, -1, 0);
559 		if (forked || (flags & PROC_OVERLAY))
560 		{
561 			if ((flags & PROC_PRIVELEGED) && !geteuid())
562 			{
563 				setuid(geteuid());
564 				setgid(getegid());
565 			}
566 			if (flags & (PROC_PARANOID|PROC_GID))
567 				setgid(getgid());
568 			if (flags & (PROC_PARANOID|PROC_UID))
569 				setuid(getuid());
570 		}
571 		if (procfd > 1)
572 		{
573 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[0], PROC_ARG_NULL))
574 				goto cleanup;
575 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[1], 1))
576 				goto cleanup;
577 #if _pipe_rw || _lib_socketpair
578 			if (modify(proc, forked, PROC_fd_dup, 1, 0))
579 				goto cleanup;
580 #else
581 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[0], 0))
582 				goto cleanup;
583 			if (poi[1] != 0 && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[1], PROC_ARG_NULL))
584 				goto cleanup;
585 #endif
586 		}
587 		else if (procfd >= 0)
588 		{
589 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!!procfd], !!procfd))
590 				goto cleanup;
591 			if (pio[!procfd] != !!procfd && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!procfd], PROC_ARG_NULL))
592 				goto cleanup;
593 		}
594 		if (modv)
595 			for (i = 0; n = modv[i]; i++)
596 				switch (PROC_OP(n))
597 				{
598 				case PROC_fd_dup:
599 				case PROC_fd_dup|PROC_FD_PARENT:
600 				case PROC_fd_dup|PROC_FD_CHILD:
601 				case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
602 					if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), PROC_ARG(n, 2)))
603 						goto cleanup;
604 					break;
605 				default:
606 					if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), 0))
607 						goto cleanup;
608 					break;
609 				}
610 #if _lib_fork
611 		if (forked && (flags & PROC_ENVCLEAR))
612 			environ = 0;
613 #if _use_spawnveg
614 		else
615 #endif
616 #endif
617 #if _use_spawnveg
618 		if (newenv)
619 		{
620 			p = environ;
621 			while (*p++);
622 			if (!(oenviron = (char**)memdup(environ, (p - environ) * sizeof(char*))))
623 				goto cleanup;
624 		}
625 #endif
626 		if (argv && envv != (char**)environ)
627 		{
628 #if _use_spawnveg
629 			if (!newenv && environ[0][0] == '_' && environ[0][1] == '=')
630 				oenviron0 = environ[0];
631 #endif
632 			env[0] = '_';
633 			env[1] = '=';
634 			env[2] = 0;
635 			if (!setenviron(env))
636 				goto cleanup;
637 		}
638 		if ((flags & PROC_PARANOID) && setenv("PATH", astconf("PATH", NiL, NiL), 1))
639 			goto cleanup;
640 		if ((p = envv) && p != (char**)environ)
641 			while (*p)
642 				if (!setenviron(*p++))
643 					goto cleanup;
644 		p = argv;
645 #if _lib_fork
646 		if (forked && !p)
647 			return proc;
648 #endif
649 #if DEBUG_PROC
650 		if (!(debug & PROC_OPT_EXEC) || (debug & PROC_OPT_VERBOSE))
651 		{
652 			if ((debug & PROC_OPT_ENVIRONMENT) && (p = environ))
653 				while (*p)
654 					sfprintf(sfstderr, "%s\n", *p++);
655 			sfprintf(sfstderr, "+ %s", cmd ? path : "sh");
656 			if ((p = argv) && *p)
657 				while (*++p)
658 					sfprintf(sfstderr, " %s", *p);
659 			sfprintf(sfstderr, "\n");
660 sfsync(sfstderr);
661 			if (!(debug & PROC_OPT_EXEC))
662 				_exit(0);
663 			p = argv;
664 		}
665 #endif
666 		if (cmd)
667 		{
668 			strcpy(env + 2, path);
669 			if (forked || (flags & PROC_OVERLAY))
670 				execve(path, p, environ);
671 #if _use_spawnveg
672 			else if ((proc->pid = spawnveg(path, p, environ, proc->pgrp)) != -1)
673 				goto cleanup;
674 #endif
675 			if (errno != ENOEXEC)
676 				goto cleanup;
677 
678 			/*
679 			 * try cmd as a shell script
680 			 */
681 
682 			if (!(flags & PROC_ARGMOD))
683 			{
684 				while (*p++);
685 				if (!(v = newof(0, char*, p - argv + 2, 0)))
686 					goto cleanup;
687 				p = v + 2;
688 				if (*argv)
689 					argv++;
690 				while (*p++ = *argv++);
691 				p = v + 1;
692 			}
693 			*p = path;
694 			*--p = "sh";
695 		}
696 		strcpy(env + 2, (flags & PROC_PARANOID) ? astconf("SH", NiL, NiL) : pathshell());
697 		if (forked || (flags & PROC_OVERLAY))
698 			execve(env + 2, p, environ);
699 #if _use_spawnveg
700 		else
701 			proc->pid = spawnveg(env + 2, p, environ, proc->pgrp);
702 #endif
703 	cleanup:
704 		if (forked)
705 		{
706 			if (!(flags & PROC_OVERLAY))
707 				_exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
708 			goto bad;
709 		}
710 #if _use_spawnveg
711 		if (v)
712 			free(v);
713 		if (p = oenviron)
714 		{
715 			environ = 0;
716 			while (*p)
717 				if (!setenviron(*p++))
718 					goto bad;
719 			free(oenviron);
720 		}
721 		else if (oenviron0)
722 			environ[0] = oenviron0;
723 		restore(proc);
724 		if (flags & PROC_OVERLAY)
725 			exit(0);
726 #endif
727 	}
728 	if (proc->pid != -1)
729 	{
730 		if (!forked)
731 		{
732 			if (flags & PROC_FOREGROUND)
733 			{
734 				proc->sigint = signal(SIGINT, SIG_IGN);
735 				proc->sigquit = signal(SIGQUIT, SIG_IGN);
736 #if defined(SIGCHLD)
737 				proc->sigchld = signal(SIGCHLD, SIG_DFL);
738 #endif
739 			}
740 		}
741 		else if (modv)
742 			for (i = 0; n = modv[i]; i++)
743 				switch (PROC_OP(n))
744 				{
745 				case PROC_fd_dup|PROC_FD_PARENT:
746 				case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
747 					close(PROC_ARG(n, 1));
748 					break;
749 				case PROC_sys_pgrp:
750 					if (proc->pgrp < 0)
751 						proc->pgrp = proc->pid;
752 					else if (proc->pgrp > 0)
753 					{
754 						if (proc->pgrp == 1)
755 							proc->pgrp = proc->pid;
756 						if (setpgid(proc->pid, proc->pgrp) < 0 && proc->pid != proc->pgrp && errno == EPERM)
757 							setpgid(proc->pid, proc->pid);
758 					}
759 					break;
760 				}
761 		if (procfd >= 0)
762 		{
763 #ifdef SIGPIPE
764 			if ((flags & (PROC_WRITE|PROC_IGNORE)) == (PROC_WRITE|PROC_IGNORE))
765 			{
766 				Handler_t	handler;
767 
768 				if ((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && handler != ignoresig)
769 					signal(SIGPIPE, handler);
770 			}
771 #endif
772 			switch (procfd)
773 			{
774 			case 0:
775 				proc->wfd = pio[1];
776 				close(pio[0]);
777 				break;
778 			default:
779 #if _pipe_rw || _lib_socketpair
780 				proc->wfd = pio[0];
781 #else
782 				proc->wfd = poi[1];
783 				close(poi[0]);
784 #endif
785 				/*FALLTHROUGH*/
786 			case 1:
787 				proc->rfd = pio[0];
788 				close(pio[1]);
789 				break;
790 			}
791 			if (proc->rfd > 2)
792 				fcntl(proc->rfd, F_SETFD, FD_CLOEXEC);
793 			if (proc->wfd > 2)
794 				fcntl(proc->wfd, F_SETFD, FD_CLOEXEC);
795 		}
796 		if (!proc->pid)
797 			proc->pid = getpid();
798 		return proc;
799 	}
800  bad:
801 	if ((flags & PROC_CLEANUP) && modv)
802 		for (i = 0; n = modv[i]; i++)
803 			switch (PROC_OP(n))
804 			{
805 			case PROC_fd_dup:
806 			case PROC_fd_dup|PROC_FD_PARENT:
807 			case PROC_fd_dup|PROC_FD_CHILD:
808 			case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
809 				if (PROC_ARG(n, 2) != PROC_ARG_NULL)
810 					close(PROC_ARG(n, 1));
811 				break;
812 			}
813 	if (pio[0] >= 0)
814 		close(pio[0]);
815 	if (pio[1] >= 0)
816 		close(pio[1]);
817 #if !_pipe_rw && !_lib_socketpair
818 	if (poi[0] >= 0)
819 		close(poi[0]);
820 	if (poi[1] >= 0)
821 		close(poi[1]);
822 #endif
823 	procfree(proc);
824 	return 0;
825 }
826