xref: /onnv-gate/usr/src/lib/libc/port/threads/spawn.c (revision 11798:1e7f1f154004)
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 /*
23*11798SRoger.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 
710Sstevel@tonic-gate extern	int	__lwp_sigmask(int, const sigset_t *, sigset_t *);
720Sstevel@tonic-gate extern	int	__sigaction(int, const struct sigaction *, struct sigaction *);
730Sstevel@tonic-gate 
748877SRoger.Faulkner@Sun.COM #if defined(_LP64)
758877SRoger.Faulkner@Sun.COM #define	__open64	__open
768877SRoger.Faulkner@Sun.COM #define	getdents64	getdents
778877SRoger.Faulkner@Sun.COM #define	dirent64_t	dirent_t
788877SRoger.Faulkner@Sun.COM #else
798877SRoger.Faulkner@Sun.COM extern int getdents64(int, dirent64_t *, size_t);
808877SRoger.Faulkner@Sun.COM #endif
818877SRoger.Faulkner@Sun.COM 
828877SRoger.Faulkner@Sun.COM /*
838877SRoger.Faulkner@Sun.COM  * Support function:
848877SRoger.Faulkner@Sun.COM  * Close all open file descriptors greater than or equal to lowfd.
858877SRoger.Faulkner@Sun.COM  * This is executed in the child of vfork(), so we must not call
868877SRoger.Faulkner@Sun.COM  * opendir() / readdir() because that would alter the parent's
878877SRoger.Faulkner@Sun.COM  * address space.  We use the low-level getdents64() system call.
888877SRoger.Faulkner@Sun.COM  * Return non-zero on error.
898877SRoger.Faulkner@Sun.COM  */
908877SRoger.Faulkner@Sun.COM static int
918877SRoger.Faulkner@Sun.COM spawn_closefrom(int lowfd, void *buf)
928877SRoger.Faulkner@Sun.COM {
938877SRoger.Faulkner@Sun.COM 	int procfd;
948877SRoger.Faulkner@Sun.COM 	int fd;
958877SRoger.Faulkner@Sun.COM 	int buflen;
968877SRoger.Faulkner@Sun.COM 	dirent64_t *dp;
978877SRoger.Faulkner@Sun.COM 	dirent64_t *dpend;
988877SRoger.Faulkner@Sun.COM 
998877SRoger.Faulkner@Sun.COM 	if (lowfd <  0)
1008877SRoger.Faulkner@Sun.COM 		lowfd = 0;
1018877SRoger.Faulkner@Sun.COM 
1028877SRoger.Faulkner@Sun.COM 	/*
1038877SRoger.Faulkner@Sun.COM 	 * Close lowfd right away as a hedge against failing
1048877SRoger.Faulkner@Sun.COM 	 * to open the /proc file descriptor directory due
1058877SRoger.Faulkner@Sun.COM 	 * all file descriptors being currently used up.
1068877SRoger.Faulkner@Sun.COM 	 */
1078877SRoger.Faulkner@Sun.COM 	(void) __close(lowfd++);
1088877SRoger.Faulkner@Sun.COM 
1098877SRoger.Faulkner@Sun.COM 	if ((procfd = __open64("/proc/self/fd", O_RDONLY, 0)) < 0) {
1108877SRoger.Faulkner@Sun.COM 		/*
1118877SRoger.Faulkner@Sun.COM 		 * We could not open the /proc file descriptor directory.
1128877SRoger.Faulkner@Sun.COM 		 * Just fail and be done with it.
1138877SRoger.Faulkner@Sun.COM 		 */
1148877SRoger.Faulkner@Sun.COM 		return (-1);
1158877SRoger.Faulkner@Sun.COM 	}
1168877SRoger.Faulkner@Sun.COM 
1178877SRoger.Faulkner@Sun.COM 	for (;;) {
1188877SRoger.Faulkner@Sun.COM 		/*
1198877SRoger.Faulkner@Sun.COM 		 * Collect a bunch of open file descriptors and close them.
1208877SRoger.Faulkner@Sun.COM 		 * Repeat until the directory is exhausted.
1218877SRoger.Faulkner@Sun.COM 		 */
1228877SRoger.Faulkner@Sun.COM 		dp = (dirent64_t *)buf;
1238877SRoger.Faulkner@Sun.COM 		if ((buflen = getdents64(procfd, dp, DIRBUF)) <= 0) {
1248877SRoger.Faulkner@Sun.COM 			(void) __close(procfd);
1258877SRoger.Faulkner@Sun.COM 			break;
1268877SRoger.Faulkner@Sun.COM 		}
1278877SRoger.Faulkner@Sun.COM 		dpend = (dirent64_t *)((uintptr_t)buf + buflen);
1288877SRoger.Faulkner@Sun.COM 		do {
1298877SRoger.Faulkner@Sun.COM 			/* skip '.', '..' and procfd */
1308877SRoger.Faulkner@Sun.COM 			if (dp->d_name[0] != '.' &&
1318877SRoger.Faulkner@Sun.COM 			    (fd = atoi(dp->d_name)) != procfd &&
1328877SRoger.Faulkner@Sun.COM 			    fd >= lowfd)
1338877SRoger.Faulkner@Sun.COM 				(void) __close(fd);
1348877SRoger.Faulkner@Sun.COM 			dp = (dirent64_t *)((uintptr_t)dp + dp->d_reclen);
1358877SRoger.Faulkner@Sun.COM 		} while (dp < dpend);
1368877SRoger.Faulkner@Sun.COM 	}
1378877SRoger.Faulkner@Sun.COM 
1388877SRoger.Faulkner@Sun.COM 	return (0);
1398877SRoger.Faulkner@Sun.COM }
1408877SRoger.Faulkner@Sun.COM 
1413086Sraf static int
1420Sstevel@tonic-gate perform_flag_actions(spawn_attr_t *sap)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	int sig;
1457930SRoger.Faulkner@Sun.COM 	struct sigaction action;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) {
1480Sstevel@tonic-gate 		(void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask, NULL);
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 
1517930SRoger.Faulkner@Sun.COM 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) {
1527930SRoger.Faulkner@Sun.COM 		(void) memset(&action, 0, sizeof (action));
1537930SRoger.Faulkner@Sun.COM 		action.sa_handler = SIG_IGN;
1547930SRoger.Faulkner@Sun.COM 		for (sig = 1; sig < NSIG; sig++) {
1557930SRoger.Faulkner@Sun.COM 			if (sigismember(&sap->sa_sigignore, sig))
1567930SRoger.Faulkner@Sun.COM 				(void) __sigaction(sig, &action, NULL);
1577930SRoger.Faulkner@Sun.COM 		}
1587930SRoger.Faulkner@Sun.COM 	}
1597930SRoger.Faulkner@Sun.COM 
1600Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) {
1617930SRoger.Faulkner@Sun.COM 		(void) memset(&action, 0, sizeof (action));
1627930SRoger.Faulkner@Sun.COM 		action.sa_handler = SIG_DFL;
1630Sstevel@tonic-gate 		for (sig = 1; sig < NSIG; sig++) {
1646515Sraf 			if (sigismember(&sap->sa_sigdefault, sig))
1657930SRoger.Faulkner@Sun.COM 				(void) __sigaction(sig, &action, NULL);
1660Sstevel@tonic-gate 		}
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) {
1706515Sraf 		if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
1713086Sraf 			return (errno);
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) {
1756515Sraf 		if (setpgid(0, sap->sa_pgroup) != 0)
1763086Sraf 			return (errno);
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) {
1806247Sraf 		if (setparam(P_LWPID, P_MYID,
1816247Sraf 		    sap->sa_schedpolicy, sap->sa_priority) == -1)
1823086Sraf 			return (errno);
1830Sstevel@tonic-gate 	} else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) {
1846247Sraf 		if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1)
1853086Sraf 			return (errno);
1860Sstevel@tonic-gate 	}
1873086Sraf 
1883086Sraf 	return (0);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1913086Sraf static int
1928877SRoger.Faulkner@Sun.COM perform_file_actions(file_attr_t *fap, void *dirbuf)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	file_attr_t *froot = fap;
1950Sstevel@tonic-gate 	int fd;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	do {
1980Sstevel@tonic-gate 		switch (fap->fa_type) {
1990Sstevel@tonic-gate 		case FA_OPEN:
200*11798SRoger.Faulkner@Sun.COM 			fd = __open(fap->fa_path, fap->fa_oflag, fap->fa_mode);
2010Sstevel@tonic-gate 			if (fd < 0)
2023086Sraf 				return (errno);
2030Sstevel@tonic-gate 			if (fd != fap->fa_filedes) {
2046515Sraf 				if (__fcntl(fd, F_DUP2FD, fap->fa_filedes) < 0)
2053086Sraf 					return (errno);
2066515Sraf 				(void) __close(fd);
2070Sstevel@tonic-gate 			}
2080Sstevel@tonic-gate 			break;
2090Sstevel@tonic-gate 		case FA_CLOSE:
2108877SRoger.Faulkner@Sun.COM 			if (__close(fap->fa_filedes) == -1 &&
2118877SRoger.Faulkner@Sun.COM 			    errno != EBADF)	/* already closed, no error */
2123086Sraf 				return (errno);
2130Sstevel@tonic-gate 			break;
2140Sstevel@tonic-gate 		case FA_DUP2:
2156515Sraf 			fd = __fcntl(fap->fa_filedes, F_DUP2FD,
2165891Sraf 			    fap->fa_newfiledes);
2170Sstevel@tonic-gate 			if (fd < 0)
2183086Sraf 				return (errno);
2190Sstevel@tonic-gate 			break;
2208877SRoger.Faulkner@Sun.COM 		case FA_CLOSEFROM:
2218877SRoger.Faulkner@Sun.COM 			if (spawn_closefrom(fap->fa_filedes, dirbuf))
2228877SRoger.Faulkner@Sun.COM 				return (errno);
2238877SRoger.Faulkner@Sun.COM 			break;
2240Sstevel@tonic-gate 		}
2250Sstevel@tonic-gate 	} while ((fap = fap->fa_next) != froot);
2263086Sraf 
2273086Sraf 	return (0);
2283086Sraf }
2293086Sraf 
2303235Sraf static int
2313235Sraf forkflags(spawn_attr_t *sap)
2323235Sraf {
2333235Sraf 	int flags = 0;
2343235Sraf 
2353235Sraf 	if (sap != NULL) {
2363235Sraf 		if (sap->sa_psflags & POSIX_SPAWN_NOSIGCHLD_NP)
2373235Sraf 			flags |= FORK_NOSIGCHLD;
2383235Sraf 		if (sap->sa_psflags & POSIX_SPAWN_WAITPID_NP)
2393235Sraf 			flags |= FORK_WAITPID;
2403235Sraf 	}
2413235Sraf 
2423235Sraf 	return (flags);
2433235Sraf }
2443235Sraf 
2453086Sraf /*
2463086Sraf  * set_error() / get_error() are used to guarantee that the local variable
2473086Sraf  * 'error' is set correctly in memory on return from vfork() in the parent.
2483086Sraf  */
2493086Sraf 
2503086Sraf static int
2513086Sraf set_error(int *errp, int err)
2523086Sraf {
2533086Sraf 	return (*errp = err);
2543086Sraf }
2553086Sraf 
2563086Sraf static int
2573086Sraf get_error(int *errp)
2583086Sraf {
2593086Sraf 	return (*errp);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate /*
2630Sstevel@tonic-gate  * For MT safety, do not invoke the dynamic linker after calling vfork().
2640Sstevel@tonic-gate  * If some other thread was in the dynamic linker when this thread's parent
2650Sstevel@tonic-gate  * called vfork() then the dynamic linker's lock would still be held here
2660Sstevel@tonic-gate  * (with a defunct owner) and we would deadlock ourself if we invoked it.
2670Sstevel@tonic-gate  *
2680Sstevel@tonic-gate  * Therefore, all of the functions we call here after returning from
2696812Sraf  * vforkx() in the child are not and must never be exported from libc
2700Sstevel@tonic-gate  * as global symbols.  To do so would risk invoking the dynamic linker.
2710Sstevel@tonic-gate  */
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate int
2746812Sraf posix_spawn(
2750Sstevel@tonic-gate 	pid_t *pidp,
2760Sstevel@tonic-gate 	const char *path,
2770Sstevel@tonic-gate 	const posix_spawn_file_actions_t *file_actions,
2780Sstevel@tonic-gate 	const posix_spawnattr_t *attrp,
2790Sstevel@tonic-gate 	char *const argv[],
2800Sstevel@tonic-gate 	char *const envp[])
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
2830Sstevel@tonic-gate 	file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
2848877SRoger.Faulkner@Sun.COM 	void *dirbuf = NULL;
2853086Sraf 	int error;		/* this will be set by the child */
2860Sstevel@tonic-gate 	pid_t pid;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	if (attrp != NULL && sap == NULL)
2890Sstevel@tonic-gate 		return (EINVAL);
2900Sstevel@tonic-gate 
2918877SRoger.Faulkner@Sun.COM 	if (fap != NULL && fap->fa_need_dirbuf) {
2928877SRoger.Faulkner@Sun.COM 		/*
2938877SRoger.Faulkner@Sun.COM 		 * Preallocate the buffer for the call to getdents64() in
2948877SRoger.Faulkner@Sun.COM 		 * spawn_closefrom() since we can't do it in the vfork() child.
2958877SRoger.Faulkner@Sun.COM 		 */
2968877SRoger.Faulkner@Sun.COM 		if ((dirbuf = lmalloc(DIRBUF)) == NULL)
2978877SRoger.Faulkner@Sun.COM 			return (ENOMEM);
2988877SRoger.Faulkner@Sun.COM 	}
2998877SRoger.Faulkner@Sun.COM 
3006812Sraf 	switch (pid = vforkx(forkflags(sap))) {
3010Sstevel@tonic-gate 	case 0:			/* child */
3020Sstevel@tonic-gate 		break;
3030Sstevel@tonic-gate 	case -1:		/* parent, failure */
3048877SRoger.Faulkner@Sun.COM 		if (dirbuf)
3058877SRoger.Faulkner@Sun.COM 			lfree(dirbuf, DIRBUF);
3060Sstevel@tonic-gate 		return (errno);
3070Sstevel@tonic-gate 	default:		/* parent, success */
3083086Sraf 		/*
3093086Sraf 		 * We don't get here until the child exec()s or exit()s
3103086Sraf 		 */
3113086Sraf 		if (pidp != NULL && get_error(&error) == 0)
3120Sstevel@tonic-gate 			*pidp = pid;
3138877SRoger.Faulkner@Sun.COM 		if (dirbuf)
3148877SRoger.Faulkner@Sun.COM 			lfree(dirbuf, DIRBUF);
3153086Sraf 		return (get_error(&error));
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	if (sap != NULL)
3193086Sraf 		if (set_error(&error, perform_flag_actions(sap)) != 0)
3206515Sraf 			_exit(_EVAPORATE);
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if (fap != NULL)
3238877SRoger.Faulkner@Sun.COM 		if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
3246515Sraf 			_exit(_EVAPORATE);
3250Sstevel@tonic-gate 
3263086Sraf 	(void) set_error(&error, 0);
3276515Sraf 	(void) execve(path, argv, envp);
3287635SRoger.Faulkner@Sun.COM 	if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
3297635SRoger.Faulkner@Sun.COM 		_exit(127);
3303086Sraf 	(void) set_error(&error, errno);
3316515Sraf 	_exit(_EVAPORATE);
3320Sstevel@tonic-gate 	return (0);	/* not reached */
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate /*
3360Sstevel@tonic-gate  * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c).
3370Sstevel@tonic-gate  */
3380Sstevel@tonic-gate 
3395891Sraf extern int libc__xpg4;
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate static const char *
3420Sstevel@tonic-gate execat(const char *s1, const char *s2, char *si)
3430Sstevel@tonic-gate {
3440Sstevel@tonic-gate 	int cnt = PATH_MAX + 1;
3450Sstevel@tonic-gate 	char *s;
3460Sstevel@tonic-gate 	char c;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	for (s = si; (c = *s1) != '\0' && c != ':'; s1++) {
3490Sstevel@tonic-gate 		if (cnt > 0) {
3500Sstevel@tonic-gate 			*s++ = c;
3510Sstevel@tonic-gate 			cnt--;
3520Sstevel@tonic-gate 		}
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 	if (si != s && cnt > 0) {
3550Sstevel@tonic-gate 		*s++ = '/';
3560Sstevel@tonic-gate 		cnt--;
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 	for (; (c = *s2) != '\0' && cnt > 0; s2++) {
3590Sstevel@tonic-gate 		*s++ = c;
3600Sstevel@tonic-gate 		cnt--;
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate 	*s = '\0';
3630Sstevel@tonic-gate 	return (*s1? ++s1: NULL);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate /* ARGSUSED */
3670Sstevel@tonic-gate int
3686812Sraf posix_spawnp(
3690Sstevel@tonic-gate 	pid_t *pidp,
3700Sstevel@tonic-gate 	const char *file,
3710Sstevel@tonic-gate 	const posix_spawn_file_actions_t *file_actions,
3720Sstevel@tonic-gate 	const posix_spawnattr_t *attrp,
3730Sstevel@tonic-gate 	char *const argv[],
3740Sstevel@tonic-gate 	char *const envp[])
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate 	spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
3770Sstevel@tonic-gate 	file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
3788877SRoger.Faulkner@Sun.COM 	void *dirbuf = NULL;
3790Sstevel@tonic-gate 	const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : "";
3805891Sraf 	int xpg4 = libc__xpg4;
3817646SRoger.Faulkner@Sun.COM 	int error = 0;		/* this will be set by the child */
3820Sstevel@tonic-gate 	char path[PATH_MAX+4];
3830Sstevel@tonic-gate 	const char *cp;
3840Sstevel@tonic-gate 	pid_t pid;
3850Sstevel@tonic-gate 	char **newargs;
3860Sstevel@tonic-gate 	int argc;
3870Sstevel@tonic-gate 	int i;
3880Sstevel@tonic-gate 	static const char *sun_path = "/bin/sh";
3890Sstevel@tonic-gate 	static const char *xpg4_path = "/usr/xpg4/bin/sh";
3900Sstevel@tonic-gate 	static const char *shell = "sh";
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	if (attrp != NULL && sap == NULL)
3930Sstevel@tonic-gate 		return (EINVAL);
3940Sstevel@tonic-gate 
3953086Sraf 	if (*file == '\0')
3963086Sraf 		return (EACCES);
3973086Sraf 
3988877SRoger.Faulkner@Sun.COM 	if (fap != NULL && fap->fa_need_dirbuf) {
3998877SRoger.Faulkner@Sun.COM 		/*
4008877SRoger.Faulkner@Sun.COM 		 * Preallocate the buffer for the call to getdents64() in
4018877SRoger.Faulkner@Sun.COM 		 * spawn_closefrom() since we can't do it in the vfork() child.
4028877SRoger.Faulkner@Sun.COM 		 */
4038877SRoger.Faulkner@Sun.COM 		if ((dirbuf = lmalloc(DIRBUF)) == NULL)
4048877SRoger.Faulkner@Sun.COM 			return (ENOMEM);
4058877SRoger.Faulkner@Sun.COM 	}
4068877SRoger.Faulkner@Sun.COM 
4070Sstevel@tonic-gate 	/*
4080Sstevel@tonic-gate 	 * We may need to invoke the shell with a slightly modified
4090Sstevel@tonic-gate 	 * argv[] array.  To do this we need to preallocate the array.
4100Sstevel@tonic-gate 	 * We must call alloca() before calling vfork() because doing
4110Sstevel@tonic-gate 	 * it after vfork() (in the child) would corrupt the parent.
4120Sstevel@tonic-gate 	 */
4130Sstevel@tonic-gate 	for (argc = 0; argv[argc] != NULL; argc++)
4140Sstevel@tonic-gate 		continue;
4150Sstevel@tonic-gate 	newargs = alloca((argc + 2) * sizeof (char *));
4160Sstevel@tonic-gate 
4176812Sraf 	switch (pid = vforkx(forkflags(sap))) {
4180Sstevel@tonic-gate 	case 0:			/* child */
4190Sstevel@tonic-gate 		break;
4200Sstevel@tonic-gate 	case -1:		/* parent, failure */
4218877SRoger.Faulkner@Sun.COM 		if (dirbuf)
4228877SRoger.Faulkner@Sun.COM 			lfree(dirbuf, DIRBUF);
4230Sstevel@tonic-gate 		return (errno);
4240Sstevel@tonic-gate 	default:		/* parent, success */
4253086Sraf 		/*
4263086Sraf 		 * We don't get here until the child exec()s or exit()s
4273086Sraf 		 */
4283086Sraf 		if (pidp != NULL && get_error(&error) == 0)
4290Sstevel@tonic-gate 			*pidp = pid;
4308877SRoger.Faulkner@Sun.COM 		if (dirbuf)
4318877SRoger.Faulkner@Sun.COM 			lfree(dirbuf, DIRBUF);
4323086Sraf 		return (get_error(&error));
4330Sstevel@tonic-gate 	}
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	if (sap != NULL)
4363086Sraf 		if (set_error(&error, perform_flag_actions(sap)) != 0)
4376515Sraf 			_exit(_EVAPORATE);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	if (fap != NULL)
4408877SRoger.Faulkner@Sun.COM 		if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
4416515Sraf 			_exit(_EVAPORATE);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	if (pathstr == NULL) {
4440Sstevel@tonic-gate 		/*
4450Sstevel@tonic-gate 		 * XPG4:  pathstr is equivalent to _CS_PATH, except that
4460Sstevel@tonic-gate 		 * :/usr/sbin is appended when root, and pathstr must end
4470Sstevel@tonic-gate 		 * with a colon when not root.  Keep these paths in sync
4480Sstevel@tonic-gate 		 * with _CS_PATH in confstr.c.  Note that pathstr must end
4490Sstevel@tonic-gate 		 * with a colon when not root so that when file doesn't
4500Sstevel@tonic-gate 		 * contain '/', the last call to execat() will result in an
4510Sstevel@tonic-gate 		 * attempt to execv file from the current directory.
4520Sstevel@tonic-gate 		 */
4536515Sraf 		if (geteuid() == 0 || getuid() == 0) {
4540Sstevel@tonic-gate 			if (!xpg4)
4550Sstevel@tonic-gate 				pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin";
4560Sstevel@tonic-gate 			else
4570Sstevel@tonic-gate 				pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
4580Sstevel@tonic-gate 				    "/usr/bin:/opt/SUNWspro/bin:/usr/sbin";
4590Sstevel@tonic-gate 		} else {
4600Sstevel@tonic-gate 			if (!xpg4)
4610Sstevel@tonic-gate 				pathstr = "/usr/ccs/bin:/usr/bin:";
4620Sstevel@tonic-gate 			else
4630Sstevel@tonic-gate 				pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
4640Sstevel@tonic-gate 				    "/usr/bin:/opt/SUNWspro/bin:";
4650Sstevel@tonic-gate 		}
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	cp = pathstr;
4690Sstevel@tonic-gate 	do {
4700Sstevel@tonic-gate 		cp = execat(cp, file, path);
4710Sstevel@tonic-gate 		/*
4720Sstevel@tonic-gate 		 * 4025035 and 4038378
4730Sstevel@tonic-gate 		 * if a filename begins with a "-" prepend "./" so that
4740Sstevel@tonic-gate 		 * the shell can't interpret it as an option
4750Sstevel@tonic-gate 		 */
4760Sstevel@tonic-gate 		if (*path == '-') {
4770Sstevel@tonic-gate 			char *s;
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 			for (s = path; *s != '\0'; s++)
4800Sstevel@tonic-gate 				continue;
4810Sstevel@tonic-gate 			for (; s >= path; s--)
4820Sstevel@tonic-gate 				*(s + 2) = *s;
4830Sstevel@tonic-gate 			path[0] = '.';
4840Sstevel@tonic-gate 			path[1] = '/';
4850Sstevel@tonic-gate 		}
4863086Sraf 		(void) set_error(&error, 0);
4876515Sraf 		(void) execve(path, argv, envp);
4883086Sraf 		if (set_error(&error, errno) == ENOEXEC) {
4890Sstevel@tonic-gate 			newargs[0] = (char *)shell;
4900Sstevel@tonic-gate 			newargs[1] = path;
4910Sstevel@tonic-gate 			for (i = 1; i <= argc; i++)
4920Sstevel@tonic-gate 				newargs[i + 1] = argv[i];
4933086Sraf 			(void) set_error(&error, 0);
4946515Sraf 			(void) execve(xpg4? xpg4_path : sun_path,
4953086Sraf 			    newargs, envp);
4967635SRoger.Faulkner@Sun.COM 			if (sap != NULL &&
4977635SRoger.Faulkner@Sun.COM 			    (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
4987635SRoger.Faulkner@Sun.COM 				_exit(127);
4993086Sraf 			(void) set_error(&error, errno);
5006515Sraf 			_exit(_EVAPORATE);
5010Sstevel@tonic-gate 		}
5020Sstevel@tonic-gate 	} while (cp);
5037646SRoger.Faulkner@Sun.COM 
5047646SRoger.Faulkner@Sun.COM 	if (sap != NULL &&
5057646SRoger.Faulkner@Sun.COM 	    (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) {
5067646SRoger.Faulkner@Sun.COM 		(void) set_error(&error, 0);
5077646SRoger.Faulkner@Sun.COM 		_exit(127);
5087646SRoger.Faulkner@Sun.COM 	}
5096515Sraf 	_exit(_EVAPORATE);
5100Sstevel@tonic-gate 	return (0);	/* not reached */
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate int
5146812Sraf posix_spawn_file_actions_init(
5150Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions)
5160Sstevel@tonic-gate {
5170Sstevel@tonic-gate 	file_actions->__file_attrp = NULL;
5180Sstevel@tonic-gate 	return (0);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate int
5226812Sraf posix_spawn_file_actions_destroy(
5230Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions)
5240Sstevel@tonic-gate {
5250Sstevel@tonic-gate 	file_attr_t *froot = file_actions->__file_attrp;
5260Sstevel@tonic-gate 	file_attr_t *fap;
5270Sstevel@tonic-gate 	file_attr_t *next;
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	if ((fap = froot) != NULL) {
5300Sstevel@tonic-gate 		do {
5310Sstevel@tonic-gate 			next = fap->fa_next;
5328877SRoger.Faulkner@Sun.COM 			if (fap->fa_type == FA_OPEN)
5330Sstevel@tonic-gate 				lfree(fap->fa_path, fap->fa_pathsize);
5340Sstevel@tonic-gate 			lfree(fap, sizeof (*fap));
5350Sstevel@tonic-gate 		} while ((fap = next) != froot);
5360Sstevel@tonic-gate 	}
5370Sstevel@tonic-gate 	file_actions->__file_attrp = NULL;
5380Sstevel@tonic-gate 	return (0);
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate static void
5420Sstevel@tonic-gate add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap)
5430Sstevel@tonic-gate {
5440Sstevel@tonic-gate 	file_attr_t *froot = file_actions->__file_attrp;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	if (froot == NULL) {
5470Sstevel@tonic-gate 		fap->fa_next = fap->fa_prev = fap;
5488877SRoger.Faulkner@Sun.COM 		file_actions->__file_attrp = froot = fap;
5490Sstevel@tonic-gate 	} else {
5500Sstevel@tonic-gate 		fap->fa_next = froot;
5510Sstevel@tonic-gate 		fap->fa_prev = froot->fa_prev;
5520Sstevel@tonic-gate 		froot->fa_prev->fa_next = fap;
5530Sstevel@tonic-gate 		froot->fa_prev = fap;
5540Sstevel@tonic-gate 	}
5558877SRoger.Faulkner@Sun.COM 
5568877SRoger.Faulkner@Sun.COM 	/*
5578877SRoger.Faulkner@Sun.COM 	 * Once set, __file_attrp no longer changes, so this assignment
5588877SRoger.Faulkner@Sun.COM 	 * always goes into the first element in the list, as required.
5598877SRoger.Faulkner@Sun.COM 	 */
5608877SRoger.Faulkner@Sun.COM 	if (fap->fa_type == FA_CLOSEFROM)
5618877SRoger.Faulkner@Sun.COM 		froot->fa_need_dirbuf = 1;
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate int
5656812Sraf posix_spawn_file_actions_addopen(
5660Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
5670Sstevel@tonic-gate 	int filedes,
5680Sstevel@tonic-gate 	const char *path,
5690Sstevel@tonic-gate 	int oflag,
5700Sstevel@tonic-gate 	mode_t mode)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 	file_attr_t *fap;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if (filedes < 0)
5750Sstevel@tonic-gate 		return (EBADF);
5760Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
5770Sstevel@tonic-gate 		return (ENOMEM);
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	fap->fa_pathsize = strlen(path) + 1;
5800Sstevel@tonic-gate 	if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) {
5810Sstevel@tonic-gate 		lfree(fap, sizeof (*fap));
5820Sstevel@tonic-gate 		return (ENOMEM);
5830Sstevel@tonic-gate 	}
5840Sstevel@tonic-gate 	(void) strcpy(fap->fa_path, path);
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	fap->fa_type = FA_OPEN;
5870Sstevel@tonic-gate 	fap->fa_oflag = oflag;
5880Sstevel@tonic-gate 	fap->fa_mode = mode;
5890Sstevel@tonic-gate 	fap->fa_filedes = filedes;
5900Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	return (0);
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate int
5966812Sraf posix_spawn_file_actions_addclose(
5970Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
5980Sstevel@tonic-gate 	int filedes)
5990Sstevel@tonic-gate {
6000Sstevel@tonic-gate 	file_attr_t *fap;
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	if (filedes < 0)
6030Sstevel@tonic-gate 		return (EBADF);
6040Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
6050Sstevel@tonic-gate 		return (ENOMEM);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	fap->fa_type = FA_CLOSE;
6080Sstevel@tonic-gate 	fap->fa_filedes = filedes;
6090Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	return (0);
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate int
6156812Sraf posix_spawn_file_actions_adddup2(
6160Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
6170Sstevel@tonic-gate 	int filedes,
6180Sstevel@tonic-gate 	int newfiledes)
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate 	file_attr_t *fap;
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	if (filedes < 0 || newfiledes < 0)
6230Sstevel@tonic-gate 		return (EBADF);
6240Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
6250Sstevel@tonic-gate 		return (ENOMEM);
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	fap->fa_type = FA_DUP2;
6280Sstevel@tonic-gate 	fap->fa_filedes = filedes;
6290Sstevel@tonic-gate 	fap->fa_newfiledes = newfiledes;
6300Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	return (0);
6330Sstevel@tonic-gate }
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate int
6368877SRoger.Faulkner@Sun.COM posix_spawn_file_actions_addclosefrom_np(
6378877SRoger.Faulkner@Sun.COM 	posix_spawn_file_actions_t *file_actions,
6388877SRoger.Faulkner@Sun.COM 	int lowfiledes)
6398877SRoger.Faulkner@Sun.COM {
6408877SRoger.Faulkner@Sun.COM 	file_attr_t *fap;
6418877SRoger.Faulkner@Sun.COM 
6428877SRoger.Faulkner@Sun.COM 	if (lowfiledes < 0)
6438877SRoger.Faulkner@Sun.COM 		return (EBADF);
6448877SRoger.Faulkner@Sun.COM 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
6458877SRoger.Faulkner@Sun.COM 		return (ENOMEM);
6468877SRoger.Faulkner@Sun.COM 	fap->fa_type = FA_CLOSEFROM;
6478877SRoger.Faulkner@Sun.COM 	fap->fa_filedes = lowfiledes;
6488877SRoger.Faulkner@Sun.COM 	add_file_attr(file_actions, fap);
6498877SRoger.Faulkner@Sun.COM 
6508877SRoger.Faulkner@Sun.COM 	return (0);
6518877SRoger.Faulkner@Sun.COM }
6528877SRoger.Faulkner@Sun.COM 
6538877SRoger.Faulkner@Sun.COM int
6546812Sraf posix_spawnattr_init(
6550Sstevel@tonic-gate 	posix_spawnattr_t *attr)
6560Sstevel@tonic-gate {
6573235Sraf 	if ((attr->__spawn_attrp = lmalloc(sizeof (posix_spawnattr_t))) == NULL)
6580Sstevel@tonic-gate 		return (ENOMEM);
6590Sstevel@tonic-gate 	/*
6600Sstevel@tonic-gate 	 * Add default stuff here?
6610Sstevel@tonic-gate 	 */
6620Sstevel@tonic-gate 	return (0);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate int
6666812Sraf posix_spawnattr_destroy(
6670Sstevel@tonic-gate 	posix_spawnattr_t *attr)
6680Sstevel@tonic-gate {
6690Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	if (sap == NULL)
6720Sstevel@tonic-gate 		return (EINVAL);
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	/*
6750Sstevel@tonic-gate 	 * deallocate stuff here?
6760Sstevel@tonic-gate 	 */
6770Sstevel@tonic-gate 	lfree(sap, sizeof (*sap));
6780Sstevel@tonic-gate 	attr->__spawn_attrp = NULL;
6790Sstevel@tonic-gate 	return (0);
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate int
6836812Sraf posix_spawnattr_setflags(
6840Sstevel@tonic-gate 	posix_spawnattr_t *attr,
6850Sstevel@tonic-gate 	short flags)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (sap == NULL ||
6900Sstevel@tonic-gate 	    (flags & ~ALL_POSIX_SPAWN_FLAGS))
6910Sstevel@tonic-gate 		return (EINVAL);
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	sap->sa_psflags = flags;
6940Sstevel@tonic-gate 	return (0);
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate int
6986812Sraf posix_spawnattr_getflags(
6990Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7000Sstevel@tonic-gate 	short *flags)
7010Sstevel@tonic-gate {
7020Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	if (sap == NULL)
7050Sstevel@tonic-gate 		return (EINVAL);
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	*flags = sap->sa_psflags;
7080Sstevel@tonic-gate 	return (0);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate int
7126812Sraf posix_spawnattr_setpgroup(
7130Sstevel@tonic-gate 	posix_spawnattr_t *attr,
7140Sstevel@tonic-gate 	pid_t pgroup)
7150Sstevel@tonic-gate {
7160Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	if (sap == NULL)
7190Sstevel@tonic-gate 		return (EINVAL);
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	sap->sa_pgroup = pgroup;
7220Sstevel@tonic-gate 	return (0);
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate int
7266812Sraf posix_spawnattr_getpgroup(
7270Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7280Sstevel@tonic-gate 	pid_t *pgroup)
7290Sstevel@tonic-gate {
7300Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	if (sap == NULL)
7330Sstevel@tonic-gate 		return (EINVAL);
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	*pgroup = sap->sa_pgroup;
7360Sstevel@tonic-gate 	return (0);
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate int
7406812Sraf posix_spawnattr_setschedparam(
7410Sstevel@tonic-gate 	posix_spawnattr_t *attr,
7420Sstevel@tonic-gate 	const struct sched_param *schedparam)
7430Sstevel@tonic-gate {
7440Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	if (sap == NULL)
7470Sstevel@tonic-gate 		return (EINVAL);
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	/*
7500Sstevel@tonic-gate 	 * Check validity?
7510Sstevel@tonic-gate 	 */
7520Sstevel@tonic-gate 	sap->sa_priority = schedparam->sched_priority;
7530Sstevel@tonic-gate 	return (0);
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate int
7576812Sraf posix_spawnattr_getschedparam(
7580Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7590Sstevel@tonic-gate 	struct sched_param *schedparam)
7600Sstevel@tonic-gate {
7610Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	if (sap == NULL)
7640Sstevel@tonic-gate 		return (EINVAL);
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	schedparam->sched_priority = sap->sa_priority;
7670Sstevel@tonic-gate 	return (0);
7680Sstevel@tonic-gate }
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate int
7716812Sraf posix_spawnattr_setschedpolicy(
7720Sstevel@tonic-gate 	posix_spawnattr_t *attr,
7730Sstevel@tonic-gate 	int schedpolicy)
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7760Sstevel@tonic-gate 
7776247Sraf 	if (sap == NULL || schedpolicy == SCHED_SYS)
7780Sstevel@tonic-gate 		return (EINVAL);
7790Sstevel@tonic-gate 
7806247Sraf 	/*
7816247Sraf 	 * Cache the policy information for later use
7826247Sraf 	 * by the vfork() child of posix_spawn().
7836247Sraf 	 */
7846247Sraf 	if (get_info_by_policy(schedpolicy) == NULL)
7856247Sraf 		return (errno);
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	sap->sa_schedpolicy = schedpolicy;
7880Sstevel@tonic-gate 	return (0);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate int
7926812Sraf posix_spawnattr_getschedpolicy(
7930Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7940Sstevel@tonic-gate 	int *schedpolicy)
7950Sstevel@tonic-gate {
7960Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	if (sap == NULL)
7990Sstevel@tonic-gate 		return (EINVAL);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	*schedpolicy = sap->sa_schedpolicy;
8020Sstevel@tonic-gate 	return (0);
8030Sstevel@tonic-gate }
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate int
8066812Sraf posix_spawnattr_setsigdefault(
8070Sstevel@tonic-gate 	posix_spawnattr_t *attr,
8080Sstevel@tonic-gate 	const sigset_t *sigdefault)
8090Sstevel@tonic-gate {
8100Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	if (sap == NULL)
8130Sstevel@tonic-gate 		return (EINVAL);
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	sap->sa_sigdefault = *sigdefault;
8160Sstevel@tonic-gate 	return (0);
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate int
8206812Sraf posix_spawnattr_getsigdefault(
8210Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
8220Sstevel@tonic-gate 	sigset_t *sigdefault)
8230Sstevel@tonic-gate {
8240Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	if (sap == NULL)
8270Sstevel@tonic-gate 		return (EINVAL);
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	*sigdefault = sap->sa_sigdefault;
8300Sstevel@tonic-gate 	return (0);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate int
8347930SRoger.Faulkner@Sun.COM posix_spawnattr_setsigignore_np(
8357930SRoger.Faulkner@Sun.COM 	posix_spawnattr_t *attr,
8367930SRoger.Faulkner@Sun.COM 	const sigset_t *sigignore)
8377930SRoger.Faulkner@Sun.COM {
8387930SRoger.Faulkner@Sun.COM 	spawn_attr_t *sap = attr->__spawn_attrp;
8397930SRoger.Faulkner@Sun.COM 
8407930SRoger.Faulkner@Sun.COM 	if (sap == NULL)
8417930SRoger.Faulkner@Sun.COM 		return (EINVAL);
8427930SRoger.Faulkner@Sun.COM 
8437930SRoger.Faulkner@Sun.COM 	sap->sa_sigignore = *sigignore;
8447930SRoger.Faulkner@Sun.COM 	return (0);
8457930SRoger.Faulkner@Sun.COM }
8467930SRoger.Faulkner@Sun.COM 
8477930SRoger.Faulkner@Sun.COM int
8487930SRoger.Faulkner@Sun.COM posix_spawnattr_getsigignore_np(
8497930SRoger.Faulkner@Sun.COM 	const posix_spawnattr_t *attr,
8507930SRoger.Faulkner@Sun.COM 	sigset_t *sigignore)
8517930SRoger.Faulkner@Sun.COM {
8527930SRoger.Faulkner@Sun.COM 	spawn_attr_t *sap = attr->__spawn_attrp;
8537930SRoger.Faulkner@Sun.COM 
8547930SRoger.Faulkner@Sun.COM 	if (sap == NULL)
8557930SRoger.Faulkner@Sun.COM 		return (EINVAL);
8567930SRoger.Faulkner@Sun.COM 
8577930SRoger.Faulkner@Sun.COM 	*sigignore = sap->sa_sigignore;
8587930SRoger.Faulkner@Sun.COM 	return (0);
8597930SRoger.Faulkner@Sun.COM }
8607930SRoger.Faulkner@Sun.COM 
8617930SRoger.Faulkner@Sun.COM int
8626812Sraf posix_spawnattr_setsigmask(
8630Sstevel@tonic-gate 	posix_spawnattr_t *attr,
8640Sstevel@tonic-gate 	const sigset_t *sigmask)
8650Sstevel@tonic-gate {
8660Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	if (sap == NULL)
8690Sstevel@tonic-gate 		return (EINVAL);
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	sap->sa_sigmask = *sigmask;
8720Sstevel@tonic-gate 	return (0);
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate int
8766812Sraf posix_spawnattr_getsigmask(
8770Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
8780Sstevel@tonic-gate 	sigset_t *sigmask)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	if (sap == NULL)
8830Sstevel@tonic-gate 		return (EINVAL);
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	*sigmask = sap->sa_sigmask;
8860Sstevel@tonic-gate 	return (0);
8870Sstevel@tonic-gate }
888