xref: /onnv-gate/usr/src/lib/libast/common/misc/procopen.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * Glenn Fowler
254887Schin  * AT&T Research
264887Schin  *
274887Schin  * common process execution support with
284887Schin  * proper sfio, signal and wait() syncronization
294887Schin  *
304887Schin  * _ contains the process path name and is
314887Schin  * placed at the top of the environment
324887Schin  */
334887Schin 
344887Schin #include "proclib.h"
354887Schin 
364887Schin #include <ls.h>
374887Schin 
384887Schin /*
394887Schin  * not quite ready for _use_spawnveg
404887Schin  */
414887Schin 
424887Schin #if _use_spawnveg && _lib_fork
434887Schin #undef	_use_spawnveg
444887Schin #endif
454887Schin 
464887Schin #ifndef DEBUG_PROC
474887Schin #define DEBUG_PROC	1
484887Schin #endif
494887Schin 
504887Schin #if _lib_socketpair
514887Schin #if _sys_socket
524887Schin #include <sys/types.h>
534887Schin #include <sys/socket.h>
544887Schin #else
554887Schin #undef	_lib_socketpair
564887Schin #endif
574887Schin #endif
584887Schin 
594887Schin Proc_t			proc_default = { -1 };
604887Schin 
614887Schin #if DEBUG_PROC
624887Schin 
634887Schin #include <namval.h>
644887Schin 
654887Schin #define PROC_ENV_OPTIONS	"PROC_OPTIONS"
664887Schin 
674887Schin #define PROC_OPT_ENVIRONMENT	(1<<0)
684887Schin #define PROC_OPT_EXEC		(1<<1)
694887Schin #define PROC_OPT_TRACE		(1<<2)
704887Schin #define PROC_OPT_VERBOSE	(1<<3)
714887Schin 
724887Schin static const Namval_t		options[] =
734887Schin {
744887Schin 	"debug",	PROC_OPT_VERBOSE,
754887Schin 	"environment",	PROC_OPT_ENVIRONMENT,
764887Schin 	"exec",		PROC_OPT_EXEC,
774887Schin 	"trace",	PROC_OPT_TRACE,
784887Schin 	"verbose",	PROC_OPT_VERBOSE,
794887Schin 	0,		0
804887Schin };
814887Schin 
824887Schin /*
834887Schin  * called by stropt() to set options
844887Schin  */
854887Schin 
864887Schin static int
setopt(register void * a,register const void * p,register int n,const char * v)874887Schin setopt(register void* a, register const void* p, register int n, const char* v)
884887Schin {
894887Schin 	NoP(v);
904887Schin 	if (p)
914887Schin 	{
924887Schin 		if (n)
934887Schin 			*((int*)a) |= ((Namval_t*)p)->value;
944887Schin 		else
954887Schin 			*((int*)a) &= ~((Namval_t*)p)->value;
964887Schin 	}
974887Schin 	return 0;
984887Schin }
994887Schin 
1004887Schin #endif
1014887Schin 
1024887Schin #if _use_spawnveg
1034887Schin 
1044887Schin typedef struct Fd_s
1054887Schin {
1064887Schin 	short		fd;
1074887Schin 	short		flag;
1084887Schin } Fd_t;
1094887Schin 
1104887Schin typedef struct Mod_s
1114887Schin {
1124887Schin 	struct Mod_s*	next;
1134887Schin 	short		op;
1144887Schin 	short		save;
1154887Schin 
1164887Schin 	union
1174887Schin 	{
1184887Schin 
1194887Schin 	struct
1204887Schin 	{
1214887Schin 	Fd_t		parent;
1224887Schin 	Fd_t		child;
1234887Schin 	}		fd;
1244887Schin 
1254887Schin 	Handler_t	handler;
1264887Schin 
1274887Schin 	}		arg;
1284887Schin 
1294887Schin } Modify_t;
1304887Schin 
1314887Schin #endif
1324887Schin 
1334887Schin #ifdef SIGPIPE
1344887Schin 
1354887Schin /*
1364887Schin  * catch but ignore sig
1374887Schin  * avoids SIG_IGN being passed to children
1384887Schin  */
1394887Schin 
1404887Schin static void
ignoresig(int sig)1414887Schin ignoresig(int sig)
1424887Schin {
1434887Schin 	signal(sig, ignoresig);
1444887Schin }
1454887Schin 
1464887Schin #endif
1474887Schin 
1484887Schin /*
1494887Schin  * do modification op and save previous state for restore()
1504887Schin  */
1514887Schin 
1524887Schin static int
modify(Proc_t * proc,int forked,int op,long arg1,long arg2)1534887Schin modify(Proc_t* proc, int forked, int op, long arg1, long arg2)
1544887Schin {
1554887Schin #if _lib_fork
1564887Schin 	if (forked)
1574887Schin 	{
1584887Schin 		switch (op)
1594887Schin 		{
1604887Schin 		case PROC_fd_dup:
1614887Schin 		case PROC_fd_dup|PROC_FD_PARENT:
1624887Schin 		case PROC_fd_dup|PROC_FD_CHILD:
1634887Schin 		case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
1644887Schin 			if (arg1 != arg2)
1654887Schin 			{
1664887Schin 				if (arg2 != PROC_ARG_NULL)
1674887Schin 				{
1684887Schin 					close(arg2);
1694887Schin 					if (fcntl(arg1, F_DUPFD, arg2) != arg2)
1704887Schin 						return -1;
1714887Schin 				}
1724887Schin 				if (op & PROC_FD_CHILD)
1734887Schin 					close(arg1);
1744887Schin 			}
1754887Schin 			break;
1764887Schin 		case PROC_sig_dfl:
1774887Schin 			signal(arg1, SIG_DFL);
1784887Schin 			break;
1794887Schin 		case PROC_sig_ign:
1804887Schin 			signal(arg1, SIG_IGN);
1814887Schin 			break;
1824887Schin 		case PROC_sys_pgrp:
1834887Schin 			if (arg1 < 0)
1844887Schin 				setsid();
1854887Schin 			else if (arg1 > 0)
1864887Schin 			{
1874887Schin 				if (arg1 == 1)
1884887Schin 					arg1 = 0;
1894887Schin 				if (setpgid(0, arg1) < 0 && arg1 && errno == EPERM)
1904887Schin 					setpgid(0, 0);
1914887Schin 			}
1924887Schin 			break;
1934887Schin 		case PROC_sys_umask:
1944887Schin 			umask(arg1);
1954887Schin 			break;
1964887Schin 		default:
1974887Schin 			return -1;
1984887Schin 		}
1994887Schin 	}
2004887Schin #if _use_spawnveg
2014887Schin 	else
2024887Schin #endif
2034887Schin #else
2044887Schin 	NoP(forked);
2054887Schin #endif
2064887Schin #if _use_spawnveg
2074887Schin 	{
2084887Schin 		register Modify_t*	m;
2094887Schin 
2104887Schin 		if (!(m = newof(NiL, Modify_t, 1, 0)))
2114887Schin 			return -1;
2124887Schin 		m->next = proc->mods;
2134887Schin 		proc->mods = m;
2144887Schin 		switch (m->op = op)
2154887Schin 		{
2164887Schin 		case PROC_fd_dup:
2174887Schin 		case PROC_fd_dup|PROC_FD_PARENT:
2184887Schin 		case PROC_fd_dup|PROC_FD_CHILD:
2194887Schin 		case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
2204887Schin 			m->arg.fd.parent.fd = (short)arg1;
2214887Schin 			m->arg.fd.parent.flag = fcntl(arg1, F_GETFD, 0);
2224887Schin 			if ((m->arg.fd.child.fd = (short)arg2) != arg1)
2234887Schin 			{
2244887Schin 				if (arg2 != PROC_ARG_NULL)
2254887Schin 				{
2264887Schin 					m->arg.fd.child.flag = fcntl(arg2, F_GETFD, 0);
2274887Schin 					if ((m->save = fcntl(arg2, F_DUPFD, 3)) < 0)
2284887Schin 					{
2294887Schin 						m->op = 0;
2304887Schin 						return -1;
2314887Schin 					}
2324887Schin 					fcntl(m->save, F_SETFD, FD_CLOEXEC);
2334887Schin 					close(arg2);
2344887Schin 					if (fcntl(arg1, F_DUPFD, arg2) != arg2)
2354887Schin 						return -1;
2364887Schin 					if (op & PROC_FD_CHILD)
2374887Schin 						close(arg1);
2384887Schin 				}
2394887Schin 				else if (op & PROC_FD_CHILD)
2404887Schin 				{
2414887Schin 					if (m->arg.fd.parent.flag)
2424887Schin 						break;
2434887Schin 					fcntl(arg1, F_SETFD, FD_CLOEXEC);
2444887Schin 				}
2454887Schin 				else if (!m->arg.fd.parent.flag)
2464887Schin 					break;
2474887Schin 				else
2484887Schin 					fcntl(arg1, F_SETFD, 0);
2494887Schin 				return 0;
2504887Schin 			}
2514887Schin 			break;
2524887Schin 		case PROC_sig_dfl:
2534887Schin 			if ((m->arg.handler = signal(arg1, SIG_DFL)) == SIG_DFL)
2544887Schin 				break;
2554887Schin 			m->save = (short)arg1;
2564887Schin 			return 0;
2574887Schin 		case PROC_sig_ign:
2584887Schin 			if ((m->arg.handler = signal(arg1, SIG_IGN)) == SIG_IGN)
2594887Schin 				break;
2604887Schin 			m->save = (short)arg1;
2614887Schin 			return 0;
2624887Schin 		case PROC_sys_pgrp:
2634887Schin 			proc->pgrp = arg1;
2644887Schin 			break;
2654887Schin 		case PROC_sys_umask:
2664887Schin 			if ((m->save = (short)umask(arg1)) == arg1)
2674887Schin 				break;
2684887Schin 			return 0;
2694887Schin 		default:
2704887Schin 			proc->mods = m->next;
2714887Schin 			free(m);
2724887Schin 			return -1;
2734887Schin 		}
2744887Schin 		proc->mods = m->next;
2754887Schin 		free(m);
2764887Schin 	}
2774887Schin #else
2784887Schin 	NoP(proc);
2794887Schin #endif
2804887Schin 	return 0;
2814887Schin }
2824887Schin 
2834887Schin #if _use_spawnveg
2844887Schin 
2854887Schin /*
2864887Schin  * restore modifications
2874887Schin  */
2884887Schin 
2894887Schin static void
restore(Proc_t * proc)2904887Schin restore(Proc_t* proc)
2914887Schin {
2924887Schin 	register Modify_t*	m;
2934887Schin 	register Modify_t*	p;
2944887Schin 	int			oerrno;
2954887Schin 
2964887Schin 	NoP(proc);
2974887Schin 	oerrno = errno;
2984887Schin 	m = proc->mods;
2994887Schin 	proc->mods = 0;
3004887Schin 	while (m)
3014887Schin 	{
3024887Schin 		switch (m->op)
3034887Schin 		{
3044887Schin 		case PROC_fd_dup:
3054887Schin 		case PROC_fd_dup|PROC_FD_PARENT:
3064887Schin 		case PROC_fd_dup|PROC_FD_CHILD:
3074887Schin 		case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
3084887Schin 			if (m->op & PROC_FD_PARENT)
3094887Schin 				close(m->arg.fd.parent.fd);
3104887Schin 			if (m->arg.fd.child.fd != m->arg.fd.parent.fd && m->arg.fd.child.fd != PROC_ARG_NULL)
3114887Schin 			{
3124887Schin 				if (!(m->op & PROC_FD_PARENT))
3134887Schin 				{
3144887Schin 					if (m->op & PROC_FD_CHILD)
3154887Schin 					{
3164887Schin 						close(m->arg.fd.parent.fd);
3174887Schin 						fcntl(m->arg.fd.child.fd, F_DUPFD, m->arg.fd.parent.fd);
3184887Schin 					}
3194887Schin 					fcntl(m->arg.fd.parent.fd, F_SETFD, m->arg.fd.parent.flag);
3204887Schin 				}
3214887Schin 				close(m->arg.fd.child.fd);
3224887Schin 				fcntl(m->save, F_DUPFD, m->arg.fd.child.fd);
3234887Schin 				close(m->save);
3244887Schin 				if (m->arg.fd.child.flag)
3254887Schin 					fcntl(m->arg.fd.child.fd, F_SETFD, FD_CLOEXEC);
3264887Schin 			}
3274887Schin 			else if ((m->op & (PROC_FD_PARENT|PROC_FD_CHILD)) == PROC_FD_CHILD)
3284887Schin 				fcntl(m->arg.fd.parent.fd, F_SETFD, 0);
3294887Schin 			break;
3304887Schin 		case PROC_sig_dfl:
3314887Schin 		case PROC_sig_ign:
3324887Schin 			signal(m->save, m->arg.handler);
3334887Schin 			break;
3344887Schin 		case PROC_sys_umask:
3354887Schin 			umask(m->save);
3364887Schin 			break;
3374887Schin 		}
3384887Schin 		p = m;
3394887Schin 		m = m->next;
3404887Schin 		free(p);
3414887Schin 	}
3424887Schin 	errno = oerrno;
3434887Schin }
3444887Schin 
3454887Schin #else
3464887Schin 
3474887Schin #define restore(p)
3484887Schin 
3494887Schin #endif
3504887Schin 
3514887Schin /*
3524887Schin  * fork and exec or spawn proc(argv) and return a Proc_t handle
3534887Schin  *
3544887Schin  * pipe not used when PROC_READ|PROC_WRITE omitted
3554887Schin  * argv==0 duplicates current process if possible
3564887Schin  * cmd==0 names the current shell
3574887Schin  * cmd=="" does error cleanup
3584887Schin  * envv is the child environment
3594887Schin  * modv is the child modification vector of PROC_*() ops
3604887Schin  */
3614887Schin 
3624887Schin Proc_t*
procopen(const char * cmd,char ** argv,char ** envv,long * modv,int flags)3638462SApril.Chin@Sun.COM procopen(const char* cmd, char** argv, char** envv, long* modv, int flags)
3644887Schin {
3654887Schin 	register Proc_t*	proc = 0;
3664887Schin 	register int		procfd;
3674887Schin 	register char**		p;
3684887Schin 	char**			v;
3694887Schin 	int			i;
3704887Schin 	int			forked = 0;
3718462SApril.Chin@Sun.COM 	int			signalled = 0;
3724887Schin 	long			n;
3734887Schin 	char			path[PATH_MAX];
3744887Schin 	char			env[PATH_MAX + 2];
3754887Schin 	int			pio[2];
3764887Schin #if !_pipe_rw && !_lib_socketpair
3774887Schin 	int			poi[2];
3784887Schin #endif
3794887Schin #if defined(SIGCHLD) && ( _lib_sigprocmask || _lib_sigsetmask )
3804887Schin 	Sig_mask_t		mask;
3814887Schin #endif
3824887Schin #if _use_spawnveg
3834887Schin 	int			newenv = 0;
3844887Schin #endif
3854887Schin #if DEBUG_PROC
3864887Schin 	int			debug = PROC_OPT_EXEC;
3874887Schin #endif
3884887Schin 
3894887Schin #if _lib_fork
3904887Schin 	if (!argv && (flags & PROC_OVERLAY))
3914887Schin #else
3924887Schin 	if (!argv)
3934887Schin #endif
3944887Schin 	{
3954887Schin 		errno = ENOEXEC;
3964887Schin 		return 0;
3974887Schin 	}
3984887Schin 	pio[0] = pio[1] = -1;
3994887Schin #if !_pipe_rw && !_lib_socketpair
4004887Schin 	poi[0] = poi[1] = -1;
4014887Schin #endif
4024887Schin 	if (cmd && (!*cmd || !pathpath(path, cmd, NiL, PATH_REGULAR|PATH_EXECUTE)))
4034887Schin 		goto bad;
4044887Schin 	switch (flags & (PROC_READ|PROC_WRITE))
4054887Schin 	{
4064887Schin 	case 0:
4074887Schin 		procfd = -1;
4084887Schin 		break;
4094887Schin 	case PROC_READ:
4104887Schin 		procfd = 1;
4114887Schin 		break;
4124887Schin 	case PROC_WRITE:
4134887Schin 		procfd = 0;
4144887Schin 		break;
4154887Schin 	case PROC_READ|PROC_WRITE:
4164887Schin 		procfd = 2;
4174887Schin 		break;
4184887Schin 	}
4194887Schin 	if (proc_default.pid == -1)
4204887Schin 		proc = &proc_default;
4214887Schin 	else if (!(proc = newof(0, Proc_t, 1, 0)))
4224887Schin 		goto bad;
4234887Schin 	proc->pid = -1;
4244887Schin 	proc->pgrp = 0;
4254887Schin 	proc->rfd = -1;
4264887Schin 	proc->wfd = -1;
4274887Schin 	proc->flags = flags;
4284887Schin 	sfsync(NiL);
4294887Schin 	if (environ && envv != (char**)environ && (envv || (flags & PROC_PARANOID) || argv && (environ[0][0] != '_' || environ[0][1] != '=')))
4304887Schin 	{
4314887Schin 		if (!setenviron(NiL))
4324887Schin 			goto bad;
4334887Schin #if _use_spawnveg
4344887Schin 		newenv = 1;
4354887Schin #endif
4364887Schin 	}
4374887Schin 	if (procfd >= 0)
4384887Schin 	{
4394887Schin #if _pipe_rw
4404887Schin 		if (pipe(pio))
4414887Schin 			goto bad;
4424887Schin #else
4434887Schin 		if (procfd > 1)
4444887Schin 		{
4454887Schin #if _lib_socketpair
4464887Schin 			if (socketpair(AF_UNIX, SOCK_STREAM, 0, pio))
4474887Schin 				goto bad;
4484887Schin #else
4494887Schin 			if (pipe(pio) || pipe(poi))
4504887Schin 				goto bad;
4514887Schin #endif
4524887Schin 		}
4534887Schin 		else if (pipe(pio))
4544887Schin 			goto bad;
4554887Schin #endif
4564887Schin 	}
4574887Schin 	if (flags & PROC_OVERLAY)
4584887Schin 	{
4594887Schin 		proc->pid = 0;
4604887Schin 		forked = 1;
4614887Schin 	}
4624887Schin #if _use_spawnveg
4634887Schin 	else if (argv)
4644887Schin 		proc->pid = 0;
4654887Schin #endif
4664887Schin #if _lib_fork
4674887Schin 	else
4684887Schin 	{
4694887Schin 		if (!(flags & PROC_FOREGROUND))
4704887Schin 			sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
4714887Schin 		else
4724887Schin 		{
4738462SApril.Chin@Sun.COM 			signalled = 1;
4744887Schin 			proc->sigint = signal(SIGINT, SIG_IGN);
4754887Schin 			proc->sigquit = signal(SIGQUIT, SIG_IGN);
4764887Schin #if defined(SIGCHLD)
4774887Schin #if _lib_sigprocmask
4784887Schin 			sigemptyset(&mask);
4794887Schin 			sigaddset(&mask, SIGCHLD);
4804887Schin 			sigprocmask(SIG_BLOCK, &mask, &proc->mask);
4814887Schin #else
4824887Schin #if _lib_sigsetmask
4834887Schin 			mask = sigmask(SIGCHLD);
4844887Schin 			proc->mask = sigblock(mask);
4858462SApril.Chin@Sun.COM #else
4868462SApril.Chin@Sun.COM 			proc->sigchld = signal(SIGCHLD, SIG_DFL);
4874887Schin #endif
4884887Schin #endif
4894887Schin #endif
4904887Schin 		}
4914887Schin 		proc->pid = fork();
4924887Schin 		if (!(flags & PROC_FOREGROUND))
4934887Schin 			sigcritical(0);
4944887Schin 		else if (!proc->pid)
4954887Schin 		{
4964887Schin 			if (proc->sigint != SIG_IGN)
4978462SApril.Chin@Sun.COM 			{
4984887Schin 				proc->sigint = SIG_DFL;
4998462SApril.Chin@Sun.COM 				signal(SIGINT, proc->sigint);
5008462SApril.Chin@Sun.COM 			}
5014887Schin 			if (proc->sigquit != SIG_IGN)
5028462SApril.Chin@Sun.COM 			{
5034887Schin 				proc->sigquit = SIG_DFL;
5048462SApril.Chin@Sun.COM 				signal(SIGQUIT, proc->sigquit);
5058462SApril.Chin@Sun.COM 			}
5064887Schin #if defined(SIGCHLD)
5078462SApril.Chin@Sun.COM #if _lib_sigprocmask
5088462SApril.Chin@Sun.COM 			sigprocmask(SIG_SETMASK, &proc->mask, NiL);
5098462SApril.Chin@Sun.COM #else
5108462SApril.Chin@Sun.COM #if _lib_sigsetmask
5118462SApril.Chin@Sun.COM 			sigsetmask(proc->mask);
5128462SApril.Chin@Sun.COM #else
5134887Schin 			if (proc->sigchld != SIG_IGN)
5148462SApril.Chin@Sun.COM 				signal(SIGCHLD, SIG_DFL);
5158462SApril.Chin@Sun.COM #endif
5168462SApril.Chin@Sun.COM #endif
5174887Schin #endif
5184887Schin 		}
5198462SApril.Chin@Sun.COM 		else if (proc->pid == -1)
5204887Schin 			goto bad;
5214887Schin 		forked = 1;
5224887Schin 	}
5234887Schin #endif
5244887Schin 	if (!proc->pid)
5254887Schin 	{
5264887Schin #if _use_spawnveg
5274887Schin 		char**		oenviron = 0;
5284887Schin 		char*		oenviron0 = 0;
5294887Schin 
5304887Schin 		v = 0;
5314887Schin #endif
5324887Schin #if DEBUG_PROC
5334887Schin 		stropt(getenv(PROC_ENV_OPTIONS), options, sizeof(*options), setopt, &debug);
5344887Schin #if _lib_fork
5354887Schin 		if (debug & PROC_OPT_TRACE)
5364887Schin 		{
5374887Schin 			if (!fork())
5384887Schin 			{
5394887Schin 				sfsprintf(path, sizeof(path), "%d", getppid());
5404887Schin 				execlp("trace", "trace", "-p", path, NiL);
5414887Schin 				_exit(EXIT_NOTFOUND);
5424887Schin 			}
5434887Schin 			sleep(2);
5444887Schin 		}
5454887Schin #endif
5464887Schin #endif
5474887Schin 		if (flags & PROC_DAEMON)
5484887Schin 		{
5494887Schin #ifdef SIGHUP
5504887Schin 			modify(proc, forked, PROC_sig_ign, SIGHUP, 0);
5514887Schin #endif
5524887Schin 			modify(proc, forked, PROC_sig_dfl, SIGTERM, 0);
5534887Schin #ifdef SIGTSTP
5544887Schin 			modify(proc, forked, PROC_sig_ign, SIGTSTP, 0);
5554887Schin #endif
5564887Schin #ifdef SIGTTIN
5574887Schin 			modify(proc, forked, PROC_sig_ign, SIGTTIN, 0);
5584887Schin #endif
5594887Schin #ifdef SIGTTOU
5604887Schin 			modify(proc, forked, PROC_sig_ign, SIGTTOU, 0);
5614887Schin #endif
5624887Schin 		}
5634887Schin 		if (flags & (PROC_BACKGROUND|PROC_DAEMON))
5644887Schin 		{
5654887Schin 			modify(proc, forked, PROC_sig_ign, SIGINT, 0);
5664887Schin #ifdef SIGQUIT
5674887Schin 			modify(proc, forked, PROC_sig_ign, SIGQUIT, 0);
5684887Schin #endif
5694887Schin 		}
5704887Schin 		if (flags & (PROC_DAEMON|PROC_SESSION))
5714887Schin 			modify(proc, forked, PROC_sys_pgrp, -1, 0);
5724887Schin 		if (forked || (flags & PROC_OVERLAY))
5734887Schin 		{
5744887Schin 			if ((flags & PROC_PRIVELEGED) && !geteuid())
5754887Schin 			{
5764887Schin 				setuid(geteuid());
5774887Schin 				setgid(getegid());
5784887Schin 			}
5794887Schin 			if (flags & (PROC_PARANOID|PROC_GID))
5804887Schin 				setgid(getgid());
5814887Schin 			if (flags & (PROC_PARANOID|PROC_UID))
5824887Schin 				setuid(getuid());
5834887Schin 		}
5844887Schin 		if (procfd > 1)
5854887Schin 		{
5864887Schin 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[0], PROC_ARG_NULL))
5874887Schin 				goto cleanup;
5884887Schin 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[1], 1))
5894887Schin 				goto cleanup;
5904887Schin #if _pipe_rw || _lib_socketpair
5914887Schin 			if (modify(proc, forked, PROC_fd_dup, 1, 0))
5924887Schin 				goto cleanup;
5934887Schin #else
5944887Schin 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[0], 0))
5954887Schin 				goto cleanup;
5964887Schin 			if (poi[1] != 0 && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[1], PROC_ARG_NULL))
5974887Schin 				goto cleanup;
5984887Schin #endif
5994887Schin 		}
6004887Schin 		else if (procfd >= 0)
6014887Schin 		{
6024887Schin 			if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!!procfd], !!procfd))
6034887Schin 				goto cleanup;
6044887Schin 			if (pio[!procfd] != !!procfd && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!procfd], PROC_ARG_NULL))
6054887Schin 				goto cleanup;
6064887Schin 		}
6074887Schin 		if (modv)
6084887Schin 			for (i = 0; n = modv[i]; i++)
6094887Schin 				switch (PROC_OP(n))
6104887Schin 				{
6114887Schin 				case PROC_fd_dup:
6124887Schin 				case PROC_fd_dup|PROC_FD_PARENT:
6134887Schin 				case PROC_fd_dup|PROC_FD_CHILD:
6144887Schin 				case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
6154887Schin 					if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), PROC_ARG(n, 2)))
6164887Schin 						goto cleanup;
6174887Schin 					break;
6184887Schin 				default:
6194887Schin 					if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), 0))
6204887Schin 						goto cleanup;
6214887Schin 					break;
6224887Schin 				}
6234887Schin #if _lib_fork
6244887Schin 		if (forked && (flags & PROC_ENVCLEAR))
6254887Schin 			environ = 0;
6264887Schin #if _use_spawnveg
6274887Schin 		else
6284887Schin #endif
6294887Schin #endif
6304887Schin #if _use_spawnveg
6314887Schin 		if (newenv)
6324887Schin 		{
6334887Schin 			p = environ;
6344887Schin 			while (*p++);
6354887Schin 			if (!(oenviron = (char**)memdup(environ, (p - environ) * sizeof(char*))))
6364887Schin 				goto cleanup;
6374887Schin 		}
6384887Schin #endif
6394887Schin 		if (argv && envv != (char**)environ)
6404887Schin 		{
6414887Schin #if _use_spawnveg
6424887Schin 			if (!newenv && environ[0][0] == '_' && environ[0][1] == '=')
6434887Schin 				oenviron0 = environ[0];
6444887Schin #endif
6454887Schin 			env[0] = '_';
6464887Schin 			env[1] = '=';
6474887Schin 			env[2] = 0;
6484887Schin 			if (!setenviron(env))
6494887Schin 				goto cleanup;
6504887Schin 		}
6514887Schin 		if ((flags & PROC_PARANOID) && setenv("PATH", astconf("PATH", NiL, NiL), 1))
6524887Schin 			goto cleanup;
6534887Schin 		if ((p = envv) && p != (char**)environ)
6544887Schin 			while (*p)
6554887Schin 				if (!setenviron(*p++))
6564887Schin 					goto cleanup;
6574887Schin 		p = argv;
6584887Schin #if _lib_fork
6594887Schin 		if (forked && !p)
6604887Schin 			return proc;
6614887Schin #endif
6624887Schin #if DEBUG_PROC
6634887Schin 		if (!(debug & PROC_OPT_EXEC) || (debug & PROC_OPT_VERBOSE))
6644887Schin 		{
6654887Schin 			if ((debug & PROC_OPT_ENVIRONMENT) && (p = environ))
6664887Schin 				while (*p)
6674887Schin 					sfprintf(sfstderr, "%s\n", *p++);
6684887Schin 			sfprintf(sfstderr, "+ %s", cmd ? path : "sh");
6694887Schin 			if ((p = argv) && *p)
6704887Schin 				while (*++p)
6714887Schin 					sfprintf(sfstderr, " %s", *p);
6724887Schin 			sfprintf(sfstderr, "\n");
6734887Schin sfsync(sfstderr);
6744887Schin 			if (!(debug & PROC_OPT_EXEC))
6754887Schin 				_exit(0);
6764887Schin 			p = argv;
6774887Schin 		}
6784887Schin #endif
6794887Schin 		if (cmd)
6804887Schin 		{
6814887Schin 			strcpy(env + 2, path);
6824887Schin 			if (forked || (flags & PROC_OVERLAY))
6834887Schin 				execve(path, p, environ);
6844887Schin #if _use_spawnveg
6854887Schin 			else if ((proc->pid = spawnveg(path, p, environ, proc->pgrp)) != -1)
6864887Schin 				goto cleanup;
6874887Schin #endif
6884887Schin 			if (errno != ENOEXEC)
6894887Schin 				goto cleanup;
6904887Schin 
6914887Schin 			/*
6924887Schin 			 * try cmd as a shell script
6934887Schin 			 */
6944887Schin 
6954887Schin 			if (!(flags & PROC_ARGMOD))
6964887Schin 			{
6974887Schin 				while (*p++);
6984887Schin 				if (!(v = newof(0, char*, p - argv + 2, 0)))
6994887Schin 					goto cleanup;
7004887Schin 				p = v + 2;
7014887Schin 				if (*argv)
7024887Schin 					argv++;
7034887Schin 				while (*p++ = *argv++);
7044887Schin 				p = v + 1;
7054887Schin 			}
7064887Schin 			*p = path;
7074887Schin 			*--p = "sh";
7084887Schin 		}
7094887Schin 		strcpy(env + 2, (flags & PROC_PARANOID) ? astconf("SH", NiL, NiL) : pathshell());
7104887Schin 		if (forked || (flags & PROC_OVERLAY))
7114887Schin 			execve(env + 2, p, environ);
7124887Schin #if _use_spawnveg
7134887Schin 		else
7144887Schin 			proc->pid = spawnveg(env + 2, p, environ, proc->pgrp);
7154887Schin #endif
7164887Schin 	cleanup:
7174887Schin 		if (forked)
7184887Schin 		{
7194887Schin 			if (!(flags & PROC_OVERLAY))
7204887Schin 				_exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
7214887Schin 			goto bad;
7224887Schin 		}
7234887Schin #if _use_spawnveg
7244887Schin 		if (v)
7254887Schin 			free(v);
7264887Schin 		if (p = oenviron)
7274887Schin 		{
7284887Schin 			environ = 0;
7294887Schin 			while (*p)
7304887Schin 				if (!setenviron(*p++))
7314887Schin 					goto bad;
7324887Schin 			free(oenviron);
7334887Schin 		}
7344887Schin 		else if (oenviron0)
7354887Schin 			environ[0] = oenviron0;
7364887Schin 		restore(proc);
7374887Schin 		if (flags & PROC_OVERLAY)
7384887Schin 			exit(0);
7394887Schin #endif
7404887Schin 	}
7414887Schin 	if (proc->pid != -1)
7424887Schin 	{
7434887Schin 		if (!forked)
7444887Schin 		{
7454887Schin 			if (flags & PROC_FOREGROUND)
7464887Schin 			{
7478462SApril.Chin@Sun.COM 				signalled = 1;
7484887Schin 				proc->sigint = signal(SIGINT, SIG_IGN);
7494887Schin 				proc->sigquit = signal(SIGQUIT, SIG_IGN);
7504887Schin #if defined(SIGCHLD)
7518462SApril.Chin@Sun.COM #if _lib_sigprocmask
7528462SApril.Chin@Sun.COM 				sigemptyset(&mask);
7538462SApril.Chin@Sun.COM 				sigaddset(&mask, SIGCHLD);
7548462SApril.Chin@Sun.COM 				sigprocmask(SIG_BLOCK, &mask, &proc->mask);
7558462SApril.Chin@Sun.COM #else
7568462SApril.Chin@Sun.COM #if _lib_sigsetmask
7578462SApril.Chin@Sun.COM 				mask = sigmask(SIGCHLD);
7588462SApril.Chin@Sun.COM 				proc->mask = sigblock(mask);
7598462SApril.Chin@Sun.COM #else
7604887Schin 				proc->sigchld = signal(SIGCHLD, SIG_DFL);
7614887Schin #endif
7628462SApril.Chin@Sun.COM #endif
7638462SApril.Chin@Sun.COM #endif
7644887Schin 			}
7654887Schin 		}
7664887Schin 		else if (modv)
7674887Schin 			for (i = 0; n = modv[i]; i++)
7684887Schin 				switch (PROC_OP(n))
7694887Schin 				{
7704887Schin 				case PROC_fd_dup|PROC_FD_PARENT:
7714887Schin 				case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
7724887Schin 					close(PROC_ARG(n, 1));
7734887Schin 					break;
7744887Schin 				case PROC_sys_pgrp:
7754887Schin 					if (proc->pgrp < 0)
7764887Schin 						proc->pgrp = proc->pid;
7774887Schin 					else if (proc->pgrp > 0)
7784887Schin 					{
7794887Schin 						if (proc->pgrp == 1)
7804887Schin 							proc->pgrp = proc->pid;
7814887Schin 						if (setpgid(proc->pid, proc->pgrp) < 0 && proc->pid != proc->pgrp && errno == EPERM)
7824887Schin 							setpgid(proc->pid, proc->pid);
7834887Schin 					}
7844887Schin 					break;
7854887Schin 				}
7864887Schin 		if (procfd >= 0)
7874887Schin 		{
7884887Schin #ifdef SIGPIPE
7894887Schin 			if ((flags & (PROC_WRITE|PROC_IGNORE)) == (PROC_WRITE|PROC_IGNORE))
7904887Schin 			{
7914887Schin 				Handler_t	handler;
7924887Schin 
7934887Schin 				if ((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && handler != ignoresig)
7944887Schin 					signal(SIGPIPE, handler);
7954887Schin 			}
7964887Schin #endif
7974887Schin 			switch (procfd)
7984887Schin 			{
7994887Schin 			case 0:
8004887Schin 				proc->wfd = pio[1];
8014887Schin 				close(pio[0]);
8024887Schin 				break;
8034887Schin 			default:
8044887Schin #if _pipe_rw || _lib_socketpair
8054887Schin 				proc->wfd = pio[0];
8064887Schin #else
8074887Schin 				proc->wfd = poi[1];
8084887Schin 				close(poi[0]);
8094887Schin #endif
8104887Schin 				/*FALLTHROUGH*/
8114887Schin 			case 1:
8124887Schin 				proc->rfd = pio[0];
8134887Schin 				close(pio[1]);
8144887Schin 				break;
8154887Schin 			}
8164887Schin 			if (proc->rfd > 2)
8174887Schin 				fcntl(proc->rfd, F_SETFD, FD_CLOEXEC);
8184887Schin 			if (proc->wfd > 2)
8194887Schin 				fcntl(proc->wfd, F_SETFD, FD_CLOEXEC);
8204887Schin 		}
8214887Schin 		if (!proc->pid)
8224887Schin 			proc->pid = getpid();
8234887Schin 		return proc;
8244887Schin 	}
8254887Schin  bad:
8268462SApril.Chin@Sun.COM 	if (signalled)
8278462SApril.Chin@Sun.COM 	{
8288462SApril.Chin@Sun.COM 		if (proc->sigint != SIG_IGN)
8298462SApril.Chin@Sun.COM 			signal(SIGINT, proc->sigint);
8308462SApril.Chin@Sun.COM 		if (proc->sigquit != SIG_IGN)
8318462SApril.Chin@Sun.COM 			signal(SIGQUIT, proc->sigquit);
8328462SApril.Chin@Sun.COM #if defined(SIGCHLD)
8338462SApril.Chin@Sun.COM #if _lib_sigprocmask
8348462SApril.Chin@Sun.COM 		sigprocmask(SIG_SETMASK, &proc->mask, NiL);
8358462SApril.Chin@Sun.COM #else
8368462SApril.Chin@Sun.COM #if _lib_sigsetmask
8378462SApril.Chin@Sun.COM 		sigsetmask(proc->mask);
8388462SApril.Chin@Sun.COM #else
8398462SApril.Chin@Sun.COM 		if (proc->sigchld != SIG_DFL)
8408462SApril.Chin@Sun.COM 			signal(SIGCHLD, proc->sigchld);
8418462SApril.Chin@Sun.COM #endif
8428462SApril.Chin@Sun.COM #endif
8438462SApril.Chin@Sun.COM #endif
8448462SApril.Chin@Sun.COM 	}
8454887Schin 	if ((flags & PROC_CLEANUP) && modv)
8464887Schin 		for (i = 0; n = modv[i]; i++)
8474887Schin 			switch (PROC_OP(n))
8484887Schin 			{
8494887Schin 			case PROC_fd_dup:
8504887Schin 			case PROC_fd_dup|PROC_FD_PARENT:
8514887Schin 			case PROC_fd_dup|PROC_FD_CHILD:
8524887Schin 			case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
8534887Schin 				if (PROC_ARG(n, 2) != PROC_ARG_NULL)
8544887Schin 					close(PROC_ARG(n, 1));
8554887Schin 				break;
8564887Schin 			}
8574887Schin 	if (pio[0] >= 0)
8584887Schin 		close(pio[0]);
8594887Schin 	if (pio[1] >= 0)
8604887Schin 		close(pio[1]);
8614887Schin #if !_pipe_rw && !_lib_socketpair
8624887Schin 	if (poi[0] >= 0)
8634887Schin 		close(poi[0]);
8644887Schin 	if (poi[1] >= 0)
8654887Schin 		close(poi[1]);
8664887Schin #endif
8674887Schin 	procfree(proc);
8684887Schin 	return 0;
8694887Schin }
870