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