xref: /onnv-gate/usr/src/lib/libc/port/threads/spawn.c (revision 11913:283e725df792)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52248Sraf  * Common Development and Distribution License (the "License").
62248Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
212248Sraf 
220Sstevel@tonic-gate /*
2311798SRoger.Faulkner@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include "lint.h"
280Sstevel@tonic-gate #include "thr_uberdata.h"
293086Sraf #include <sys/libc_kernel.h>
300Sstevel@tonic-gate #include <sys/procset.h>
313235Sraf #include <sys/fork.h>
328877SRoger.Faulkner@Sun.COM #include <dirent.h>
330Sstevel@tonic-gate #include <alloca.h>
340Sstevel@tonic-gate #include <spawn.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #define	ALL_POSIX_SPAWN_FLAGS			\
370Sstevel@tonic-gate 		(POSIX_SPAWN_RESETIDS |		\
380Sstevel@tonic-gate 		POSIX_SPAWN_SETPGROUP |		\
390Sstevel@tonic-gate 		POSIX_SPAWN_SETSIGDEF |		\
400Sstevel@tonic-gate 		POSIX_SPAWN_SETSIGMASK |	\
410Sstevel@tonic-gate 		POSIX_SPAWN_SETSCHEDPARAM |	\
423235Sraf 		POSIX_SPAWN_SETSCHEDULER |	\
437930SRoger.Faulkner@Sun.COM 		POSIX_SPAWN_SETSIGIGN_NP |	\
443235Sraf 		POSIX_SPAWN_NOSIGCHLD_NP |	\
457635SRoger.Faulkner@Sun.COM 		POSIX_SPAWN_WAITPID_NP |	\
467635SRoger.Faulkner@Sun.COM 		POSIX_SPAWN_NOEXECERR_NP)
470Sstevel@tonic-gate 
480Sstevel@tonic-gate typedef struct {
496247Sraf 	int		sa_psflags;	/* POSIX_SPAWN_* flags */
506247Sraf 	int		sa_priority;
510Sstevel@tonic-gate 	int		sa_schedpolicy;
520Sstevel@tonic-gate 	pid_t		sa_pgroup;
530Sstevel@tonic-gate 	sigset_t	sa_sigdefault;
547930SRoger.Faulkner@Sun.COM 	sigset_t	sa_sigignore;
550Sstevel@tonic-gate 	sigset_t	sa_sigmask;
560Sstevel@tonic-gate } spawn_attr_t;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate typedef struct file_attr {
590Sstevel@tonic-gate 	struct file_attr *fa_next;	/* circular list of file actions */
600Sstevel@tonic-gate 	struct file_attr *fa_prev;
618877SRoger.Faulkner@Sun.COM 	enum {FA_OPEN, FA_CLOSE, FA_DUP2, FA_CLOSEFROM} fa_type;
628877SRoger.Faulkner@Sun.COM 	int		fa_need_dirbuf;	/* only consulted in the head action */
638877SRoger.Faulkner@Sun.COM 	char		*fa_path;	/* copied pathname for open() */
640Sstevel@tonic-gate 	uint_t		fa_pathsize;	/* size of fa_path[] array */
650Sstevel@tonic-gate 	int		fa_oflag;	/* oflag for open() */
660Sstevel@tonic-gate 	mode_t		fa_mode;	/* mode for open() */
670Sstevel@tonic-gate 	int		fa_filedes;	/* file descriptor for open()/close() */
680Sstevel@tonic-gate 	int		fa_newfiledes;	/* new file descriptor for dup2() */
690Sstevel@tonic-gate } file_attr_t;
700Sstevel@tonic-gate 
718877SRoger.Faulkner@Sun.COM #if defined(_LP64)
728877SRoger.Faulkner@Sun.COM #define	__open64	__open
738877SRoger.Faulkner@Sun.COM #define	getdents64	getdents
748877SRoger.Faulkner@Sun.COM #define	dirent64_t	dirent_t
758877SRoger.Faulkner@Sun.COM #else
768877SRoger.Faulkner@Sun.COM extern int getdents64(int, dirent64_t *, size_t);
778877SRoger.Faulkner@Sun.COM #endif
788877SRoger.Faulkner@Sun.COM 
798877SRoger.Faulkner@Sun.COM /*
808877SRoger.Faulkner@Sun.COM  * Support function:
818877SRoger.Faulkner@Sun.COM  * Close all open file descriptors greater than or equal to lowfd.
828877SRoger.Faulkner@Sun.COM  * This is executed in the child of vfork(), so we must not call
838877SRoger.Faulkner@Sun.COM  * opendir() / readdir() because that would alter the parent's
848877SRoger.Faulkner@Sun.COM  * address space.  We use the low-level getdents64() system call.
858877SRoger.Faulkner@Sun.COM  * Return non-zero on error.
868877SRoger.Faulkner@Sun.COM  */
878877SRoger.Faulkner@Sun.COM static int
spawn_closefrom(int lowfd,void * buf)888877SRoger.Faulkner@Sun.COM spawn_closefrom(int lowfd, void *buf)
898877SRoger.Faulkner@Sun.COM {
908877SRoger.Faulkner@Sun.COM 	int procfd;
918877SRoger.Faulkner@Sun.COM 	int fd;
928877SRoger.Faulkner@Sun.COM 	int buflen;
938877SRoger.Faulkner@Sun.COM 	dirent64_t *dp;
948877SRoger.Faulkner@Sun.COM 	dirent64_t *dpend;
958877SRoger.Faulkner@Sun.COM 
968877SRoger.Faulkner@Sun.COM 	if (lowfd <  0)
978877SRoger.Faulkner@Sun.COM 		lowfd = 0;
988877SRoger.Faulkner@Sun.COM 
998877SRoger.Faulkner@Sun.COM 	/*
1008877SRoger.Faulkner@Sun.COM 	 * Close lowfd right away as a hedge against failing
1018877SRoger.Faulkner@Sun.COM 	 * to open the /proc file descriptor directory due
1028877SRoger.Faulkner@Sun.COM 	 * all file descriptors being currently used up.
1038877SRoger.Faulkner@Sun.COM 	 */
1048877SRoger.Faulkner@Sun.COM 	(void) __close(lowfd++);
1058877SRoger.Faulkner@Sun.COM 
1068877SRoger.Faulkner@Sun.COM 	if ((procfd = __open64("/proc/self/fd", O_RDONLY, 0)) < 0) {
1078877SRoger.Faulkner@Sun.COM 		/*
1088877SRoger.Faulkner@Sun.COM 		 * We could not open the /proc file descriptor directory.
1098877SRoger.Faulkner@Sun.COM 		 * Just fail and be done with it.
1108877SRoger.Faulkner@Sun.COM 		 */
1118877SRoger.Faulkner@Sun.COM 		return (-1);
1128877SRoger.Faulkner@Sun.COM 	}
1138877SRoger.Faulkner@Sun.COM 
1148877SRoger.Faulkner@Sun.COM 	for (;;) {
1158877SRoger.Faulkner@Sun.COM 		/*
1168877SRoger.Faulkner@Sun.COM 		 * Collect a bunch of open file descriptors and close them.
1178877SRoger.Faulkner@Sun.COM 		 * Repeat until the directory is exhausted.
1188877SRoger.Faulkner@Sun.COM 		 */
1198877SRoger.Faulkner@Sun.COM 		dp = (dirent64_t *)buf;
1208877SRoger.Faulkner@Sun.COM 		if ((buflen = getdents64(procfd, dp, DIRBUF)) <= 0) {
1218877SRoger.Faulkner@Sun.COM 			(void) __close(procfd);
1228877SRoger.Faulkner@Sun.COM 			break;
1238877SRoger.Faulkner@Sun.COM 		}
1248877SRoger.Faulkner@Sun.COM 		dpend = (dirent64_t *)((uintptr_t)buf + buflen);
1258877SRoger.Faulkner@Sun.COM 		do {
1268877SRoger.Faulkner@Sun.COM 			/* skip '.', '..' and procfd */
1278877SRoger.Faulkner@Sun.COM 			if (dp->d_name[0] != '.' &&
1288877SRoger.Faulkner@Sun.COM 			    (fd = atoi(dp->d_name)) != procfd &&
1298877SRoger.Faulkner@Sun.COM 			    fd >= lowfd)
1308877SRoger.Faulkner@Sun.COM 				(void) __close(fd);
1318877SRoger.Faulkner@Sun.COM 			dp = (dirent64_t *)((uintptr_t)dp + dp->d_reclen);
1328877SRoger.Faulkner@Sun.COM 		} while (dp < dpend);
1338877SRoger.Faulkner@Sun.COM 	}
1348877SRoger.Faulkner@Sun.COM 
1358877SRoger.Faulkner@Sun.COM 	return (0);
1368877SRoger.Faulkner@Sun.COM }
1378877SRoger.Faulkner@Sun.COM 
1383086Sraf static int
perform_flag_actions(spawn_attr_t * sap)1390Sstevel@tonic-gate perform_flag_actions(spawn_attr_t *sap)
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate 	int sig;
1427930SRoger.Faulkner@Sun.COM 	struct sigaction action;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) {
145*11913SRoger.Faulkner@Sun.COM 		(void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask);
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 
1487930SRoger.Faulkner@Sun.COM 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) {
1497930SRoger.Faulkner@Sun.COM 		(void) memset(&action, 0, sizeof (action));
1507930SRoger.Faulkner@Sun.COM 		action.sa_handler = SIG_IGN;
1517930SRoger.Faulkner@Sun.COM 		for (sig = 1; sig < NSIG; sig++) {
1527930SRoger.Faulkner@Sun.COM 			if (sigismember(&sap->sa_sigignore, sig))
1537930SRoger.Faulkner@Sun.COM 				(void) __sigaction(sig, &action, NULL);
1547930SRoger.Faulkner@Sun.COM 		}
1557930SRoger.Faulkner@Sun.COM 	}
1567930SRoger.Faulkner@Sun.COM 
1570Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) {
1587930SRoger.Faulkner@Sun.COM 		(void) memset(&action, 0, sizeof (action));
1597930SRoger.Faulkner@Sun.COM 		action.sa_handler = SIG_DFL;
1600Sstevel@tonic-gate 		for (sig = 1; sig < NSIG; sig++) {
1616515Sraf 			if (sigismember(&sap->sa_sigdefault, sig))
1627930SRoger.Faulkner@Sun.COM 				(void) __sigaction(sig, &action, NULL);
1630Sstevel@tonic-gate 		}
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) {
1676515Sraf 		if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
1683086Sraf 			return (errno);
1690Sstevel@tonic-gate 	}
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) {
1726515Sraf 		if (setpgid(0, sap->sa_pgroup) != 0)
1733086Sraf 			return (errno);
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) {
1776247Sraf 		if (setparam(P_LWPID, P_MYID,
1786247Sraf 		    sap->sa_schedpolicy, sap->sa_priority) == -1)
1793086Sraf 			return (errno);
1800Sstevel@tonic-gate 	} else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) {
1816247Sraf 		if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1)
1823086Sraf 			return (errno);
1830Sstevel@tonic-gate 	}
1843086Sraf 
1853086Sraf 	return (0);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1883086Sraf static int
perform_file_actions(file_attr_t * fap,void * dirbuf)1898877SRoger.Faulkner@Sun.COM perform_file_actions(file_attr_t *fap, void *dirbuf)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate 	file_attr_t *froot = fap;
1920Sstevel@tonic-gate 	int fd;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	do {
1950Sstevel@tonic-gate 		switch (fap->fa_type) {
1960Sstevel@tonic-gate 		case FA_OPEN:
19711798SRoger.Faulkner@Sun.COM 			fd = __open(fap->fa_path, fap->fa_oflag, fap->fa_mode);
1980Sstevel@tonic-gate 			if (fd < 0)
1993086Sraf 				return (errno);
2000Sstevel@tonic-gate 			if (fd != fap->fa_filedes) {
2016515Sraf 				if (__fcntl(fd, F_DUP2FD, fap->fa_filedes) < 0)
2023086Sraf 					return (errno);
2036515Sraf 				(void) __close(fd);
2040Sstevel@tonic-gate 			}
2050Sstevel@tonic-gate 			break;
2060Sstevel@tonic-gate 		case FA_CLOSE:
2078877SRoger.Faulkner@Sun.COM 			if (__close(fap->fa_filedes) == -1 &&
2088877SRoger.Faulkner@Sun.COM 			    errno != EBADF)	/* already closed, no error */
2093086Sraf 				return (errno);
2100Sstevel@tonic-gate 			break;
2110Sstevel@tonic-gate 		case FA_DUP2:
2126515Sraf 			fd = __fcntl(fap->fa_filedes, F_DUP2FD,
2135891Sraf 			    fap->fa_newfiledes);
2140Sstevel@tonic-gate 			if (fd < 0)
2153086Sraf 				return (errno);
2160Sstevel@tonic-gate 			break;
2178877SRoger.Faulkner@Sun.COM 		case FA_CLOSEFROM:
2188877SRoger.Faulkner@Sun.COM 			if (spawn_closefrom(fap->fa_filedes, dirbuf))
2198877SRoger.Faulkner@Sun.COM 				return (errno);
2208877SRoger.Faulkner@Sun.COM 			break;
2210Sstevel@tonic-gate 		}
2220Sstevel@tonic-gate 	} while ((fap = fap->fa_next) != froot);
2233086Sraf 
2243086Sraf 	return (0);
2253086Sraf }
2263086Sraf 
2273235Sraf static int
forkflags(spawn_attr_t * sap)2283235Sraf forkflags(spawn_attr_t *sap)
2293235Sraf {
2303235Sraf 	int flags = 0;
2313235Sraf 
2323235Sraf 	if (sap != NULL) {
2333235Sraf 		if (sap->sa_psflags & POSIX_SPAWN_NOSIGCHLD_NP)
2343235Sraf 			flags |= FORK_NOSIGCHLD;
2353235Sraf 		if (sap->sa_psflags & POSIX_SPAWN_WAITPID_NP)
2363235Sraf 			flags |= FORK_WAITPID;
2373235Sraf 	}
2383235Sraf 
2393235Sraf 	return (flags);
2403235Sraf }
2413235Sraf 
2423086Sraf /*
2433086Sraf  * set_error() / get_error() are used to guarantee that the local variable
2443086Sraf  * 'error' is set correctly in memory on return from vfork() in the parent.
2453086Sraf  */
2463086Sraf 
2473086Sraf static int
set_error(int * errp,int err)2483086Sraf set_error(int *errp, int err)
2493086Sraf {
2503086Sraf 	return (*errp = err);
2513086Sraf }
2523086Sraf 
2533086Sraf static int
get_error(int * errp)2543086Sraf get_error(int *errp)
2553086Sraf {
2563086Sraf 	return (*errp);
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate /*
2600Sstevel@tonic-gate  * For MT safety, do not invoke the dynamic linker after calling vfork().
2610Sstevel@tonic-gate  * If some other thread was in the dynamic linker when this thread's parent
2620Sstevel@tonic-gate  * called vfork() then the dynamic linker's lock would still be held here
2630Sstevel@tonic-gate  * (with a defunct owner) and we would deadlock ourself if we invoked it.
2640Sstevel@tonic-gate  *
2650Sstevel@tonic-gate  * Therefore, all of the functions we call here after returning from
2666812Sraf  * vforkx() in the child are not and must never be exported from libc
2670Sstevel@tonic-gate  * as global symbols.  To do so would risk invoking the dynamic linker.
2680Sstevel@tonic-gate  */
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate int
posix_spawn(pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])2716812Sraf posix_spawn(
2720Sstevel@tonic-gate 	pid_t *pidp,
2730Sstevel@tonic-gate 	const char *path,
2740Sstevel@tonic-gate 	const posix_spawn_file_actions_t *file_actions,
2750Sstevel@tonic-gate 	const posix_spawnattr_t *attrp,
2760Sstevel@tonic-gate 	char *const argv[],
2770Sstevel@tonic-gate 	char *const envp[])
2780Sstevel@tonic-gate {
2790Sstevel@tonic-gate 	spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
2800Sstevel@tonic-gate 	file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
2818877SRoger.Faulkner@Sun.COM 	void *dirbuf = NULL;
2823086Sraf 	int error;		/* this will be set by the child */
2830Sstevel@tonic-gate 	pid_t pid;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	if (attrp != NULL && sap == NULL)
2860Sstevel@tonic-gate 		return (EINVAL);
2870Sstevel@tonic-gate 
2888877SRoger.Faulkner@Sun.COM 	if (fap != NULL && fap->fa_need_dirbuf) {
2898877SRoger.Faulkner@Sun.COM 		/*
2908877SRoger.Faulkner@Sun.COM 		 * Preallocate the buffer for the call to getdents64() in
2918877SRoger.Faulkner@Sun.COM 		 * spawn_closefrom() since we can't do it in the vfork() child.
2928877SRoger.Faulkner@Sun.COM 		 */
2938877SRoger.Faulkner@Sun.COM 		if ((dirbuf = lmalloc(DIRBUF)) == NULL)
2948877SRoger.Faulkner@Sun.COM 			return (ENOMEM);
2958877SRoger.Faulkner@Sun.COM 	}
2968877SRoger.Faulkner@Sun.COM 
2976812Sraf 	switch (pid = vforkx(forkflags(sap))) {
2980Sstevel@tonic-gate 	case 0:			/* child */
2990Sstevel@tonic-gate 		break;
3000Sstevel@tonic-gate 	case -1:		/* parent, failure */
3018877SRoger.Faulkner@Sun.COM 		if (dirbuf)
3028877SRoger.Faulkner@Sun.COM 			lfree(dirbuf, DIRBUF);
3030Sstevel@tonic-gate 		return (errno);
3040Sstevel@tonic-gate 	default:		/* parent, success */
3053086Sraf 		/*
3063086Sraf 		 * We don't get here until the child exec()s or exit()s
3073086Sraf 		 */
3083086Sraf 		if (pidp != NULL && get_error(&error) == 0)
3090Sstevel@tonic-gate 			*pidp = pid;
3108877SRoger.Faulkner@Sun.COM 		if (dirbuf)
3118877SRoger.Faulkner@Sun.COM 			lfree(dirbuf, DIRBUF);
3123086Sraf 		return (get_error(&error));
3130Sstevel@tonic-gate 	}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	if (sap != NULL)
3163086Sraf 		if (set_error(&error, perform_flag_actions(sap)) != 0)
3176515Sraf 			_exit(_EVAPORATE);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	if (fap != NULL)
3208877SRoger.Faulkner@Sun.COM 		if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
3216515Sraf 			_exit(_EVAPORATE);
3220Sstevel@tonic-gate 
3233086Sraf 	(void) set_error(&error, 0);
3246515Sraf 	(void) execve(path, argv, envp);
3257635SRoger.Faulkner@Sun.COM 	if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
3267635SRoger.Faulkner@Sun.COM 		_exit(127);
3273086Sraf 	(void) set_error(&error, errno);
3286515Sraf 	_exit(_EVAPORATE);
3290Sstevel@tonic-gate 	return (0);	/* not reached */
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate  * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c).
3340Sstevel@tonic-gate  */
3350Sstevel@tonic-gate 
3365891Sraf extern int libc__xpg4;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate static const char *
execat(const char * s1,const char * s2,char * si)3390Sstevel@tonic-gate execat(const char *s1, const char *s2, char *si)
3400Sstevel@tonic-gate {
3410Sstevel@tonic-gate 	int cnt = PATH_MAX + 1;
3420Sstevel@tonic-gate 	char *s;
3430Sstevel@tonic-gate 	char c;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	for (s = si; (c = *s1) != '\0' && c != ':'; s1++) {
3460Sstevel@tonic-gate 		if (cnt > 0) {
3470Sstevel@tonic-gate 			*s++ = c;
3480Sstevel@tonic-gate 			cnt--;
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 	if (si != s && cnt > 0) {
3520Sstevel@tonic-gate 		*s++ = '/';
3530Sstevel@tonic-gate 		cnt--;
3540Sstevel@tonic-gate 	}
3550Sstevel@tonic-gate 	for (; (c = *s2) != '\0' && cnt > 0; s2++) {
3560Sstevel@tonic-gate 		*s++ = c;
3570Sstevel@tonic-gate 		cnt--;
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate 	*s = '\0';
3600Sstevel@tonic-gate 	return (*s1? ++s1: NULL);
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate /* ARGSUSED */
3640Sstevel@tonic-gate int
posix_spawnp(pid_t * pidp,const char * file,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])3656812Sraf posix_spawnp(
3660Sstevel@tonic-gate 	pid_t *pidp,
3670Sstevel@tonic-gate 	const char *file,
3680Sstevel@tonic-gate 	const posix_spawn_file_actions_t *file_actions,
3690Sstevel@tonic-gate 	const posix_spawnattr_t *attrp,
3700Sstevel@tonic-gate 	char *const argv[],
3710Sstevel@tonic-gate 	char *const envp[])
3720Sstevel@tonic-gate {
3730Sstevel@tonic-gate 	spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
3740Sstevel@tonic-gate 	file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
3758877SRoger.Faulkner@Sun.COM 	void *dirbuf = NULL;
3760Sstevel@tonic-gate 	const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : "";
3775891Sraf 	int xpg4 = libc__xpg4;
3787646SRoger.Faulkner@Sun.COM 	int error = 0;		/* this will be set by the child */
3790Sstevel@tonic-gate 	char path[PATH_MAX+4];
3800Sstevel@tonic-gate 	const char *cp;
3810Sstevel@tonic-gate 	pid_t pid;
3820Sstevel@tonic-gate 	char **newargs;
3830Sstevel@tonic-gate 	int argc;
3840Sstevel@tonic-gate 	int i;
3850Sstevel@tonic-gate 	static const char *sun_path = "/bin/sh";
3860Sstevel@tonic-gate 	static const char *xpg4_path = "/usr/xpg4/bin/sh";
3870Sstevel@tonic-gate 	static const char *shell = "sh";
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	if (attrp != NULL && sap == NULL)
3900Sstevel@tonic-gate 		return (EINVAL);
3910Sstevel@tonic-gate 
3923086Sraf 	if (*file == '\0')
3933086Sraf 		return (EACCES);
3943086Sraf 
3958877SRoger.Faulkner@Sun.COM 	if (fap != NULL && fap->fa_need_dirbuf) {
3968877SRoger.Faulkner@Sun.COM 		/*
3978877SRoger.Faulkner@Sun.COM 		 * Preallocate the buffer for the call to getdents64() in
3988877SRoger.Faulkner@Sun.COM 		 * spawn_closefrom() since we can't do it in the vfork() child.
3998877SRoger.Faulkner@Sun.COM 		 */
4008877SRoger.Faulkner@Sun.COM 		if ((dirbuf = lmalloc(DIRBUF)) == NULL)
4018877SRoger.Faulkner@Sun.COM 			return (ENOMEM);
4028877SRoger.Faulkner@Sun.COM 	}
4038877SRoger.Faulkner@Sun.COM 
4040Sstevel@tonic-gate 	/*
4050Sstevel@tonic-gate 	 * We may need to invoke the shell with a slightly modified
4060Sstevel@tonic-gate 	 * argv[] array.  To do this we need to preallocate the array.
4070Sstevel@tonic-gate 	 * We must call alloca() before calling vfork() because doing
4080Sstevel@tonic-gate 	 * it after vfork() (in the child) would corrupt the parent.
4090Sstevel@tonic-gate 	 */
4100Sstevel@tonic-gate 	for (argc = 0; argv[argc] != NULL; argc++)
4110Sstevel@tonic-gate 		continue;
4120Sstevel@tonic-gate 	newargs = alloca((argc + 2) * sizeof (char *));
4130Sstevel@tonic-gate 
4146812Sraf 	switch (pid = vforkx(forkflags(sap))) {
4150Sstevel@tonic-gate 	case 0:			/* child */
4160Sstevel@tonic-gate 		break;
4170Sstevel@tonic-gate 	case -1:		/* parent, failure */
4188877SRoger.Faulkner@Sun.COM 		if (dirbuf)
4198877SRoger.Faulkner@Sun.COM 			lfree(dirbuf, DIRBUF);
4200Sstevel@tonic-gate 		return (errno);
4210Sstevel@tonic-gate 	default:		/* parent, success */
4223086Sraf 		/*
4233086Sraf 		 * We don't get here until the child exec()s or exit()s
4243086Sraf 		 */
4253086Sraf 		if (pidp != NULL && get_error(&error) == 0)
4260Sstevel@tonic-gate 			*pidp = pid;
4278877SRoger.Faulkner@Sun.COM 		if (dirbuf)
4288877SRoger.Faulkner@Sun.COM 			lfree(dirbuf, DIRBUF);
4293086Sraf 		return (get_error(&error));
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (sap != NULL)
4333086Sraf 		if (set_error(&error, perform_flag_actions(sap)) != 0)
4346515Sraf 			_exit(_EVAPORATE);
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	if (fap != NULL)
4378877SRoger.Faulkner@Sun.COM 		if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
4386515Sraf 			_exit(_EVAPORATE);
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	if (pathstr == NULL) {
4410Sstevel@tonic-gate 		/*
4420Sstevel@tonic-gate 		 * XPG4:  pathstr is equivalent to _CS_PATH, except that
4430Sstevel@tonic-gate 		 * :/usr/sbin is appended when root, and pathstr must end
4440Sstevel@tonic-gate 		 * with a colon when not root.  Keep these paths in sync
4450Sstevel@tonic-gate 		 * with _CS_PATH in confstr.c.  Note that pathstr must end
4460Sstevel@tonic-gate 		 * with a colon when not root so that when file doesn't
4470Sstevel@tonic-gate 		 * contain '/', the last call to execat() will result in an
4480Sstevel@tonic-gate 		 * attempt to execv file from the current directory.
4490Sstevel@tonic-gate 		 */
4506515Sraf 		if (geteuid() == 0 || getuid() == 0) {
4510Sstevel@tonic-gate 			if (!xpg4)
4520Sstevel@tonic-gate 				pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin";
4530Sstevel@tonic-gate 			else
4540Sstevel@tonic-gate 				pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
4550Sstevel@tonic-gate 				    "/usr/bin:/opt/SUNWspro/bin:/usr/sbin";
4560Sstevel@tonic-gate 		} else {
4570Sstevel@tonic-gate 			if (!xpg4)
4580Sstevel@tonic-gate 				pathstr = "/usr/ccs/bin:/usr/bin:";
4590Sstevel@tonic-gate 			else
4600Sstevel@tonic-gate 				pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
4610Sstevel@tonic-gate 				    "/usr/bin:/opt/SUNWspro/bin:";
4620Sstevel@tonic-gate 		}
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	cp = pathstr;
4660Sstevel@tonic-gate 	do {
4670Sstevel@tonic-gate 		cp = execat(cp, file, path);
4680Sstevel@tonic-gate 		/*
4690Sstevel@tonic-gate 		 * 4025035 and 4038378
4700Sstevel@tonic-gate 		 * if a filename begins with a "-" prepend "./" so that
4710Sstevel@tonic-gate 		 * the shell can't interpret it as an option
4720Sstevel@tonic-gate 		 */
4730Sstevel@tonic-gate 		if (*path == '-') {
4740Sstevel@tonic-gate 			char *s;
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 			for (s = path; *s != '\0'; s++)
4770Sstevel@tonic-gate 				continue;
4780Sstevel@tonic-gate 			for (; s >= path; s--)
4790Sstevel@tonic-gate 				*(s + 2) = *s;
4800Sstevel@tonic-gate 			path[0] = '.';
4810Sstevel@tonic-gate 			path[1] = '/';
4820Sstevel@tonic-gate 		}
4833086Sraf 		(void) set_error(&error, 0);
4846515Sraf 		(void) execve(path, argv, envp);
4853086Sraf 		if (set_error(&error, errno) == ENOEXEC) {
4860Sstevel@tonic-gate 			newargs[0] = (char *)shell;
4870Sstevel@tonic-gate 			newargs[1] = path;
4880Sstevel@tonic-gate 			for (i = 1; i <= argc; i++)
4890Sstevel@tonic-gate 				newargs[i + 1] = argv[i];
4903086Sraf 			(void) set_error(&error, 0);
4916515Sraf 			(void) execve(xpg4? xpg4_path : sun_path,
4923086Sraf 			    newargs, envp);
4937635SRoger.Faulkner@Sun.COM 			if (sap != NULL &&
4947635SRoger.Faulkner@Sun.COM 			    (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
4957635SRoger.Faulkner@Sun.COM 				_exit(127);
4963086Sraf 			(void) set_error(&error, errno);
4976515Sraf 			_exit(_EVAPORATE);
4980Sstevel@tonic-gate 		}
4990Sstevel@tonic-gate 	} while (cp);
5007646SRoger.Faulkner@Sun.COM 
5017646SRoger.Faulkner@Sun.COM 	if (sap != NULL &&
5027646SRoger.Faulkner@Sun.COM 	    (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) {
5037646SRoger.Faulkner@Sun.COM 		(void) set_error(&error, 0);
5047646SRoger.Faulkner@Sun.COM 		_exit(127);
5057646SRoger.Faulkner@Sun.COM 	}
5066515Sraf 	_exit(_EVAPORATE);
5070Sstevel@tonic-gate 	return (0);	/* not reached */
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate int
posix_spawn_file_actions_init(posix_spawn_file_actions_t * file_actions)5116812Sraf posix_spawn_file_actions_init(
5120Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions)
5130Sstevel@tonic-gate {
5140Sstevel@tonic-gate 	file_actions->__file_attrp = NULL;
5150Sstevel@tonic-gate 	return (0);
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate int
posix_spawn_file_actions_destroy(posix_spawn_file_actions_t * file_actions)5196812Sraf posix_spawn_file_actions_destroy(
5200Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions)
5210Sstevel@tonic-gate {
5220Sstevel@tonic-gate 	file_attr_t *froot = file_actions->__file_attrp;
5230Sstevel@tonic-gate 	file_attr_t *fap;
5240Sstevel@tonic-gate 	file_attr_t *next;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	if ((fap = froot) != NULL) {
5270Sstevel@tonic-gate 		do {
5280Sstevel@tonic-gate 			next = fap->fa_next;
5298877SRoger.Faulkner@Sun.COM 			if (fap->fa_type == FA_OPEN)
5300Sstevel@tonic-gate 				lfree(fap->fa_path, fap->fa_pathsize);
5310Sstevel@tonic-gate 			lfree(fap, sizeof (*fap));
5320Sstevel@tonic-gate 		} while ((fap = next) != froot);
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 	file_actions->__file_attrp = NULL;
5350Sstevel@tonic-gate 	return (0);
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate static void
add_file_attr(posix_spawn_file_actions_t * file_actions,file_attr_t * fap)5390Sstevel@tonic-gate add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	file_attr_t *froot = file_actions->__file_attrp;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	if (froot == NULL) {
5440Sstevel@tonic-gate 		fap->fa_next = fap->fa_prev = fap;
5458877SRoger.Faulkner@Sun.COM 		file_actions->__file_attrp = froot = fap;
5460Sstevel@tonic-gate 	} else {
5470Sstevel@tonic-gate 		fap->fa_next = froot;
5480Sstevel@tonic-gate 		fap->fa_prev = froot->fa_prev;
5490Sstevel@tonic-gate 		froot->fa_prev->fa_next = fap;
5500Sstevel@tonic-gate 		froot->fa_prev = fap;
5510Sstevel@tonic-gate 	}
5528877SRoger.Faulkner@Sun.COM 
5538877SRoger.Faulkner@Sun.COM 	/*
5548877SRoger.Faulkner@Sun.COM 	 * Once set, __file_attrp no longer changes, so this assignment
5558877SRoger.Faulkner@Sun.COM 	 * always goes into the first element in the list, as required.
5568877SRoger.Faulkner@Sun.COM 	 */
5578877SRoger.Faulkner@Sun.COM 	if (fap->fa_type == FA_CLOSEFROM)
5588877SRoger.Faulkner@Sun.COM 		froot->fa_need_dirbuf = 1;
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate int
posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * file_actions,int filedes,const char * path,int oflag,mode_t mode)5626812Sraf posix_spawn_file_actions_addopen(
5630Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
5640Sstevel@tonic-gate 	int filedes,
5650Sstevel@tonic-gate 	const char *path,
5660Sstevel@tonic-gate 	int oflag,
5670Sstevel@tonic-gate 	mode_t mode)
5680Sstevel@tonic-gate {
5690Sstevel@tonic-gate 	file_attr_t *fap;
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	if (filedes < 0)
5720Sstevel@tonic-gate 		return (EBADF);
5730Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
5740Sstevel@tonic-gate 		return (ENOMEM);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	fap->fa_pathsize = strlen(path) + 1;
5770Sstevel@tonic-gate 	if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) {
5780Sstevel@tonic-gate 		lfree(fap, sizeof (*fap));
5790Sstevel@tonic-gate 		return (ENOMEM);
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 	(void) strcpy(fap->fa_path, path);
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	fap->fa_type = FA_OPEN;
5840Sstevel@tonic-gate 	fap->fa_oflag = oflag;
5850Sstevel@tonic-gate 	fap->fa_mode = mode;
5860Sstevel@tonic-gate 	fap->fa_filedes = filedes;
5870Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	return (0);
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate int
posix_spawn_file_actions_addclose(posix_spawn_file_actions_t * file_actions,int filedes)5936812Sraf posix_spawn_file_actions_addclose(
5940Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
5950Sstevel@tonic-gate 	int filedes)
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate 	file_attr_t *fap;
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	if (filedes < 0)
6000Sstevel@tonic-gate 		return (EBADF);
6010Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
6020Sstevel@tonic-gate 		return (ENOMEM);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	fap->fa_type = FA_CLOSE;
6050Sstevel@tonic-gate 	fap->fa_filedes = filedes;
6060Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	return (0);
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate int
posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t * file_actions,int filedes,int newfiledes)6126812Sraf posix_spawn_file_actions_adddup2(
6130Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
6140Sstevel@tonic-gate 	int filedes,
6150Sstevel@tonic-gate 	int newfiledes)
6160Sstevel@tonic-gate {
6170Sstevel@tonic-gate 	file_attr_t *fap;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	if (filedes < 0 || newfiledes < 0)
6200Sstevel@tonic-gate 		return (EBADF);
6210Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
6220Sstevel@tonic-gate 		return (ENOMEM);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	fap->fa_type = FA_DUP2;
6250Sstevel@tonic-gate 	fap->fa_filedes = filedes;
6260Sstevel@tonic-gate 	fap->fa_newfiledes = newfiledes;
6270Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	return (0);
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate int
posix_spawn_file_actions_addclosefrom_np(posix_spawn_file_actions_t * file_actions,int lowfiledes)6338877SRoger.Faulkner@Sun.COM posix_spawn_file_actions_addclosefrom_np(
6348877SRoger.Faulkner@Sun.COM 	posix_spawn_file_actions_t *file_actions,
6358877SRoger.Faulkner@Sun.COM 	int lowfiledes)
6368877SRoger.Faulkner@Sun.COM {
6378877SRoger.Faulkner@Sun.COM 	file_attr_t *fap;
6388877SRoger.Faulkner@Sun.COM 
6398877SRoger.Faulkner@Sun.COM 	if (lowfiledes < 0)
6408877SRoger.Faulkner@Sun.COM 		return (EBADF);
6418877SRoger.Faulkner@Sun.COM 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
6428877SRoger.Faulkner@Sun.COM 		return (ENOMEM);
6438877SRoger.Faulkner@Sun.COM 	fap->fa_type = FA_CLOSEFROM;
6448877SRoger.Faulkner@Sun.COM 	fap->fa_filedes = lowfiledes;
6458877SRoger.Faulkner@Sun.COM 	add_file_attr(file_actions, fap);
6468877SRoger.Faulkner@Sun.COM 
6478877SRoger.Faulkner@Sun.COM 	return (0);
6488877SRoger.Faulkner@Sun.COM }
6498877SRoger.Faulkner@Sun.COM 
6508877SRoger.Faulkner@Sun.COM int
posix_spawnattr_init(posix_spawnattr_t * attr)6516812Sraf posix_spawnattr_init(
6520Sstevel@tonic-gate 	posix_spawnattr_t *attr)
6530Sstevel@tonic-gate {
6543235Sraf 	if ((attr->__spawn_attrp = lmalloc(sizeof (posix_spawnattr_t))) == NULL)
6550Sstevel@tonic-gate 		return (ENOMEM);
6560Sstevel@tonic-gate 	/*
6570Sstevel@tonic-gate 	 * Add default stuff here?
6580Sstevel@tonic-gate 	 */
6590Sstevel@tonic-gate 	return (0);
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate int
posix_spawnattr_destroy(posix_spawnattr_t * attr)6636812Sraf posix_spawnattr_destroy(
6640Sstevel@tonic-gate 	posix_spawnattr_t *attr)
6650Sstevel@tonic-gate {
6660Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	if (sap == NULL)
6690Sstevel@tonic-gate 		return (EINVAL);
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	/*
6720Sstevel@tonic-gate 	 * deallocate stuff here?
6730Sstevel@tonic-gate 	 */
6740Sstevel@tonic-gate 	lfree(sap, sizeof (*sap));
6750Sstevel@tonic-gate 	attr->__spawn_attrp = NULL;
6760Sstevel@tonic-gate 	return (0);
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate int
posix_spawnattr_setflags(posix_spawnattr_t * attr,short flags)6806812Sraf posix_spawnattr_setflags(
6810Sstevel@tonic-gate 	posix_spawnattr_t *attr,
6820Sstevel@tonic-gate 	short flags)
6830Sstevel@tonic-gate {
6840Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	if (sap == NULL ||
6870Sstevel@tonic-gate 	    (flags & ~ALL_POSIX_SPAWN_FLAGS))
6880Sstevel@tonic-gate 		return (EINVAL);
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	sap->sa_psflags = flags;
6910Sstevel@tonic-gate 	return (0);
6920Sstevel@tonic-gate }
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate int
posix_spawnattr_getflags(const posix_spawnattr_t * attr,short * flags)6956812Sraf posix_spawnattr_getflags(
6960Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
6970Sstevel@tonic-gate 	short *flags)
6980Sstevel@tonic-gate {
6990Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	if (sap == NULL)
7020Sstevel@tonic-gate 		return (EINVAL);
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	*flags = sap->sa_psflags;
7050Sstevel@tonic-gate 	return (0);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate int
posix_spawnattr_setpgroup(posix_spawnattr_t * attr,pid_t pgroup)7096812Sraf posix_spawnattr_setpgroup(
7100Sstevel@tonic-gate 	posix_spawnattr_t *attr,
7110Sstevel@tonic-gate 	pid_t pgroup)
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	if (sap == NULL)
7160Sstevel@tonic-gate 		return (EINVAL);
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	sap->sa_pgroup = pgroup;
7190Sstevel@tonic-gate 	return (0);
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate int
posix_spawnattr_getpgroup(const posix_spawnattr_t * attr,pid_t * pgroup)7236812Sraf posix_spawnattr_getpgroup(
7240Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7250Sstevel@tonic-gate 	pid_t *pgroup)
7260Sstevel@tonic-gate {
7270Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	if (sap == NULL)
7300Sstevel@tonic-gate 		return (EINVAL);
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	*pgroup = sap->sa_pgroup;
7330Sstevel@tonic-gate 	return (0);
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate int
posix_spawnattr_setschedparam(posix_spawnattr_t * attr,const struct sched_param * schedparam)7376812Sraf posix_spawnattr_setschedparam(
7380Sstevel@tonic-gate 	posix_spawnattr_t *attr,
7390Sstevel@tonic-gate 	const struct sched_param *schedparam)
7400Sstevel@tonic-gate {
7410Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	if (sap == NULL)
7440Sstevel@tonic-gate 		return (EINVAL);
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	/*
7470Sstevel@tonic-gate 	 * Check validity?
7480Sstevel@tonic-gate 	 */
7490Sstevel@tonic-gate 	sap->sa_priority = schedparam->sched_priority;
7500Sstevel@tonic-gate 	return (0);
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate int
posix_spawnattr_getschedparam(const posix_spawnattr_t * attr,struct sched_param * schedparam)7546812Sraf posix_spawnattr_getschedparam(
7550Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7560Sstevel@tonic-gate 	struct sched_param *schedparam)
7570Sstevel@tonic-gate {
7580Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	if (sap == NULL)
7610Sstevel@tonic-gate 		return (EINVAL);
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	schedparam->sched_priority = sap->sa_priority;
7640Sstevel@tonic-gate 	return (0);
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate int
posix_spawnattr_setschedpolicy(posix_spawnattr_t * attr,int schedpolicy)7686812Sraf posix_spawnattr_setschedpolicy(
7690Sstevel@tonic-gate 	posix_spawnattr_t *attr,
7700Sstevel@tonic-gate 	int schedpolicy)
7710Sstevel@tonic-gate {
7720Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7730Sstevel@tonic-gate 
7746247Sraf 	if (sap == NULL || schedpolicy == SCHED_SYS)
7750Sstevel@tonic-gate 		return (EINVAL);
7760Sstevel@tonic-gate 
7776247Sraf 	/*
7786247Sraf 	 * Cache the policy information for later use
7796247Sraf 	 * by the vfork() child of posix_spawn().
7806247Sraf 	 */
7816247Sraf 	if (get_info_by_policy(schedpolicy) == NULL)
7826247Sraf 		return (errno);
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	sap->sa_schedpolicy = schedpolicy;
7850Sstevel@tonic-gate 	return (0);
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate int
posix_spawnattr_getschedpolicy(const posix_spawnattr_t * attr,int * schedpolicy)7896812Sraf posix_spawnattr_getschedpolicy(
7900Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7910Sstevel@tonic-gate 	int *schedpolicy)
7920Sstevel@tonic-gate {
7930Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	if (sap == NULL)
7960Sstevel@tonic-gate 		return (EINVAL);
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	*schedpolicy = sap->sa_schedpolicy;
7990Sstevel@tonic-gate 	return (0);
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate int
posix_spawnattr_setsigdefault(posix_spawnattr_t * attr,const sigset_t * sigdefault)8036812Sraf posix_spawnattr_setsigdefault(
8040Sstevel@tonic-gate 	posix_spawnattr_t *attr,
8050Sstevel@tonic-gate 	const sigset_t *sigdefault)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	if (sap == NULL)
8100Sstevel@tonic-gate 		return (EINVAL);
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	sap->sa_sigdefault = *sigdefault;
8130Sstevel@tonic-gate 	return (0);
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate int
posix_spawnattr_getsigdefault(const posix_spawnattr_t * attr,sigset_t * sigdefault)8176812Sraf posix_spawnattr_getsigdefault(
8180Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
8190Sstevel@tonic-gate 	sigset_t *sigdefault)
8200Sstevel@tonic-gate {
8210Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	if (sap == NULL)
8240Sstevel@tonic-gate 		return (EINVAL);
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	*sigdefault = sap->sa_sigdefault;
8270Sstevel@tonic-gate 	return (0);
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate int
posix_spawnattr_setsigignore_np(posix_spawnattr_t * attr,const sigset_t * sigignore)8317930SRoger.Faulkner@Sun.COM posix_spawnattr_setsigignore_np(
8327930SRoger.Faulkner@Sun.COM 	posix_spawnattr_t *attr,
8337930SRoger.Faulkner@Sun.COM 	const sigset_t *sigignore)
8347930SRoger.Faulkner@Sun.COM {
8357930SRoger.Faulkner@Sun.COM 	spawn_attr_t *sap = attr->__spawn_attrp;
8367930SRoger.Faulkner@Sun.COM 
8377930SRoger.Faulkner@Sun.COM 	if (sap == NULL)
8387930SRoger.Faulkner@Sun.COM 		return (EINVAL);
8397930SRoger.Faulkner@Sun.COM 
8407930SRoger.Faulkner@Sun.COM 	sap->sa_sigignore = *sigignore;
8417930SRoger.Faulkner@Sun.COM 	return (0);
8427930SRoger.Faulkner@Sun.COM }
8437930SRoger.Faulkner@Sun.COM 
8447930SRoger.Faulkner@Sun.COM int
posix_spawnattr_getsigignore_np(const posix_spawnattr_t * attr,sigset_t * sigignore)8457930SRoger.Faulkner@Sun.COM posix_spawnattr_getsigignore_np(
8467930SRoger.Faulkner@Sun.COM 	const posix_spawnattr_t *attr,
8477930SRoger.Faulkner@Sun.COM 	sigset_t *sigignore)
8487930SRoger.Faulkner@Sun.COM {
8497930SRoger.Faulkner@Sun.COM 	spawn_attr_t *sap = attr->__spawn_attrp;
8507930SRoger.Faulkner@Sun.COM 
8517930SRoger.Faulkner@Sun.COM 	if (sap == NULL)
8527930SRoger.Faulkner@Sun.COM 		return (EINVAL);
8537930SRoger.Faulkner@Sun.COM 
8547930SRoger.Faulkner@Sun.COM 	*sigignore = sap->sa_sigignore;
8557930SRoger.Faulkner@Sun.COM 	return (0);
8567930SRoger.Faulkner@Sun.COM }
8577930SRoger.Faulkner@Sun.COM 
8587930SRoger.Faulkner@Sun.COM int
posix_spawnattr_setsigmask(posix_spawnattr_t * attr,const sigset_t * sigmask)8596812Sraf posix_spawnattr_setsigmask(
8600Sstevel@tonic-gate 	posix_spawnattr_t *attr,
8610Sstevel@tonic-gate 	const sigset_t *sigmask)
8620Sstevel@tonic-gate {
8630Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	if (sap == NULL)
8660Sstevel@tonic-gate 		return (EINVAL);
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	sap->sa_sigmask = *sigmask;
8690Sstevel@tonic-gate 	return (0);
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate int
posix_spawnattr_getsigmask(const posix_spawnattr_t * attr,sigset_t * sigmask)8736812Sraf posix_spawnattr_getsigmask(
8740Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
8750Sstevel@tonic-gate 	sigset_t *sigmask)
8760Sstevel@tonic-gate {
8770Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	if (sap == NULL)
8800Sstevel@tonic-gate 		return (EINVAL);
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	*sigmask = sap->sa_sigmask;
8830Sstevel@tonic-gate 	return (0);
8840Sstevel@tonic-gate }
885