14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1985-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.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 /*
254887Schin  * spawnveg -- spawnve with process group or session control
264887Schin  *
274887Schin  *	pgid	<0	setsid()	[session group leader]
284887Schin  *		 0	nothing		[retain session and process group]
294887Schin  *		 1	setpgid(0,0)	[process group leader]
304887Schin  *		>1	setpgid(0,pgid)	[join process group]
314887Schin  */
324887Schin 
334887Schin #include <ast.h>
344887Schin 
354887Schin #if _lib_spawnveg
364887Schin 
374887Schin NoN(spawnveg)
384887Schin 
394887Schin #else
404887Schin 
414887Schin #if _lib_posix_spawn > 1	/* reports underlying exec() errors */
424887Schin 
434887Schin #include <spawn.h>
444887Schin #include <error.h>
454887Schin #include <wait.h>
464887Schin 
474887Schin pid_t
484887Schin spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
494887Schin {
504887Schin 	int			err;
514887Schin 	pid_t			pid;
524887Schin 	posix_spawnattr_t	attr;
534887Schin 
544887Schin 	if (err = posix_spawnattr_init(&attr))
554887Schin 		goto bad;
564887Schin 	if (pgid)
574887Schin 	{
584887Schin 		if (pgid <= 1)
594887Schin 			pgid = 0;
604887Schin 		if (err = posix_spawnattr_setpgroup(&attr, pgid))
614887Schin 			goto bad;
624887Schin 		if (err = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP))
634887Schin 			goto bad;
644887Schin 	}
654887Schin 	if (err = posix_spawn(&pid, path, NiL, &attr, argv, envv ? envv : environ))
664887Schin 		goto bad;
674887Schin 	posix_spawnattr_destroy(&attr);
684887Schin #if _lib_posix_spawn < 2
694887Schin 	if (waitpid(pid, &err, WNOHANG|WNOWAIT) == pid && EXIT_STATUS(err) == 127)
704887Schin 	{
714887Schin 		while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
724887Schin 		if (!access(path, X_OK))
734887Schin 			errno = ENOEXEC;
744887Schin 		pid = -1;
754887Schin 	}
764887Schin #endif
774887Schin 	return pid;
784887Schin  bad:
794887Schin 	errno = err;
804887Schin 	return -1;
814887Schin }
824887Schin 
834887Schin #else
844887Schin 
854887Schin #if _lib_spawn_mode
864887Schin 
874887Schin #include <process.h>
884887Schin 
894887Schin #ifndef P_NOWAIT
904887Schin #define P_NOWAIT	_P_NOWAIT
914887Schin #endif
924887Schin #ifndef P_DETACH
934887Schin #define P_DETACH	_P_DETACH
944887Schin #endif
954887Schin 
964887Schin pid_t
974887Schin spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
984887Schin {
994887Schin 	return spawnve(pgid ? P_DETACH : P_NOWAIT, path, argv, envv ? envv : environ);
1004887Schin }
1014887Schin 
1024887Schin #else
1034887Schin 
1044887Schin #if _lib_spawn && _hdr_spawn && _mem_pgroup_inheritance
1054887Schin 
1064887Schin #include <spawn.h>
1074887Schin 
1084887Schin /*
1094887Schin  * open-edition/mvs/zos fork+exec+(setpgid)
1104887Schin  */
1114887Schin 
1124887Schin pid_t
1134887Schin spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
1144887Schin {
1154887Schin 	struct inheritance	inherit;
1164887Schin 
1174887Schin 	inherit.flags = 0;
1184887Schin 	if (pgid)
1194887Schin 	{
1204887Schin 		inherit.flags |= SPAWN_SETGROUP;
1214887Schin 		inherit.pgroup = (pgid > 1) ? pgid : SPAWN_NEWPGROUP;
1224887Schin 	}
1234887Schin 	return spawn(path, 0, (int*)0, &inherit, (const char**)argv, (const char**)envv);
1244887Schin }
1254887Schin 
1264887Schin #else
1274887Schin 
1284887Schin #include <error.h>
1294887Schin #include <wait.h>
1304887Schin #include <sig.h>
1314887Schin #include <ast_vfork.h>
1324887Schin 
1334887Schin #ifndef ENOSYS
1344887Schin #define ENOSYS	EINVAL
1354887Schin #endif
1364887Schin 
1374887Schin #if _lib_spawnve && _hdr_process
1384887Schin #include <process.h>
1394887Schin #if defined(P_NOWAIT) || defined(_P_NOWAIT)
1404887Schin #undef	_lib_spawnve
1414887Schin #endif
1424887Schin #endif
1434887Schin 
1444887Schin #if !_lib_vfork
1454887Schin #undef	_real_vfork
1464887Schin #endif
1474887Schin 
1484887Schin /*
1494887Schin  * fork+exec+(setsid|setpgid)
1504887Schin  */
1514887Schin 
1524887Schin pid_t
1534887Schin spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
1544887Schin {
1554887Schin #if _lib_fork || _lib_vfork
1564887Schin 	int			n;
1574887Schin 	int			m;
1584887Schin 	pid_t			pid;
1594887Schin 	pid_t			rid;
1604887Schin #if _real_vfork
1614887Schin 	volatile int		exec_errno;
1624887Schin 	volatile int* volatile	exec_errno_ptr;
1634887Schin #else
1644887Schin 	int			err[2];
1654887Schin #endif
1664887Schin #endif
1674887Schin 
1684887Schin #if 0
1694887Schin 	if (access(path, X_OK))
1704887Schin 		return -1;
1714887Schin #endif
1724887Schin 	if (!envv)
1734887Schin 		envv = environ;
1744887Schin #if _lib_spawnve
1754887Schin #if _lib_fork || _lib_vfork
1764887Schin 	if (!pgid)
1774887Schin #endif
1784887Schin 		return spawnve(path, argv, envv);
1794887Schin #endif
1804887Schin #if _lib_fork || _lib_vfork
1814887Schin 	n = errno;
1824887Schin #if _real_vfork
1834887Schin 	exec_errno = 0;
1844887Schin 	exec_errno_ptr = &exec_errno;
1854887Schin #else
1864887Schin 	if (pipe(err) < 0)
1874887Schin 		err[0] = -1;
1884887Schin 	else
1894887Schin 	{
1904887Schin 		fcntl(err[0], F_SETFD, FD_CLOEXEC);
1914887Schin 		fcntl(err[1], F_SETFD, FD_CLOEXEC);
1924887Schin 	}
1934887Schin #endif
1944887Schin 	sigcritical(1);
1954887Schin #if _lib_vfork
1964887Schin 	pid = vfork();
1974887Schin #else
1984887Schin 	pid = fork();
1994887Schin #endif
2004887Schin 	sigcritical(0);
201*8462SApril.Chin@Sun.COM 	if (pid == -1)
202*8462SApril.Chin@Sun.COM 		n = errno;
203*8462SApril.Chin@Sun.COM 	else if (!pid)
2044887Schin 	{
2054887Schin 		if (pgid < 0)
2064887Schin 			setsid();
2074887Schin 		else if (pgid > 0)
2084887Schin 		{
2094887Schin 			if (pgid == 1)
2104887Schin 				pgid = 0;
2114887Schin 			if (setpgid(0, pgid) < 0 && pgid && errno == EPERM)
2124887Schin 				setpgid(0, 0);
2134887Schin 		}
2144887Schin 		execve(path, argv, envv);
2154887Schin #if _real_vfork
2164887Schin 		*exec_errno_ptr = errno;
2174887Schin #else
2184887Schin 		if (err[0] != -1)
2194887Schin 		{
2204887Schin 			n = errno;
2214887Schin 			write(err[1], &n, sizeof(n));
2224887Schin 		}
2234887Schin #endif
2244887Schin 		_exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
2254887Schin 	}
2264887Schin 	rid = pid;
2274887Schin #if _real_vfork
2284887Schin 	if (pid != -1 && (m = *exec_errno_ptr))
2294887Schin 	{
2304887Schin 		while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
2314887Schin 		rid = pid = -1;
2324887Schin 		n = m;
2334887Schin 	}
2344887Schin #else
235*8462SApril.Chin@Sun.COM 	if (err[0] != -1)
2364887Schin 	{
2374887Schin 		close(err[1]);
238*8462SApril.Chin@Sun.COM 		if (pid != -1 && read(err[0], &m, sizeof(m)) == sizeof(m) && m)
2394887Schin 		{
2404887Schin 			while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
2414887Schin 			rid = pid = -1;
2424887Schin 			n = m;
2434887Schin 		}
2444887Schin 		close(err[0]);
2454887Schin 	}
2464887Schin #endif
2474887Schin 	if (pid != -1 && pgid > 0)
2484887Schin 	{
2494887Schin 		/*
2504887Schin 		 * parent and child are in a race here
2514887Schin 		 */
2524887Schin 
2534887Schin 		if (pgid == 1)
2544887Schin 			pgid = pid;
2554887Schin 		if (setpgid(pid, pgid) < 0 && pid != pgid && errno == EPERM)
2564887Schin 			setpgid(pid, pid);
2574887Schin 	}
2584887Schin 	errno = n;
2594887Schin 	return rid;
2604887Schin #else
2614887Schin 	errno = ENOSYS;
2624887Schin 	return -1;
2634887Schin #endif
2644887Schin }
2654887Schin 
2664887Schin #endif
2674887Schin 
2684887Schin #endif
2694887Schin 
2704887Schin #endif
2714887Schin 
2724887Schin #endif
273