xref: /titanic_51/usr/src/lib/libc/port/threads/spawn.c (revision 10a6478a64c986fe8b918521951c9068ed5588fe)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5f841f6adSraf  * Common Development and Distribution License (the "License").
6f841f6adSraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21f841f6adSraf 
227c478bd9Sstevel@tonic-gate /*
238fd04b83SRoger A. Faulkner  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27462453d2SMatthew Ahrens /*
28462453d2SMatthew Ahrens  * Copyright (c) 2011 by Delphix. All rights reserved.
29462453d2SMatthew Ahrens  */
30462453d2SMatthew Ahrens 
317c478bd9Sstevel@tonic-gate #include "lint.h"
327c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
338ceba33eSraf #include <sys/libc_kernel.h>
347c478bd9Sstevel@tonic-gate #include <sys/procset.h>
35657b1f3dSraf #include <sys/fork.h>
3608556f6cSRoger A. Faulkner #include <dirent.h>
377c478bd9Sstevel@tonic-gate #include <alloca.h>
387c478bd9Sstevel@tonic-gate #include <spawn.h>
396a5408e6SRichard Lowe #include <paths.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #define	ALL_POSIX_SPAWN_FLAGS			\
427c478bd9Sstevel@tonic-gate 		(POSIX_SPAWN_RESETIDS |		\
437c478bd9Sstevel@tonic-gate 		POSIX_SPAWN_SETPGROUP |		\
447c478bd9Sstevel@tonic-gate 		POSIX_SPAWN_SETSIGDEF |		\
457c478bd9Sstevel@tonic-gate 		POSIX_SPAWN_SETSIGMASK |	\
467c478bd9Sstevel@tonic-gate 		POSIX_SPAWN_SETSCHEDPARAM |	\
47657b1f3dSraf 		POSIX_SPAWN_SETSCHEDULER |	\
4803bc411dSRoger A. Faulkner 		POSIX_SPAWN_SETSIGIGN_NP |	\
49657b1f3dSraf 		POSIX_SPAWN_NOSIGCHLD_NP |	\
50f9f6ed06SRoger A. Faulkner 		POSIX_SPAWN_WAITPID_NP |	\
51f9f6ed06SRoger A. Faulkner 		POSIX_SPAWN_NOEXECERR_NP)
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate typedef struct {
54d4204c85Sraf 	int		sa_psflags;	/* POSIX_SPAWN_* flags */
55d4204c85Sraf 	int		sa_priority;
567c478bd9Sstevel@tonic-gate 	int		sa_schedpolicy;
577c478bd9Sstevel@tonic-gate 	pid_t		sa_pgroup;
587c478bd9Sstevel@tonic-gate 	sigset_t	sa_sigdefault;
5903bc411dSRoger A. Faulkner 	sigset_t	sa_sigignore;
607c478bd9Sstevel@tonic-gate 	sigset_t	sa_sigmask;
617c478bd9Sstevel@tonic-gate } spawn_attr_t;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate typedef struct file_attr {
647c478bd9Sstevel@tonic-gate 	struct file_attr *fa_next;	/* circular list of file actions */
657c478bd9Sstevel@tonic-gate 	struct file_attr *fa_prev;
6608556f6cSRoger A. Faulkner 	enum {FA_OPEN, FA_CLOSE, FA_DUP2, FA_CLOSEFROM} fa_type;
6708556f6cSRoger A. Faulkner 	int		fa_need_dirbuf;	/* only consulted in the head action */
687c478bd9Sstevel@tonic-gate 	char		*fa_path;	/* copied pathname for open() */
6908556f6cSRoger A. Faulkner 	uint_t		fa_pathsize;	/* size of fa_path[] array */
707c478bd9Sstevel@tonic-gate 	int		fa_oflag;	/* oflag for open() */
717c478bd9Sstevel@tonic-gate 	mode_t		fa_mode;	/* mode for open() */
727c478bd9Sstevel@tonic-gate 	int		fa_filedes;	/* file descriptor for open()/close() */
737c478bd9Sstevel@tonic-gate 	int		fa_newfiledes;	/* new file descriptor for dup2() */
747c478bd9Sstevel@tonic-gate } file_attr_t;
757c478bd9Sstevel@tonic-gate 
7608556f6cSRoger A. Faulkner #if defined(_LP64)
7708556f6cSRoger A. Faulkner #define	__open64	__open
7808556f6cSRoger A. Faulkner #define	getdents64	getdents
7908556f6cSRoger A. Faulkner #define	dirent64_t	dirent_t
8008556f6cSRoger A. Faulkner #else
8108556f6cSRoger A. Faulkner extern int getdents64(int, dirent64_t *, size_t);
8208556f6cSRoger A. Faulkner #endif
8308556f6cSRoger A. Faulkner 
84462453d2SMatthew Ahrens extern const char **_environ;
85462453d2SMatthew Ahrens 
8608556f6cSRoger A. Faulkner /*
8708556f6cSRoger A. Faulkner  * Support function:
8808556f6cSRoger A. Faulkner  * Close all open file descriptors greater than or equal to lowfd.
8908556f6cSRoger A. Faulkner  * This is executed in the child of vfork(), so we must not call
9008556f6cSRoger A. Faulkner  * opendir() / readdir() because that would alter the parent's
9108556f6cSRoger A. Faulkner  * address space.  We use the low-level getdents64() system call.
9208556f6cSRoger A. Faulkner  * Return non-zero on error.
9308556f6cSRoger A. Faulkner  */
9408556f6cSRoger A. Faulkner static int
9508556f6cSRoger A. Faulkner spawn_closefrom(int lowfd, void *buf)
9608556f6cSRoger A. Faulkner {
9708556f6cSRoger A. Faulkner 	int procfd;
9808556f6cSRoger A. Faulkner 	int fd;
9908556f6cSRoger A. Faulkner 	int buflen;
10008556f6cSRoger A. Faulkner 	dirent64_t *dp;
10108556f6cSRoger A. Faulkner 	dirent64_t *dpend;
10208556f6cSRoger A. Faulkner 
10308556f6cSRoger A. Faulkner 	if (lowfd <  0)
10408556f6cSRoger A. Faulkner 		lowfd = 0;
10508556f6cSRoger A. Faulkner 
10608556f6cSRoger A. Faulkner 	/*
10708556f6cSRoger A. Faulkner 	 * Close lowfd right away as a hedge against failing
10808556f6cSRoger A. Faulkner 	 * to open the /proc file descriptor directory due
10908556f6cSRoger A. Faulkner 	 * all file descriptors being currently used up.
11008556f6cSRoger A. Faulkner 	 */
11108556f6cSRoger A. Faulkner 	(void) __close(lowfd++);
11208556f6cSRoger A. Faulkner 
11308556f6cSRoger A. Faulkner 	if ((procfd = __open64("/proc/self/fd", O_RDONLY, 0)) < 0) {
11408556f6cSRoger A. Faulkner 		/*
11508556f6cSRoger A. Faulkner 		 * We could not open the /proc file descriptor directory.
11608556f6cSRoger A. Faulkner 		 * Just fail and be done with it.
11708556f6cSRoger A. Faulkner 		 */
11808556f6cSRoger A. Faulkner 		return (-1);
11908556f6cSRoger A. Faulkner 	}
12008556f6cSRoger A. Faulkner 
12108556f6cSRoger A. Faulkner 	for (;;) {
12208556f6cSRoger A. Faulkner 		/*
12308556f6cSRoger A. Faulkner 		 * Collect a bunch of open file descriptors and close them.
12408556f6cSRoger A. Faulkner 		 * Repeat until the directory is exhausted.
12508556f6cSRoger A. Faulkner 		 */
12608556f6cSRoger A. Faulkner 		dp = (dirent64_t *)buf;
12708556f6cSRoger A. Faulkner 		if ((buflen = getdents64(procfd, dp, DIRBUF)) <= 0) {
12808556f6cSRoger A. Faulkner 			(void) __close(procfd);
12908556f6cSRoger A. Faulkner 			break;
13008556f6cSRoger A. Faulkner 		}
13108556f6cSRoger A. Faulkner 		dpend = (dirent64_t *)((uintptr_t)buf + buflen);
13208556f6cSRoger A. Faulkner 		do {
13308556f6cSRoger A. Faulkner 			/* skip '.', '..' and procfd */
13408556f6cSRoger A. Faulkner 			if (dp->d_name[0] != '.' &&
13508556f6cSRoger A. Faulkner 			    (fd = atoi(dp->d_name)) != procfd &&
13608556f6cSRoger A. Faulkner 			    fd >= lowfd)
13708556f6cSRoger A. Faulkner 				(void) __close(fd);
13808556f6cSRoger A. Faulkner 			dp = (dirent64_t *)((uintptr_t)dp + dp->d_reclen);
13908556f6cSRoger A. Faulkner 		} while (dp < dpend);
14008556f6cSRoger A. Faulkner 	}
14108556f6cSRoger A. Faulkner 
14208556f6cSRoger A. Faulkner 	return (0);
14308556f6cSRoger A. Faulkner }
14408556f6cSRoger A. Faulkner 
1458ceba33eSraf static int
1467c478bd9Sstevel@tonic-gate perform_flag_actions(spawn_attr_t *sap)
1477c478bd9Sstevel@tonic-gate {
1487c478bd9Sstevel@tonic-gate 	int sig;
14903bc411dSRoger A. Faulkner 	struct sigaction action;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) {
152bdf0047cSRoger A. Faulkner 		(void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask);
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 
15503bc411dSRoger A. Faulkner 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) {
15603bc411dSRoger A. Faulkner 		(void) memset(&action, 0, sizeof (action));
15703bc411dSRoger A. Faulkner 		action.sa_handler = SIG_IGN;
15803bc411dSRoger A. Faulkner 		for (sig = 1; sig < NSIG; sig++) {
15903bc411dSRoger A. Faulkner 			if (sigismember(&sap->sa_sigignore, sig))
16003bc411dSRoger A. Faulkner 				(void) __sigaction(sig, &action, NULL);
16103bc411dSRoger A. Faulkner 		}
16203bc411dSRoger A. Faulkner 	}
1637c478bd9Sstevel@tonic-gate 
16403bc411dSRoger A. Faulkner 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) {
16503bc411dSRoger A. Faulkner 		(void) memset(&action, 0, sizeof (action));
16603bc411dSRoger A. Faulkner 		action.sa_handler = SIG_DFL;
1677c478bd9Sstevel@tonic-gate 		for (sig = 1; sig < NSIG; sig++) {
1688cd45542Sraf 			if (sigismember(&sap->sa_sigdefault, sig))
16903bc411dSRoger A. Faulkner 				(void) __sigaction(sig, &action, NULL);
1707c478bd9Sstevel@tonic-gate 		}
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) {
1748cd45542Sraf 		if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
1758ceba33eSraf 			return (errno);
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) {
1798cd45542Sraf 		if (setpgid(0, sap->sa_pgroup) != 0)
1808ceba33eSraf 			return (errno);
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) {
184d4204c85Sraf 		if (setparam(P_LWPID, P_MYID,
185d4204c85Sraf 		    sap->sa_schedpolicy, sap->sa_priority) == -1)
1868ceba33eSraf 			return (errno);
1877c478bd9Sstevel@tonic-gate 	} else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) {
188d4204c85Sraf 		if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1)
1898ceba33eSraf 			return (errno);
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 
1928ceba33eSraf 	return (0);
1938ceba33eSraf }
1948ceba33eSraf 
1958ceba33eSraf static int
19608556f6cSRoger A. Faulkner perform_file_actions(file_attr_t *fap, void *dirbuf)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate 	file_attr_t *froot = fap;
1997c478bd9Sstevel@tonic-gate 	int fd;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	do {
2027c478bd9Sstevel@tonic-gate 		switch (fap->fa_type) {
2037c478bd9Sstevel@tonic-gate 		case FA_OPEN:
2048fd04b83SRoger A. Faulkner 			fd = __open(fap->fa_path, fap->fa_oflag, fap->fa_mode);
2057c478bd9Sstevel@tonic-gate 			if (fd < 0)
2068ceba33eSraf 				return (errno);
2077c478bd9Sstevel@tonic-gate 			if (fd != fap->fa_filedes) {
2088cd45542Sraf 				if (__fcntl(fd, F_DUP2FD, fap->fa_filedes) < 0)
2098ceba33eSraf 					return (errno);
2108cd45542Sraf 				(void) __close(fd);
2117c478bd9Sstevel@tonic-gate 			}
2127c478bd9Sstevel@tonic-gate 			break;
2137c478bd9Sstevel@tonic-gate 		case FA_CLOSE:
21408556f6cSRoger A. Faulkner 			if (__close(fap->fa_filedes) == -1 &&
21508556f6cSRoger A. Faulkner 			    errno != EBADF)	/* already closed, no error */
2168ceba33eSraf 				return (errno);
2177c478bd9Sstevel@tonic-gate 			break;
2187c478bd9Sstevel@tonic-gate 		case FA_DUP2:
2198cd45542Sraf 			fd = __fcntl(fap->fa_filedes, F_DUP2FD,
2207c478bd9Sstevel@tonic-gate 			    fap->fa_newfiledes);
2217c478bd9Sstevel@tonic-gate 			if (fd < 0)
2228ceba33eSraf 				return (errno);
2237c478bd9Sstevel@tonic-gate 			break;
22408556f6cSRoger A. Faulkner 		case FA_CLOSEFROM:
22508556f6cSRoger A. Faulkner 			if (spawn_closefrom(fap->fa_filedes, dirbuf))
22608556f6cSRoger A. Faulkner 				return (errno);
22708556f6cSRoger A. Faulkner 			break;
2287c478bd9Sstevel@tonic-gate 		}
2297c478bd9Sstevel@tonic-gate 	} while ((fap = fap->fa_next) != froot);
2308ceba33eSraf 
2318ceba33eSraf 	return (0);
2328ceba33eSraf }
2338ceba33eSraf 
234657b1f3dSraf static int
235657b1f3dSraf forkflags(spawn_attr_t *sap)
236657b1f3dSraf {
237657b1f3dSraf 	int flags = 0;
238657b1f3dSraf 
239657b1f3dSraf 	if (sap != NULL) {
240657b1f3dSraf 		if (sap->sa_psflags & POSIX_SPAWN_NOSIGCHLD_NP)
241657b1f3dSraf 			flags |= FORK_NOSIGCHLD;
242657b1f3dSraf 		if (sap->sa_psflags & POSIX_SPAWN_WAITPID_NP)
243657b1f3dSraf 			flags |= FORK_WAITPID;
244657b1f3dSraf 	}
245657b1f3dSraf 
246657b1f3dSraf 	return (flags);
247657b1f3dSraf }
248657b1f3dSraf 
2498ceba33eSraf /*
2508ceba33eSraf  * set_error() / get_error() are used to guarantee that the local variable
2518ceba33eSraf  * 'error' is set correctly in memory on return from vfork() in the parent.
2528ceba33eSraf  */
2538ceba33eSraf 
2548ceba33eSraf static int
2558ceba33eSraf set_error(int *errp, int err)
2568ceba33eSraf {
2578ceba33eSraf 	return (*errp = err);
2588ceba33eSraf }
2598ceba33eSraf 
2608ceba33eSraf static int
2618ceba33eSraf get_error(int *errp)
2628ceba33eSraf {
2638ceba33eSraf 	return (*errp);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate  * For MT safety, do not invoke the dynamic linker after calling vfork().
2687c478bd9Sstevel@tonic-gate  * If some other thread was in the dynamic linker when this thread's parent
2697c478bd9Sstevel@tonic-gate  * called vfork() then the dynamic linker's lock would still be held here
2707c478bd9Sstevel@tonic-gate  * (with a defunct owner) and we would deadlock ourself if we invoked it.
2717c478bd9Sstevel@tonic-gate  *
2727c478bd9Sstevel@tonic-gate  * Therefore, all of the functions we call here after returning from
2737257d1b4Sraf  * vforkx() in the child are not and must never be exported from libc
2747c478bd9Sstevel@tonic-gate  * as global symbols.  To do so would risk invoking the dynamic linker.
2757c478bd9Sstevel@tonic-gate  */
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate int
2787257d1b4Sraf posix_spawn(
2797c478bd9Sstevel@tonic-gate 	pid_t *pidp,
2807c478bd9Sstevel@tonic-gate 	const char *path,
2817c478bd9Sstevel@tonic-gate 	const posix_spawn_file_actions_t *file_actions,
2827c478bd9Sstevel@tonic-gate 	const posix_spawnattr_t *attrp,
283*10a6478aSRichard PALO 	char *const *argv,
284*10a6478aSRichard PALO 	char *const *envp)
2857c478bd9Sstevel@tonic-gate {
2867c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
2877c478bd9Sstevel@tonic-gate 	file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
28808556f6cSRoger A. Faulkner 	void *dirbuf = NULL;
2898ceba33eSraf 	int error;		/* this will be set by the child */
2907c478bd9Sstevel@tonic-gate 	pid_t pid;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if (attrp != NULL && sap == NULL)
2937c478bd9Sstevel@tonic-gate 		return (EINVAL);
2947c478bd9Sstevel@tonic-gate 
29508556f6cSRoger A. Faulkner 	if (fap != NULL && fap->fa_need_dirbuf) {
29608556f6cSRoger A. Faulkner 		/*
29708556f6cSRoger A. Faulkner 		 * Preallocate the buffer for the call to getdents64() in
29808556f6cSRoger A. Faulkner 		 * spawn_closefrom() since we can't do it in the vfork() child.
29908556f6cSRoger A. Faulkner 		 */
30008556f6cSRoger A. Faulkner 		if ((dirbuf = lmalloc(DIRBUF)) == NULL)
30108556f6cSRoger A. Faulkner 			return (ENOMEM);
30208556f6cSRoger A. Faulkner 	}
30308556f6cSRoger A. Faulkner 
3047257d1b4Sraf 	switch (pid = vforkx(forkflags(sap))) {
3057c478bd9Sstevel@tonic-gate 	case 0:			/* child */
3067c478bd9Sstevel@tonic-gate 		break;
3077c478bd9Sstevel@tonic-gate 	case -1:		/* parent, failure */
30808556f6cSRoger A. Faulkner 		if (dirbuf)
30908556f6cSRoger A. Faulkner 			lfree(dirbuf, DIRBUF);
3107c478bd9Sstevel@tonic-gate 		return (errno);
3117c478bd9Sstevel@tonic-gate 	default:		/* parent, success */
3128ceba33eSraf 		/*
3138ceba33eSraf 		 * We don't get here until the child exec()s or exit()s
3148ceba33eSraf 		 */
3158ceba33eSraf 		if (pidp != NULL && get_error(&error) == 0)
3167c478bd9Sstevel@tonic-gate 			*pidp = pid;
31708556f6cSRoger A. Faulkner 		if (dirbuf)
31808556f6cSRoger A. Faulkner 			lfree(dirbuf, DIRBUF);
3198ceba33eSraf 		return (get_error(&error));
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (sap != NULL)
3238ceba33eSraf 		if (set_error(&error, perform_flag_actions(sap)) != 0)
3248cd45542Sraf 			_exit(_EVAPORATE);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	if (fap != NULL)
32708556f6cSRoger A. Faulkner 		if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
3288cd45542Sraf 			_exit(_EVAPORATE);
3297c478bd9Sstevel@tonic-gate 
3308ceba33eSraf 	(void) set_error(&error, 0);
3318cd45542Sraf 	(void) execve(path, argv, envp);
332f9f6ed06SRoger A. Faulkner 	if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
333f9f6ed06SRoger A. Faulkner 		_exit(127);
3348ceba33eSraf 	(void) set_error(&error, errno);
3358cd45542Sraf 	_exit(_EVAPORATE);
3367c478bd9Sstevel@tonic-gate 	return (0);	/* not reached */
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate  * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c).
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate 
343a574db85Sraf extern int libc__xpg4;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate static const char *
3467c478bd9Sstevel@tonic-gate execat(const char *s1, const char *s2, char *si)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate 	int cnt = PATH_MAX + 1;
3497c478bd9Sstevel@tonic-gate 	char *s;
3507c478bd9Sstevel@tonic-gate 	char c;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	for (s = si; (c = *s1) != '\0' && c != ':'; s1++) {
3537c478bd9Sstevel@tonic-gate 		if (cnt > 0) {
3547c478bd9Sstevel@tonic-gate 			*s++ = c;
3557c478bd9Sstevel@tonic-gate 			cnt--;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	if (si != s && cnt > 0) {
3597c478bd9Sstevel@tonic-gate 		*s++ = '/';
3607c478bd9Sstevel@tonic-gate 		cnt--;
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 	for (; (c = *s2) != '\0' && cnt > 0; s2++) {
3637c478bd9Sstevel@tonic-gate 		*s++ = c;
3647c478bd9Sstevel@tonic-gate 		cnt--;
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 	*s = '\0';
3677c478bd9Sstevel@tonic-gate 	return (*s1? ++s1: NULL);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate /* ARGSUSED */
3717c478bd9Sstevel@tonic-gate int
3727257d1b4Sraf posix_spawnp(
3737c478bd9Sstevel@tonic-gate 	pid_t *pidp,
3747c478bd9Sstevel@tonic-gate 	const char *file,
3757c478bd9Sstevel@tonic-gate 	const posix_spawn_file_actions_t *file_actions,
3767c478bd9Sstevel@tonic-gate 	const posix_spawnattr_t *attrp,
377*10a6478aSRichard PALO 	char *const *argv,
378*10a6478aSRichard PALO 	char *const *envp)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
3817c478bd9Sstevel@tonic-gate 	file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
38208556f6cSRoger A. Faulkner 	void *dirbuf = NULL;
3837c478bd9Sstevel@tonic-gate 	const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : "";
384a574db85Sraf 	int xpg4 = libc__xpg4;
385030a4fdfSRoger A. Faulkner 	int error = 0;		/* this will be set by the child */
3867c478bd9Sstevel@tonic-gate 	char path[PATH_MAX+4];
3877c478bd9Sstevel@tonic-gate 	const char *cp;
3887c478bd9Sstevel@tonic-gate 	pid_t pid;
3897c478bd9Sstevel@tonic-gate 	char **newargs;
3907c478bd9Sstevel@tonic-gate 	int argc;
3917c478bd9Sstevel@tonic-gate 	int i;
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	if (attrp != NULL && sap == NULL)
3947c478bd9Sstevel@tonic-gate 		return (EINVAL);
3957c478bd9Sstevel@tonic-gate 
3968ceba33eSraf 	if (*file == '\0')
3978ceba33eSraf 		return (EACCES);
3988ceba33eSraf 
39908556f6cSRoger A. Faulkner 	if (fap != NULL && fap->fa_need_dirbuf) {
40008556f6cSRoger A. Faulkner 		/*
40108556f6cSRoger A. Faulkner 		 * Preallocate the buffer for the call to getdents64() in
40208556f6cSRoger A. Faulkner 		 * spawn_closefrom() since we can't do it in the vfork() child.
40308556f6cSRoger A. Faulkner 		 */
40408556f6cSRoger A. Faulkner 		if ((dirbuf = lmalloc(DIRBUF)) == NULL)
40508556f6cSRoger A. Faulkner 			return (ENOMEM);
40608556f6cSRoger A. Faulkner 	}
40708556f6cSRoger A. Faulkner 
4087c478bd9Sstevel@tonic-gate 	/*
4097c478bd9Sstevel@tonic-gate 	 * We may need to invoke the shell with a slightly modified
4107c478bd9Sstevel@tonic-gate 	 * argv[] array.  To do this we need to preallocate the array.
4117c478bd9Sstevel@tonic-gate 	 * We must call alloca() before calling vfork() because doing
4127c478bd9Sstevel@tonic-gate 	 * it after vfork() (in the child) would corrupt the parent.
4137c478bd9Sstevel@tonic-gate 	 */
4147c478bd9Sstevel@tonic-gate 	for (argc = 0; argv[argc] != NULL; argc++)
4157c478bd9Sstevel@tonic-gate 		continue;
4167c478bd9Sstevel@tonic-gate 	newargs = alloca((argc + 2) * sizeof (char *));
4177c478bd9Sstevel@tonic-gate 
4187257d1b4Sraf 	switch (pid = vforkx(forkflags(sap))) {
4197c478bd9Sstevel@tonic-gate 	case 0:			/* child */
4207c478bd9Sstevel@tonic-gate 		break;
4217c478bd9Sstevel@tonic-gate 	case -1:		/* parent, failure */
42208556f6cSRoger A. Faulkner 		if (dirbuf)
42308556f6cSRoger A. Faulkner 			lfree(dirbuf, DIRBUF);
4247c478bd9Sstevel@tonic-gate 		return (errno);
4257c478bd9Sstevel@tonic-gate 	default:		/* parent, success */
4268ceba33eSraf 		/*
4278ceba33eSraf 		 * We don't get here until the child exec()s or exit()s
4288ceba33eSraf 		 */
4298ceba33eSraf 		if (pidp != NULL && get_error(&error) == 0)
4307c478bd9Sstevel@tonic-gate 			*pidp = pid;
43108556f6cSRoger A. Faulkner 		if (dirbuf)
43208556f6cSRoger A. Faulkner 			lfree(dirbuf, DIRBUF);
4338ceba33eSraf 		return (get_error(&error));
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	if (sap != NULL)
4378ceba33eSraf 		if (set_error(&error, perform_flag_actions(sap)) != 0)
4388cd45542Sraf 			_exit(_EVAPORATE);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	if (fap != NULL)
44108556f6cSRoger A. Faulkner 		if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
4428cd45542Sraf 			_exit(_EVAPORATE);
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	if (pathstr == NULL) {
4457c478bd9Sstevel@tonic-gate 		/*
4467c478bd9Sstevel@tonic-gate 		 * XPG4:  pathstr is equivalent to _CS_PATH, except that
4477c478bd9Sstevel@tonic-gate 		 * :/usr/sbin is appended when root, and pathstr must end
4487c478bd9Sstevel@tonic-gate 		 * with a colon when not root.  Keep these paths in sync
4497c478bd9Sstevel@tonic-gate 		 * with _CS_PATH in confstr.c.  Note that pathstr must end
4507c478bd9Sstevel@tonic-gate 		 * with a colon when not root so that when file doesn't
4517c478bd9Sstevel@tonic-gate 		 * contain '/', the last call to execat() will result in an
4527c478bd9Sstevel@tonic-gate 		 * attempt to execv file from the current directory.
4537c478bd9Sstevel@tonic-gate 		 */
4548cd45542Sraf 		if (geteuid() == 0 || getuid() == 0) {
4557c478bd9Sstevel@tonic-gate 			if (!xpg4)
4567c478bd9Sstevel@tonic-gate 				pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin";
4577c478bd9Sstevel@tonic-gate 			else
4587c478bd9Sstevel@tonic-gate 				pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
4597c478bd9Sstevel@tonic-gate 				    "/usr/bin:/opt/SUNWspro/bin:/usr/sbin";
4607c478bd9Sstevel@tonic-gate 		} else {
4617c478bd9Sstevel@tonic-gate 			if (!xpg4)
4627c478bd9Sstevel@tonic-gate 				pathstr = "/usr/ccs/bin:/usr/bin:";
4637c478bd9Sstevel@tonic-gate 			else
4647c478bd9Sstevel@tonic-gate 				pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
4657c478bd9Sstevel@tonic-gate 				    "/usr/bin:/opt/SUNWspro/bin:";
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	cp = pathstr;
4707c478bd9Sstevel@tonic-gate 	do {
4717c478bd9Sstevel@tonic-gate 		cp = execat(cp, file, path);
4727c478bd9Sstevel@tonic-gate 		/*
4737c478bd9Sstevel@tonic-gate 		 * 4025035 and 4038378
4747c478bd9Sstevel@tonic-gate 		 * if a filename begins with a "-" prepend "./" so that
4757c478bd9Sstevel@tonic-gate 		 * the shell can't interpret it as an option
4767c478bd9Sstevel@tonic-gate 		 */
4777c478bd9Sstevel@tonic-gate 		if (*path == '-') {
4787c478bd9Sstevel@tonic-gate 			char *s;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 			for (s = path; *s != '\0'; s++)
4817c478bd9Sstevel@tonic-gate 				continue;
4827c478bd9Sstevel@tonic-gate 			for (; s >= path; s--)
4837c478bd9Sstevel@tonic-gate 				*(s + 2) = *s;
4847c478bd9Sstevel@tonic-gate 			path[0] = '.';
4857c478bd9Sstevel@tonic-gate 			path[1] = '/';
4867c478bd9Sstevel@tonic-gate 		}
4878ceba33eSraf 		(void) set_error(&error, 0);
4888cd45542Sraf 		(void) execve(path, argv, envp);
4898ceba33eSraf 		if (set_error(&error, errno) == ENOEXEC) {
4906a5408e6SRichard Lowe 			newargs[0] = "sh";
4917c478bd9Sstevel@tonic-gate 			newargs[1] = path;
4927c478bd9Sstevel@tonic-gate 			for (i = 1; i <= argc; i++)
4937c478bd9Sstevel@tonic-gate 				newargs[i + 1] = argv[i];
4948ceba33eSraf 			(void) set_error(&error, 0);
4956a5408e6SRichard Lowe 			(void) execve(_PATH_BSHELL, newargs, envp);
496f9f6ed06SRoger A. Faulkner 			if (sap != NULL &&
497f9f6ed06SRoger A. Faulkner 			    (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
498f9f6ed06SRoger A. Faulkner 				_exit(127);
4998ceba33eSraf 			(void) set_error(&error, errno);
5008cd45542Sraf 			_exit(_EVAPORATE);
5017c478bd9Sstevel@tonic-gate 		}
5027c478bd9Sstevel@tonic-gate 	} while (cp);
503030a4fdfSRoger A. Faulkner 
504030a4fdfSRoger A. Faulkner 	if (sap != NULL &&
505030a4fdfSRoger A. Faulkner 	    (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) {
506030a4fdfSRoger A. Faulkner 		(void) set_error(&error, 0);
507030a4fdfSRoger A. Faulkner 		_exit(127);
508030a4fdfSRoger A. Faulkner 	}
5098cd45542Sraf 	_exit(_EVAPORATE);
5107c478bd9Sstevel@tonic-gate 	return (0);	/* not reached */
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate int
5147257d1b4Sraf posix_spawn_file_actions_init(
5157c478bd9Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	file_actions->__file_attrp = NULL;
5187c478bd9Sstevel@tonic-gate 	return (0);
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate int
5227257d1b4Sraf posix_spawn_file_actions_destroy(
5237c478bd9Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate 	file_attr_t *froot = file_actions->__file_attrp;
5267c478bd9Sstevel@tonic-gate 	file_attr_t *fap;
5277c478bd9Sstevel@tonic-gate 	file_attr_t *next;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	if ((fap = froot) != NULL) {
5307c478bd9Sstevel@tonic-gate 		do {
5317c478bd9Sstevel@tonic-gate 			next = fap->fa_next;
5327c478bd9Sstevel@tonic-gate 			if (fap->fa_type == FA_OPEN)
5337c478bd9Sstevel@tonic-gate 				lfree(fap->fa_path, fap->fa_pathsize);
5347c478bd9Sstevel@tonic-gate 			lfree(fap, sizeof (*fap));
5357c478bd9Sstevel@tonic-gate 		} while ((fap = next) != froot);
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 	file_actions->__file_attrp = NULL;
5387c478bd9Sstevel@tonic-gate 	return (0);
5397c478bd9Sstevel@tonic-gate }
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate static void
5427c478bd9Sstevel@tonic-gate add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap)
5437c478bd9Sstevel@tonic-gate {
5447c478bd9Sstevel@tonic-gate 	file_attr_t *froot = file_actions->__file_attrp;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if (froot == NULL) {
5477c478bd9Sstevel@tonic-gate 		fap->fa_next = fap->fa_prev = fap;
54808556f6cSRoger A. Faulkner 		file_actions->__file_attrp = froot = fap;
5497c478bd9Sstevel@tonic-gate 	} else {
5507c478bd9Sstevel@tonic-gate 		fap->fa_next = froot;
5517c478bd9Sstevel@tonic-gate 		fap->fa_prev = froot->fa_prev;
5527c478bd9Sstevel@tonic-gate 		froot->fa_prev->fa_next = fap;
5537c478bd9Sstevel@tonic-gate 		froot->fa_prev = fap;
5547c478bd9Sstevel@tonic-gate 	}
55508556f6cSRoger A. Faulkner 
55608556f6cSRoger A. Faulkner 	/*
55708556f6cSRoger A. Faulkner 	 * Once set, __file_attrp no longer changes, so this assignment
55808556f6cSRoger A. Faulkner 	 * always goes into the first element in the list, as required.
55908556f6cSRoger A. Faulkner 	 */
56008556f6cSRoger A. Faulkner 	if (fap->fa_type == FA_CLOSEFROM)
56108556f6cSRoger A. Faulkner 		froot->fa_need_dirbuf = 1;
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate int
5657257d1b4Sraf posix_spawn_file_actions_addopen(
5667c478bd9Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
5677c478bd9Sstevel@tonic-gate 	int filedes,
5687c478bd9Sstevel@tonic-gate 	const char *path,
5697c478bd9Sstevel@tonic-gate 	int oflag,
5707c478bd9Sstevel@tonic-gate 	mode_t mode)
5717c478bd9Sstevel@tonic-gate {
5727c478bd9Sstevel@tonic-gate 	file_attr_t *fap;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	if (filedes < 0)
5757c478bd9Sstevel@tonic-gate 		return (EBADF);
5767c478bd9Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
5777c478bd9Sstevel@tonic-gate 		return (ENOMEM);
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	fap->fa_pathsize = strlen(path) + 1;
5807c478bd9Sstevel@tonic-gate 	if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) {
5817c478bd9Sstevel@tonic-gate 		lfree(fap, sizeof (*fap));
5827c478bd9Sstevel@tonic-gate 		return (ENOMEM);
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 	(void) strcpy(fap->fa_path, path);
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	fap->fa_type = FA_OPEN;
5877c478bd9Sstevel@tonic-gate 	fap->fa_oflag = oflag;
5887c478bd9Sstevel@tonic-gate 	fap->fa_mode = mode;
5897c478bd9Sstevel@tonic-gate 	fap->fa_filedes = filedes;
5907c478bd9Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	return (0);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate int
5967257d1b4Sraf posix_spawn_file_actions_addclose(
5977c478bd9Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
5987c478bd9Sstevel@tonic-gate 	int filedes)
5997c478bd9Sstevel@tonic-gate {
6007c478bd9Sstevel@tonic-gate 	file_attr_t *fap;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	if (filedes < 0)
6037c478bd9Sstevel@tonic-gate 		return (EBADF);
6047c478bd9Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
6057c478bd9Sstevel@tonic-gate 		return (ENOMEM);
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	fap->fa_type = FA_CLOSE;
6087c478bd9Sstevel@tonic-gate 	fap->fa_filedes = filedes;
6097c478bd9Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	return (0);
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate int
6157257d1b4Sraf posix_spawn_file_actions_adddup2(
6167c478bd9Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
6177c478bd9Sstevel@tonic-gate 	int filedes,
6187c478bd9Sstevel@tonic-gate 	int newfiledes)
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate 	file_attr_t *fap;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	if (filedes < 0 || newfiledes < 0)
6237c478bd9Sstevel@tonic-gate 		return (EBADF);
6247c478bd9Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
6257c478bd9Sstevel@tonic-gate 		return (ENOMEM);
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	fap->fa_type = FA_DUP2;
6287c478bd9Sstevel@tonic-gate 	fap->fa_filedes = filedes;
6297c478bd9Sstevel@tonic-gate 	fap->fa_newfiledes = newfiledes;
6307c478bd9Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	return (0);
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate int
63608556f6cSRoger A. Faulkner posix_spawn_file_actions_addclosefrom_np(
63708556f6cSRoger A. Faulkner 	posix_spawn_file_actions_t *file_actions,
63808556f6cSRoger A. Faulkner 	int lowfiledes)
63908556f6cSRoger A. Faulkner {
64008556f6cSRoger A. Faulkner 	file_attr_t *fap;
64108556f6cSRoger A. Faulkner 
64208556f6cSRoger A. Faulkner 	if (lowfiledes < 0)
64308556f6cSRoger A. Faulkner 		return (EBADF);
64408556f6cSRoger A. Faulkner 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
64508556f6cSRoger A. Faulkner 		return (ENOMEM);
64608556f6cSRoger A. Faulkner 	fap->fa_type = FA_CLOSEFROM;
64708556f6cSRoger A. Faulkner 	fap->fa_filedes = lowfiledes;
64808556f6cSRoger A. Faulkner 	add_file_attr(file_actions, fap);
64908556f6cSRoger A. Faulkner 
65008556f6cSRoger A. Faulkner 	return (0);
65108556f6cSRoger A. Faulkner }
65208556f6cSRoger A. Faulkner 
65308556f6cSRoger A. Faulkner int
6547257d1b4Sraf posix_spawnattr_init(
6557c478bd9Sstevel@tonic-gate 	posix_spawnattr_t *attr)
6567c478bd9Sstevel@tonic-gate {
657657b1f3dSraf 	if ((attr->__spawn_attrp = lmalloc(sizeof (posix_spawnattr_t))) == NULL)
6587c478bd9Sstevel@tonic-gate 		return (ENOMEM);
6597c478bd9Sstevel@tonic-gate 	/*
6607c478bd9Sstevel@tonic-gate 	 * Add default stuff here?
6617c478bd9Sstevel@tonic-gate 	 */
6627c478bd9Sstevel@tonic-gate 	return (0);
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate int
6667257d1b4Sraf posix_spawnattr_destroy(
6677c478bd9Sstevel@tonic-gate 	posix_spawnattr_t *attr)
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	if (sap == NULL)
6727c478bd9Sstevel@tonic-gate 		return (EINVAL);
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	/*
6757c478bd9Sstevel@tonic-gate 	 * deallocate stuff here?
6767c478bd9Sstevel@tonic-gate 	 */
6777c478bd9Sstevel@tonic-gate 	lfree(sap, sizeof (*sap));
6787c478bd9Sstevel@tonic-gate 	attr->__spawn_attrp = NULL;
6797c478bd9Sstevel@tonic-gate 	return (0);
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate int
6837257d1b4Sraf posix_spawnattr_setflags(
6847c478bd9Sstevel@tonic-gate 	posix_spawnattr_t *attr,
6857c478bd9Sstevel@tonic-gate 	short flags)
6867c478bd9Sstevel@tonic-gate {
6877c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	if (sap == NULL ||
6907c478bd9Sstevel@tonic-gate 	    (flags & ~ALL_POSIX_SPAWN_FLAGS))
6917c478bd9Sstevel@tonic-gate 		return (EINVAL);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	sap->sa_psflags = flags;
6947c478bd9Sstevel@tonic-gate 	return (0);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate int
6987257d1b4Sraf posix_spawnattr_getflags(
6997c478bd9Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7007c478bd9Sstevel@tonic-gate 	short *flags)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	if (sap == NULL)
7057c478bd9Sstevel@tonic-gate 		return (EINVAL);
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	*flags = sap->sa_psflags;
7087c478bd9Sstevel@tonic-gate 	return (0);
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate int
7127257d1b4Sraf posix_spawnattr_setpgroup(
7137c478bd9Sstevel@tonic-gate 	posix_spawnattr_t *attr,
7147c478bd9Sstevel@tonic-gate 	pid_t pgroup)
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	if (sap == NULL)
7197c478bd9Sstevel@tonic-gate 		return (EINVAL);
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	sap->sa_pgroup = pgroup;
7227c478bd9Sstevel@tonic-gate 	return (0);
7237c478bd9Sstevel@tonic-gate }
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate int
7267257d1b4Sraf posix_spawnattr_getpgroup(
7277c478bd9Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7287c478bd9Sstevel@tonic-gate 	pid_t *pgroup)
7297c478bd9Sstevel@tonic-gate {
7307c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	if (sap == NULL)
7337c478bd9Sstevel@tonic-gate 		return (EINVAL);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	*pgroup = sap->sa_pgroup;
7367c478bd9Sstevel@tonic-gate 	return (0);
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate int
7407257d1b4Sraf posix_spawnattr_setschedparam(
7417c478bd9Sstevel@tonic-gate 	posix_spawnattr_t *attr,
7427c478bd9Sstevel@tonic-gate 	const struct sched_param *schedparam)
7437c478bd9Sstevel@tonic-gate {
7447c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	if (sap == NULL)
7477c478bd9Sstevel@tonic-gate 		return (EINVAL);
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	/*
7507c478bd9Sstevel@tonic-gate 	 * Check validity?
7517c478bd9Sstevel@tonic-gate 	 */
7527c478bd9Sstevel@tonic-gate 	sap->sa_priority = schedparam->sched_priority;
7537c478bd9Sstevel@tonic-gate 	return (0);
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate int
7577257d1b4Sraf posix_spawnattr_getschedparam(
7587c478bd9Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7597c478bd9Sstevel@tonic-gate 	struct sched_param *schedparam)
7607c478bd9Sstevel@tonic-gate {
7617c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	if (sap == NULL)
7647c478bd9Sstevel@tonic-gate 		return (EINVAL);
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	schedparam->sched_priority = sap->sa_priority;
7677c478bd9Sstevel@tonic-gate 	return (0);
7687c478bd9Sstevel@tonic-gate }
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate int
7717257d1b4Sraf posix_spawnattr_setschedpolicy(
7727c478bd9Sstevel@tonic-gate 	posix_spawnattr_t *attr,
7737c478bd9Sstevel@tonic-gate 	int schedpolicy)
7747c478bd9Sstevel@tonic-gate {
7757c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7767c478bd9Sstevel@tonic-gate 
777d4204c85Sraf 	if (sap == NULL || schedpolicy == SCHED_SYS)
7787c478bd9Sstevel@tonic-gate 		return (EINVAL);
7797c478bd9Sstevel@tonic-gate 
780d4204c85Sraf 	/*
781d4204c85Sraf 	 * Cache the policy information for later use
782d4204c85Sraf 	 * by the vfork() child of posix_spawn().
783d4204c85Sraf 	 */
784d4204c85Sraf 	if (get_info_by_policy(schedpolicy) == NULL)
785d4204c85Sraf 		return (errno);
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	sap->sa_schedpolicy = schedpolicy;
7887c478bd9Sstevel@tonic-gate 	return (0);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate int
7927257d1b4Sraf posix_spawnattr_getschedpolicy(
7937c478bd9Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
7947c478bd9Sstevel@tonic-gate 	int *schedpolicy)
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	if (sap == NULL)
7997c478bd9Sstevel@tonic-gate 		return (EINVAL);
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	*schedpolicy = sap->sa_schedpolicy;
8027c478bd9Sstevel@tonic-gate 	return (0);
8037c478bd9Sstevel@tonic-gate }
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate int
8067257d1b4Sraf posix_spawnattr_setsigdefault(
8077c478bd9Sstevel@tonic-gate 	posix_spawnattr_t *attr,
8087c478bd9Sstevel@tonic-gate 	const sigset_t *sigdefault)
8097c478bd9Sstevel@tonic-gate {
8107c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	if (sap == NULL)
8137c478bd9Sstevel@tonic-gate 		return (EINVAL);
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	sap->sa_sigdefault = *sigdefault;
8167c478bd9Sstevel@tonic-gate 	return (0);
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate int
8207257d1b4Sraf posix_spawnattr_getsigdefault(
8217c478bd9Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
8227c478bd9Sstevel@tonic-gate 	sigset_t *sigdefault)
8237c478bd9Sstevel@tonic-gate {
8247c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	if (sap == NULL)
8277c478bd9Sstevel@tonic-gate 		return (EINVAL);
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	*sigdefault = sap->sa_sigdefault;
8307c478bd9Sstevel@tonic-gate 	return (0);
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate int
83403bc411dSRoger A. Faulkner posix_spawnattr_setsigignore_np(
83503bc411dSRoger A. Faulkner 	posix_spawnattr_t *attr,
83603bc411dSRoger A. Faulkner 	const sigset_t *sigignore)
83703bc411dSRoger A. Faulkner {
83803bc411dSRoger A. Faulkner 	spawn_attr_t *sap = attr->__spawn_attrp;
83903bc411dSRoger A. Faulkner 
84003bc411dSRoger A. Faulkner 	if (sap == NULL)
84103bc411dSRoger A. Faulkner 		return (EINVAL);
84203bc411dSRoger A. Faulkner 
84303bc411dSRoger A. Faulkner 	sap->sa_sigignore = *sigignore;
84403bc411dSRoger A. Faulkner 	return (0);
84503bc411dSRoger A. Faulkner }
84603bc411dSRoger A. Faulkner 
84703bc411dSRoger A. Faulkner int
84803bc411dSRoger A. Faulkner posix_spawnattr_getsigignore_np(
84903bc411dSRoger A. Faulkner 	const posix_spawnattr_t *attr,
85003bc411dSRoger A. Faulkner 	sigset_t *sigignore)
85103bc411dSRoger A. Faulkner {
85203bc411dSRoger A. Faulkner 	spawn_attr_t *sap = attr->__spawn_attrp;
85303bc411dSRoger A. Faulkner 
85403bc411dSRoger A. Faulkner 	if (sap == NULL)
85503bc411dSRoger A. Faulkner 		return (EINVAL);
85603bc411dSRoger A. Faulkner 
85703bc411dSRoger A. Faulkner 	*sigignore = sap->sa_sigignore;
85803bc411dSRoger A. Faulkner 	return (0);
85903bc411dSRoger A. Faulkner }
86003bc411dSRoger A. Faulkner 
86103bc411dSRoger A. Faulkner int
8627257d1b4Sraf posix_spawnattr_setsigmask(
8637c478bd9Sstevel@tonic-gate 	posix_spawnattr_t *attr,
8647c478bd9Sstevel@tonic-gate 	const sigset_t *sigmask)
8657c478bd9Sstevel@tonic-gate {
8667c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	if (sap == NULL)
8697c478bd9Sstevel@tonic-gate 		return (EINVAL);
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	sap->sa_sigmask = *sigmask;
8727c478bd9Sstevel@tonic-gate 	return (0);
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate int
8767257d1b4Sraf posix_spawnattr_getsigmask(
8777c478bd9Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
8787c478bd9Sstevel@tonic-gate 	sigset_t *sigmask)
8797c478bd9Sstevel@tonic-gate {
8807c478bd9Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (sap == NULL)
8837c478bd9Sstevel@tonic-gate 		return (EINVAL);
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	*sigmask = sap->sa_sigmask;
8867c478bd9Sstevel@tonic-gate 	return (0);
8877c478bd9Sstevel@tonic-gate }
888462453d2SMatthew Ahrens 
889462453d2SMatthew Ahrens /*
890462453d2SMatthew Ahrens  * Spawn a process to run "sh -c <cmd>".  Return the child's pid (in
891462453d2SMatthew Ahrens  * *pidp), and a file descriptor (in *fdp) for reading or writing to the
892462453d2SMatthew Ahrens  * child process, depending on the 'write' argument.
893462453d2SMatthew Ahrens  * Return 0 on success; otherwise return an error code.
894462453d2SMatthew Ahrens  */
895462453d2SMatthew Ahrens int
896462453d2SMatthew Ahrens posix_spawn_pipe_np(pid_t *pidp, int *fdp,
897462453d2SMatthew Ahrens     const char *cmd, boolean_t write,
898462453d2SMatthew Ahrens     posix_spawn_file_actions_t *fact, posix_spawnattr_t *attr)
899462453d2SMatthew Ahrens {
900462453d2SMatthew Ahrens 	int	p[2];
901462453d2SMatthew Ahrens 	int	myside, yourside, stdio;
902462453d2SMatthew Ahrens 	const char *shpath = _PATH_BSHELL;
903462453d2SMatthew Ahrens 	const char *argvec[4] = { "sh", "-c", cmd, NULL };
904462453d2SMatthew Ahrens 	int	error;
905462453d2SMatthew Ahrens 
906462453d2SMatthew Ahrens 	if (pipe(p) < 0)
907462453d2SMatthew Ahrens 		return (errno);
908462453d2SMatthew Ahrens 
909462453d2SMatthew Ahrens 	if (access(shpath, X_OK))	/* XPG4 Requirement: */
910462453d2SMatthew Ahrens 		shpath = "";		/* force child to fail immediately */
911462453d2SMatthew Ahrens 
912462453d2SMatthew Ahrens 	if (write) {
913462453d2SMatthew Ahrens 		/*
914462453d2SMatthew Ahrens 		 * Data is read from p[0] and written to p[1].
915462453d2SMatthew Ahrens 		 * 'stdio' is the fd in the child process that should be
916462453d2SMatthew Ahrens 		 * connected to the pipe.
917462453d2SMatthew Ahrens 		 */
918462453d2SMatthew Ahrens 		myside = p[1];
919462453d2SMatthew Ahrens 		yourside = p[0];
920462453d2SMatthew Ahrens 		stdio = STDIN_FILENO;
921462453d2SMatthew Ahrens 	} else {
922462453d2SMatthew Ahrens 		myside = p[0];
923462453d2SMatthew Ahrens 		yourside = p[1];
924462453d2SMatthew Ahrens 		stdio = STDOUT_FILENO;
925462453d2SMatthew Ahrens 	}
926462453d2SMatthew Ahrens 
927462453d2SMatthew Ahrens 	error = posix_spawn_file_actions_addclose(fact, myside);
928462453d2SMatthew Ahrens 	if (yourside != stdio) {
929462453d2SMatthew Ahrens 		if (error == 0) {
930462453d2SMatthew Ahrens 			error = posix_spawn_file_actions_adddup2(fact,
931462453d2SMatthew Ahrens 			    yourside, stdio);
932462453d2SMatthew Ahrens 		}
933462453d2SMatthew Ahrens 		if (error == 0) {
934462453d2SMatthew Ahrens 			error = posix_spawn_file_actions_addclose(fact,
935462453d2SMatthew Ahrens 			    yourside);
936462453d2SMatthew Ahrens 		}
937462453d2SMatthew Ahrens 	}
938462453d2SMatthew Ahrens 
939462453d2SMatthew Ahrens 	if (error)
940462453d2SMatthew Ahrens 		return (error);
941462453d2SMatthew Ahrens 	error = posix_spawn(pidp, shpath, fact, attr,
942462453d2SMatthew Ahrens 	    (char *const *)argvec, (char *const *)_environ);
943462453d2SMatthew Ahrens 	(void) close(yourside);
944462453d2SMatthew Ahrens 	if (error) {
945462453d2SMatthew Ahrens 		(void) close(myside);
946462453d2SMatthew Ahrens 		return (error);
947462453d2SMatthew Ahrens 	}
948462453d2SMatthew Ahrens 
949462453d2SMatthew Ahrens 	*fdp = myside;
950462453d2SMatthew Ahrens 	return (0);
951462453d2SMatthew Ahrens }
952