Home | History | Annotate | Download | only in threads
      1     0  stevel /*
      2     0  stevel  * CDDL HEADER START
      3     0  stevel  *
      4     0  stevel  * The contents of this file are subject to the terms of the
      5  2248     raf  * Common Development and Distribution License (the "License").
      6  2248     raf  * You may not use this file except in compliance with the License.
      7     0  stevel  *
      8     0  stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0  stevel  * or http://www.opensolaris.org/os/licensing.
     10     0  stevel  * See the License for the specific language governing permissions
     11     0  stevel  * and limitations under the License.
     12     0  stevel  *
     13     0  stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0  stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0  stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0  stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0  stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0  stevel  *
     19     0  stevel  * CDDL HEADER END
     20     0  stevel  */
     21  2248     raf 
     22     0  stevel /*
     23  8877   Roger  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24     0  stevel  * Use is subject to license terms.
     25     0  stevel  */
     26     0  stevel 
     27     0  stevel #include "lint.h"
     28     0  stevel #include "thr_uberdata.h"
     29  3086     raf #include <sys/libc_kernel.h>
     30     0  stevel #include <sys/procset.h>
     31  3235     raf #include <sys/fork.h>
     32  8877   Roger #include <dirent.h>
     33     0  stevel #include <alloca.h>
     34     0  stevel #include <spawn.h>
     35     0  stevel 
     36     0  stevel #define	ALL_POSIX_SPAWN_FLAGS			\
     37     0  stevel 		(POSIX_SPAWN_RESETIDS |		\
     38     0  stevel 		POSIX_SPAWN_SETPGROUP |		\
     39     0  stevel 		POSIX_SPAWN_SETSIGDEF |		\
     40     0  stevel 		POSIX_SPAWN_SETSIGMASK |	\
     41     0  stevel 		POSIX_SPAWN_SETSCHEDPARAM |	\
     42  3235     raf 		POSIX_SPAWN_SETSCHEDULER |	\
     43  7930   Roger 		POSIX_SPAWN_SETSIGIGN_NP |	\
     44  3235     raf 		POSIX_SPAWN_NOSIGCHLD_NP |	\
     45  7635   Roger 		POSIX_SPAWN_WAITPID_NP |	\
     46  7635   Roger 		POSIX_SPAWN_NOEXECERR_NP)
     47     0  stevel 
     48     0  stevel typedef struct {
     49  6247     raf 	int		sa_psflags;	/* POSIX_SPAWN_* flags */
     50  6247     raf 	int		sa_priority;
     51     0  stevel 	int		sa_schedpolicy;
     52     0  stevel 	pid_t		sa_pgroup;
     53     0  stevel 	sigset_t	sa_sigdefault;
     54  7930   Roger 	sigset_t	sa_sigignore;
     55     0  stevel 	sigset_t	sa_sigmask;
     56     0  stevel } spawn_attr_t;
     57     0  stevel 
     58     0  stevel typedef struct file_attr {
     59     0  stevel 	struct file_attr *fa_next;	/* circular list of file actions */
     60     0  stevel 	struct file_attr *fa_prev;
     61  8877   Roger 	enum {FA_OPEN, FA_CLOSE, FA_DUP2, FA_CLOSEFROM} fa_type;
     62  8877   Roger 	int		fa_need_dirbuf;	/* only consulted in the head action */
     63  8877   Roger 	char		*fa_path;	/* copied pathname for open() */
     64     0  stevel 	uint_t		fa_pathsize;	/* size of fa_path[] array */
     65     0  stevel 	int		fa_oflag;	/* oflag for open() */
     66     0  stevel 	mode_t		fa_mode;	/* mode for open() */
     67     0  stevel 	int		fa_filedes;	/* file descriptor for open()/close() */
     68     0  stevel 	int		fa_newfiledes;	/* new file descriptor for dup2() */
     69     0  stevel } file_attr_t;
     70  2248     raf 
     71     0  stevel extern	int	__lwp_sigmask(int, const sigset_t *, sigset_t *);
     72     0  stevel extern	int	__sigaction(int, const struct sigaction *, struct sigaction *);
     73  8877   Roger 
     74  8877   Roger #if defined(_LP64)
     75  8877   Roger #define	__open64	__open
     76  8877   Roger #define	getdents64	getdents
     77  8877   Roger #define	dirent64_t	dirent_t
     78  8877   Roger #else
     79  8877   Roger extern int __open64(const char *, int, ...);
     80  8877   Roger extern int getdents64(int, dirent64_t *, size_t);
     81  8877   Roger #endif
     82  8877   Roger 
     83  8877   Roger /*
     84  8877   Roger  * Support function:
     85  8877   Roger  * Close all open file descriptors greater than or equal to lowfd.
     86  8877   Roger  * This is executed in the child of vfork(), so we must not call
     87  8877   Roger  * opendir() / readdir() because that would alter the parent's
     88  8877   Roger  * address space.  We use the low-level getdents64() system call.
     89  8877   Roger  * Return non-zero on error.
     90  8877   Roger  */
     91  8877   Roger static int
     92  8877   Roger spawn_closefrom(int lowfd, void *buf)
     93  8877   Roger {
     94  8877   Roger 	int procfd;
     95  8877   Roger 	int fd;
     96  8877   Roger 	int buflen;
     97  8877   Roger 	dirent64_t *dp;
     98  8877   Roger 	dirent64_t *dpend;
     99  8877   Roger 
    100  8877   Roger 	if (lowfd <  0)
    101  8877   Roger 		lowfd = 0;
    102  8877   Roger 
    103  8877   Roger 	/*
    104  8877   Roger 	 * Close lowfd right away as a hedge against failing
    105  8877   Roger 	 * to open the /proc file descriptor directory due
    106  8877   Roger 	 * all file descriptors being currently used up.
    107  8877   Roger 	 */
    108  8877   Roger 	(void) __close(lowfd++);
    109  8877   Roger 
    110  8877   Roger 	if ((procfd = __open64("/proc/self/fd", O_RDONLY, 0)) < 0) {
    111  8877   Roger 		/*
    112  8877   Roger 		 * We could not open the /proc file descriptor directory.
    113  8877   Roger 		 * Just fail and be done with it.
    114  8877   Roger 		 */
    115  8877   Roger 		return (-1);
    116  8877   Roger 	}
    117  8877   Roger 
    118  8877   Roger 	for (;;) {
    119  8877   Roger 		/*
    120  8877   Roger 		 * Collect a bunch of open file descriptors and close them.
    121  8877   Roger 		 * Repeat until the directory is exhausted.
    122  8877   Roger 		 */
    123  8877   Roger 		dp = (dirent64_t *)buf;
    124  8877   Roger 		if ((buflen = getdents64(procfd, dp, DIRBUF)) <= 0) {
    125  8877   Roger 			(void) __close(procfd);
    126  8877   Roger 			break;
    127  8877   Roger 		}
    128  8877   Roger 		dpend = (dirent64_t *)((uintptr_t)buf + buflen);
    129  8877   Roger 		do {
    130  8877   Roger 			/* skip '.', '..' and procfd */
    131  8877   Roger 			if (dp->d_name[0] != '.' &&
    132  8877   Roger 			    (fd = atoi(dp->d_name)) != procfd &&
    133  8877   Roger 			    fd >= lowfd)
    134  8877   Roger 				(void) __close(fd);
    135  8877   Roger 			dp = (dirent64_t *)((uintptr_t)dp + dp->d_reclen);
    136  8877   Roger 		} while (dp < dpend);
    137  8877   Roger 	}
    138  8877   Roger 
    139  8877   Roger 	return (0);
    140  8877   Roger }
    141     0  stevel 
    142  3086     raf static int
    143     0  stevel perform_flag_actions(spawn_attr_t *sap)
    144     0  stevel {
    145     0  stevel 	int sig;
    146  7930   Roger 	struct sigaction action;
    147     0  stevel 
    148     0  stevel 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) {
    149     0  stevel 		(void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask, NULL);
    150     0  stevel 	}
    151     0  stevel 
    152  7930   Roger 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) {
    153  7930   Roger 		(void) memset(&action, 0, sizeof (action));
    154  7930   Roger 		action.sa_handler = SIG_IGN;
    155  7930   Roger 		for (sig = 1; sig < NSIG; sig++) {
    156  7930   Roger 			if (sigismember(&sap->sa_sigignore, sig))
    157  7930   Roger 				(void) __sigaction(sig, &action, NULL);
    158  7930   Roger 		}
    159  7930   Roger 	}
    160  7930   Roger 
    161     0  stevel 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) {
    162  7930   Roger 		(void) memset(&action, 0, sizeof (action));
    163  7930   Roger 		action.sa_handler = SIG_DFL;
    164     0  stevel 		for (sig = 1; sig < NSIG; sig++) {
    165  6515     raf 			if (sigismember(&sap->sa_sigdefault, sig))
    166  7930   Roger 				(void) __sigaction(sig, &action, NULL);
    167     0  stevel 		}
    168     0  stevel 	}
    169     0  stevel 
    170     0  stevel 	if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) {
    171  6515     raf 		if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
    172  3086     raf 			return (errno);
    173     0  stevel 	}
    174     0  stevel 
    175     0  stevel 	if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) {
    176  6515     raf 		if (setpgid(0, sap->sa_pgroup) != 0)
    177  3086     raf 			return (errno);
    178     0  stevel 	}
    179     0  stevel 
    180     0  stevel 	if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) {
    181  6247     raf 		if (setparam(P_LWPID, P_MYID,
    182  6247     raf 		    sap->sa_schedpolicy, sap->sa_priority) == -1)
    183  3086     raf 			return (errno);
    184     0  stevel 	} else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) {
    185  6247     raf 		if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1)
    186  3086     raf 			return (errno);
    187     0  stevel 	}
    188  3086     raf 
    189  3086     raf 	return (0);
    190     0  stevel }
    191     0  stevel 
    192  3086     raf static int
    193  8877   Roger perform_file_actions(file_attr_t *fap, void *dirbuf)
    194     0  stevel {
    195     0  stevel 	file_attr_t *froot = fap;
    196     0  stevel 	int fd;
    197     0  stevel 
    198     0  stevel 	do {
    199     0  stevel 		switch (fap->fa_type) {
    200     0  stevel 		case FA_OPEN:
    201  6515     raf 			fd = __open(fap->fa_path,
    202  5891     raf 			    fap->fa_oflag, fap->fa_mode);
    203     0  stevel 			if (fd < 0)
    204  3086     raf 				return (errno);
    205     0  stevel 			if (fd != fap->fa_filedes) {
    206  6515     raf 				if (__fcntl(fd, F_DUP2FD, fap->fa_filedes) < 0)
    207  3086     raf 					return (errno);
    208  6515     raf 				(void) __close(fd);
    209     0  stevel 			}
    210     0  stevel 			break;
    211     0  stevel 		case FA_CLOSE:
    212  8877   Roger 			if (__close(fap->fa_filedes) == -1 &&
    213  8877   Roger 			    errno != EBADF)	/* already closed, no error */
    214  3086     raf 				return (errno);
    215     0  stevel 			break;
    216     0  stevel 		case FA_DUP2:
    217  6515     raf 			fd = __fcntl(fap->fa_filedes, F_DUP2FD,
    218  5891     raf 			    fap->fa_newfiledes);
    219     0  stevel 			if (fd < 0)
    220  8877   Roger 				return (errno);
    221  8877   Roger 			break;
    222  8877   Roger 		case FA_CLOSEFROM:
    223  8877   Roger 			if (spawn_closefrom(fap->fa_filedes, dirbuf))
    224  3086     raf 				return (errno);
    225     0  stevel 			break;
    226     0  stevel 		}
    227     0  stevel 	} while ((fap = fap->fa_next) != froot);
    228  3086     raf 
    229  3086     raf 	return (0);
    230  3086     raf }
    231  3086     raf 
    232  3235     raf static int
    233  3235     raf forkflags(spawn_attr_t *sap)
    234  3235     raf {
    235  3235     raf 	int flags = 0;
    236  3235     raf 
    237  3235     raf 	if (sap != NULL) {
    238  3235     raf 		if (sap->sa_psflags & POSIX_SPAWN_NOSIGCHLD_NP)
    239  3235     raf 			flags |= FORK_NOSIGCHLD;
    240  3235     raf 		if (sap->sa_psflags & POSIX_SPAWN_WAITPID_NP)
    241  3235     raf 			flags |= FORK_WAITPID;
    242  3235     raf 	}
    243  3235     raf 
    244  3235     raf 	return (flags);
    245  3235     raf }
    246  3235     raf 
    247  3086     raf /*
    248  3086     raf  * set_error() / get_error() are used to guarantee that the local variable
    249  3086     raf  * 'error' is set correctly in memory on return from vfork() in the parent.
    250  3086     raf  */
    251  3086     raf 
    252  3086     raf static int
    253  3086     raf set_error(int *errp, int err)
    254  3086     raf {
    255  3086     raf 	return (*errp = err);
    256  3086     raf }
    257  3086     raf 
    258  3086     raf static int
    259  3086     raf get_error(int *errp)
    260  3086     raf {
    261  3086     raf 	return (*errp);
    262     0  stevel }
    263     0  stevel 
    264     0  stevel /*
    265     0  stevel  * For MT safety, do not invoke the dynamic linker after calling vfork().
    266     0  stevel  * If some other thread was in the dynamic linker when this thread's parent
    267     0  stevel  * called vfork() then the dynamic linker's lock would still be held here
    268     0  stevel  * (with a defunct owner) and we would deadlock ourself if we invoked it.
    269     0  stevel  *
    270     0  stevel  * Therefore, all of the functions we call here after returning from
    271  6812     raf  * vforkx() in the child are not and must never be exported from libc
    272     0  stevel  * as global symbols.  To do so would risk invoking the dynamic linker.
    273     0  stevel  */
    274     0  stevel 
    275     0  stevel int
    276  6812     raf posix_spawn(
    277     0  stevel 	pid_t *pidp,
    278     0  stevel 	const char *path,
    279     0  stevel 	const posix_spawn_file_actions_t *file_actions,
    280     0  stevel 	const posix_spawnattr_t *attrp,
    281     0  stevel 	char *const argv[],
    282     0  stevel 	char *const envp[])
    283     0  stevel {
    284     0  stevel 	spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
    285     0  stevel 	file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
    286  8877   Roger 	void *dirbuf = NULL;
    287  3086     raf 	int error;		/* this will be set by the child */
    288     0  stevel 	pid_t pid;
    289     0  stevel 
    290     0  stevel 	if (attrp != NULL && sap == NULL)
    291     0  stevel 		return (EINVAL);
    292     0  stevel 
    293  8877   Roger 	if (fap != NULL && fap->fa_need_dirbuf) {
    294  8877   Roger 		/*
    295  8877   Roger 		 * Preallocate the buffer for the call to getdents64() in
    296  8877   Roger 		 * spawn_closefrom() since we can't do it in the vfork() child.
    297  8877   Roger 		 */
    298  8877   Roger 		if ((dirbuf = lmalloc(DIRBUF)) == NULL)
    299  8877   Roger 			return (ENOMEM);
    300  8877   Roger 	}
    301  8877   Roger 
    302  6812     raf 	switch (pid = vforkx(forkflags(sap))) {
    303     0  stevel 	case 0:			/* child */
    304     0  stevel 		break;
    305     0  stevel 	case -1:		/* parent, failure */
    306  8877   Roger 		if (dirbuf)
    307  8877   Roger 			lfree(dirbuf, DIRBUF);
    308     0  stevel 		return (errno);
    309     0  stevel 	default:		/* parent, success */
    310  3086     raf 		/*
    311  3086     raf 		 * We don't get here until the child exec()s or exit()s
    312  3086     raf 		 */
    313  3086     raf 		if (pidp != NULL && get_error(&error) == 0)
    314     0  stevel 			*pidp = pid;
    315  8877   Roger 		if (dirbuf)
    316  8877   Roger 			lfree(dirbuf, DIRBUF);
    317  3086     raf 		return (get_error(&error));
    318     0  stevel 	}
    319     0  stevel 
    320     0  stevel 	if (sap != NULL)
    321  3086     raf 		if (set_error(&error, perform_flag_actions(sap)) != 0)
    322  6515     raf 			_exit(_EVAPORATE);
    323     0  stevel 
    324     0  stevel 	if (fap != NULL)
    325  8877   Roger 		if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
    326  6515     raf 			_exit(_EVAPORATE);
    327     0  stevel 
    328  3086     raf 	(void) set_error(&error, 0);
    329  6515     raf 	(void) execve(path, argv, envp);
    330  7635   Roger 	if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
    331  7635   Roger 		_exit(127);
    332  3086     raf 	(void) set_error(&error, errno);
    333  6515     raf 	_exit(_EVAPORATE);
    334     0  stevel 	return (0);	/* not reached */
    335     0  stevel }
    336     0  stevel 
    337     0  stevel /*
    338     0  stevel  * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c).
    339     0  stevel  */
    340     0  stevel 
    341  5891     raf extern int libc__xpg4;
    342     0  stevel 
    343     0  stevel static const char *
    344     0  stevel execat(const char *s1, const char *s2, char *si)
    345     0  stevel {
    346     0  stevel 	int cnt = PATH_MAX + 1;
    347     0  stevel 	char *s;
    348     0  stevel 	char c;
    349     0  stevel 
    350     0  stevel 	for (s = si; (c = *s1) != '\0' && c != ':'; s1++) {
    351     0  stevel 		if (cnt > 0) {
    352     0  stevel 			*s++ = c;
    353     0  stevel 			cnt--;
    354     0  stevel 		}
    355     0  stevel 	}
    356     0  stevel 	if (si != s && cnt > 0) {
    357     0  stevel 		*s++ = '/';
    358     0  stevel 		cnt--;
    359     0  stevel 	}
    360     0  stevel 	for (; (c = *s2) != '\0' && cnt > 0; s2++) {
    361     0  stevel 		*s++ = c;
    362     0  stevel 		cnt--;
    363     0  stevel 	}
    364     0  stevel 	*s = '\0';
    365     0  stevel 	return (*s1? ++s1: NULL);
    366     0  stevel }
    367     0  stevel 
    368     0  stevel /* ARGSUSED */
    369     0  stevel int
    370  6812     raf posix_spawnp(
    371     0  stevel 	pid_t *pidp,
    372     0  stevel 	const char *file,
    373     0  stevel 	const posix_spawn_file_actions_t *file_actions,
    374     0  stevel 	const posix_spawnattr_t *attrp,
    375     0  stevel 	char *const argv[],
    376     0  stevel 	char *const envp[])
    377     0  stevel {
    378     0  stevel 	spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
    379     0  stevel 	file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
    380  8877   Roger 	void *dirbuf = NULL;
    381     0  stevel 	const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : "";
    382  5891     raf 	int xpg4 = libc__xpg4;
    383  7646   Roger 	int error = 0;		/* this will be set by the child */
    384     0  stevel 	char path[PATH_MAX+4];
    385     0  stevel 	const char *cp;
    386     0  stevel 	pid_t pid;
    387     0  stevel 	char **newargs;
    388     0  stevel 	int argc;
    389     0  stevel 	int i;
    390     0  stevel 	static const char *sun_path = "/bin/sh";
    391     0  stevel 	static const char *xpg4_path = "/usr/xpg4/bin/sh";
    392     0  stevel 	static const char *shell = "sh";
    393     0  stevel 
    394     0  stevel 	if (attrp != NULL && sap == NULL)
    395     0  stevel 		return (EINVAL);
    396  3086     raf 
    397  3086     raf 	if (*file == '\0')
    398  3086     raf 		return (EACCES);
    399     0  stevel 
    400  8877   Roger 	if (fap != NULL && fap->fa_need_dirbuf) {
    401  8877   Roger 		/*
    402  8877   Roger 		 * Preallocate the buffer for the call to getdents64() in
    403  8877   Roger 		 * spawn_closefrom() since we can't do it in the vfork() child.
    404  8877   Roger 		 */
    405  8877   Roger 		if ((dirbuf = lmalloc(DIRBUF)) == NULL)
    406  8877   Roger 			return (ENOMEM);
    407  8877   Roger 	}
    408  8877   Roger 
    409     0  stevel 	/*
    410     0  stevel 	 * We may need to invoke the shell with a slightly modified
    411     0  stevel 	 * argv[] array.  To do this we need to preallocate the array.
    412     0  stevel 	 * We must call alloca() before calling vfork() because doing
    413     0  stevel 	 * it after vfork() (in the child) would corrupt the parent.
    414     0  stevel 	 */
    415     0  stevel 	for (argc = 0; argv[argc] != NULL; argc++)
    416     0  stevel 		continue;
    417     0  stevel 	newargs = alloca((argc + 2) * sizeof (char *));
    418     0  stevel 
    419  6812     raf 	switch (pid = vforkx(forkflags(sap))) {
    420     0  stevel 	case 0:			/* child */
    421     0  stevel 		break;
    422     0  stevel 	case -1:		/* parent, failure */
    423  8877   Roger 		if (dirbuf)
    424  8877   Roger 			lfree(dirbuf, DIRBUF);
    425     0  stevel 		return (errno);
    426     0  stevel 	default:		/* parent, success */
    427  3086     raf 		/*
    428  3086     raf 		 * We don't get here until the child exec()s or exit()s
    429  3086     raf 		 */
    430  3086     raf 		if (pidp != NULL && get_error(&error) == 0)
    431     0  stevel 			*pidp = pid;
    432  8877   Roger 		if (dirbuf)
    433  8877   Roger 			lfree(dirbuf, DIRBUF);
    434  3086     raf 		return (get_error(&error));
    435     0  stevel 	}
    436     0  stevel 
    437     0  stevel 	if (sap != NULL)
    438  3086     raf 		if (set_error(&error, perform_flag_actions(sap)) != 0)
    439  6515     raf 			_exit(_EVAPORATE);
    440     0  stevel 
    441     0  stevel 	if (fap != NULL)
    442  8877   Roger 		if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
    443  6515     raf 			_exit(_EVAPORATE);
    444     0  stevel 
    445     0  stevel 	if (pathstr == NULL) {
    446     0  stevel 		/*
    447     0  stevel 		 * XPG4:  pathstr is equivalent to _CS_PATH, except that
    448     0  stevel 		 * :/usr/sbin is appended when root, and pathstr must end
    449     0  stevel 		 * with a colon when not root.  Keep these paths in sync
    450     0  stevel 		 * with _CS_PATH in confstr.c.  Note that pathstr must end
    451     0  stevel 		 * with a colon when not root so that when file doesn't
    452     0  stevel 		 * contain '/', the last call to execat() will result in an
    453     0  stevel 		 * attempt to execv file from the current directory.
    454     0  stevel 		 */
    455  6515     raf 		if (geteuid() == 0 || getuid() == 0) {
    456     0  stevel 			if (!xpg4)
    457     0  stevel 				pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin";
    458     0  stevel 			else
    459     0  stevel 				pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
    460     0  stevel 				    "/usr/bin:/opt/SUNWspro/bin:/usr/sbin";
    461     0  stevel 		} else {
    462     0  stevel 			if (!xpg4)
    463     0  stevel 				pathstr = "/usr/ccs/bin:/usr/bin:";
    464     0  stevel 			else
    465     0  stevel 				pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
    466     0  stevel 				    "/usr/bin:/opt/SUNWspro/bin:";
    467     0  stevel 		}
    468     0  stevel 	}
    469     0  stevel 
    470     0  stevel 	cp = pathstr;
    471     0  stevel 	do {
    472     0  stevel 		cp = execat(cp, file, path);
    473     0  stevel 		/*
    474     0  stevel 		 * 4025035 and 4038378
    475     0  stevel 		 * if a filename begins with a "-" prepend "./" so that
    476     0  stevel 		 * the shell can't interpret it as an option
    477     0  stevel 		 */
    478     0  stevel 		if (*path == '-') {
    479     0  stevel 			char *s;
    480     0  stevel 
    481     0  stevel 			for (s = path; *s != '\0'; s++)
    482     0  stevel 				continue;
    483     0  stevel 			for (; s >= path; s--)
    484     0  stevel 				*(s + 2) = *s;
    485     0  stevel 			path[0] = '.';
    486     0  stevel 			path[1] = '/';
    487     0  stevel 		}
    488  3086     raf 		(void) set_error(&error, 0);
    489  6515     raf 		(void) execve(path, argv, envp);
    490  3086     raf 		if (set_error(&error, errno) == ENOEXEC) {
    491     0  stevel 			newargs[0] = (char *)shell;
    492     0  stevel 			newargs[1] = path;
    493     0  stevel 			for (i = 1; i <= argc; i++)
    494     0  stevel 				newargs[i + 1] = argv[i];
    495  3086     raf 			(void) set_error(&error, 0);
    496  6515     raf 			(void) execve(xpg4? xpg4_path : sun_path,
    497  3086     raf 			    newargs, envp);
    498  7635   Roger 			if (sap != NULL &&
    499  7635   Roger 			    (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
    500  7635   Roger 				_exit(127);
    501  3086     raf 			(void) set_error(&error, errno);
    502  6515     raf 			_exit(_EVAPORATE);
    503     0  stevel 		}
    504     0  stevel 	} while (cp);
    505  7646   Roger 
    506  7646   Roger 	if (sap != NULL &&
    507  7646   Roger 	    (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) {
    508  7646   Roger 		(void) set_error(&error, 0);
    509  7646   Roger 		_exit(127);
    510  7646   Roger 	}
    511  6515     raf 	_exit(_EVAPORATE);
    512     0  stevel 	return (0);	/* not reached */
    513     0  stevel }
    514     0  stevel 
    515     0  stevel int
    516  6812     raf posix_spawn_file_actions_init(
    517     0  stevel 	posix_spawn_file_actions_t *file_actions)
    518     0  stevel {
    519     0  stevel 	file_actions->__file_attrp = NULL;
    520     0  stevel 	return (0);
    521     0  stevel }
    522     0  stevel 
    523     0  stevel int
    524  6812     raf posix_spawn_file_actions_destroy(
    525     0  stevel 	posix_spawn_file_actions_t *file_actions)
    526     0  stevel {
    527     0  stevel 	file_attr_t *froot = file_actions->__file_attrp;
    528     0  stevel 	file_attr_t *fap;
    529     0  stevel 	file_attr_t *next;
    530     0  stevel 
    531     0  stevel 	if ((fap = froot) != NULL) {
    532     0  stevel 		do {
    533     0  stevel 			next = fap->fa_next;
    534  8877   Roger 			if (fap->fa_type == FA_OPEN)
    535     0  stevel 				lfree(fap->fa_path, fap->fa_pathsize);
    536     0  stevel 			lfree(fap, sizeof (*fap));
    537     0  stevel 		} while ((fap = next) != froot);
    538     0  stevel 	}
    539     0  stevel 	file_actions->__file_attrp = NULL;
    540     0  stevel 	return (0);
    541     0  stevel }
    542     0  stevel 
    543     0  stevel static void
    544     0  stevel add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap)
    545     0  stevel {
    546     0  stevel 	file_attr_t *froot = file_actions->__file_attrp;
    547     0  stevel 
    548     0  stevel 	if (froot == NULL) {
    549     0  stevel 		fap->fa_next = fap->fa_prev = fap;
    550  8877   Roger 		file_actions->__file_attrp = froot = fap;
    551     0  stevel 	} else {
    552     0  stevel 		fap->fa_next = froot;
    553     0  stevel 		fap->fa_prev = froot->fa_prev;
    554     0  stevel 		froot->fa_prev->fa_next = fap;
    555     0  stevel 		froot->fa_prev = fap;
    556     0  stevel 	}
    557  8877   Roger 
    558  8877   Roger 	/*
    559  8877   Roger 	 * Once set, __file_attrp no longer changes, so this assignment
    560  8877   Roger 	 * always goes into the first element in the list, as required.
    561  8877   Roger 	 */
    562  8877   Roger 	if (fap->fa_type == FA_CLOSEFROM)
    563  8877   Roger 		froot->fa_need_dirbuf = 1;
    564     0  stevel }
    565     0  stevel 
    566     0  stevel int
    567  6812     raf posix_spawn_file_actions_addopen(
    568     0  stevel 	posix_spawn_file_actions_t *file_actions,
    569     0  stevel 	int filedes,
    570     0  stevel 	const char *path,
    571     0  stevel 	int oflag,
    572     0  stevel 	mode_t mode)
    573     0  stevel {
    574     0  stevel 	file_attr_t *fap;
    575     0  stevel 
    576     0  stevel 	if (filedes < 0)
    577     0  stevel 		return (EBADF);
    578     0  stevel 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
    579     0  stevel 		return (ENOMEM);
    580     0  stevel 
    581     0  stevel 	fap->fa_pathsize = strlen(path) + 1;
    582     0  stevel 	if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) {
    583     0  stevel 		lfree(fap, sizeof (*fap));
    584     0  stevel 		return (ENOMEM);
    585     0  stevel 	}
    586     0  stevel 	(void) strcpy(fap->fa_path, path);
    587     0  stevel 
    588     0  stevel 	fap->fa_type = FA_OPEN;
    589     0  stevel 	fap->fa_oflag = oflag;
    590     0  stevel 	fap->fa_mode = mode;
    591     0  stevel 	fap->fa_filedes = filedes;
    592     0  stevel 	add_file_attr(file_actions, fap);
    593     0  stevel 
    594     0  stevel 	return (0);
    595     0  stevel }
    596     0  stevel 
    597     0  stevel int
    598  6812     raf posix_spawn_file_actions_addclose(
    599     0  stevel 	posix_spawn_file_actions_t *file_actions,
    600     0  stevel 	int filedes)
    601     0  stevel {
    602     0  stevel 	file_attr_t *fap;
    603     0  stevel 
    604     0  stevel 	if (filedes < 0)
    605     0  stevel 		return (EBADF);
    606     0  stevel 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
    607     0  stevel 		return (ENOMEM);
    608     0  stevel 
    609     0  stevel 	fap->fa_type = FA_CLOSE;
    610     0  stevel 	fap->fa_filedes = filedes;
    611     0  stevel 	add_file_attr(file_actions, fap);
    612     0  stevel 
    613     0  stevel 	return (0);
    614     0  stevel }
    615     0  stevel 
    616     0  stevel int
    617  6812     raf posix_spawn_file_actions_adddup2(
    618     0  stevel 	posix_spawn_file_actions_t *file_actions,
    619     0  stevel 	int filedes,
    620     0  stevel 	int newfiledes)
    621     0  stevel {
    622     0  stevel 	file_attr_t *fap;
    623     0  stevel 
    624     0  stevel 	if (filedes < 0 || newfiledes < 0)
    625     0  stevel 		return (EBADF);
    626     0  stevel 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
    627     0  stevel 		return (ENOMEM);
    628     0  stevel 
    629     0  stevel 	fap->fa_type = FA_DUP2;
    630     0  stevel 	fap->fa_filedes = filedes;
    631     0  stevel 	fap->fa_newfiledes = newfiledes;
    632  8877   Roger 	add_file_attr(file_actions, fap);
    633  8877   Roger 
    634  8877   Roger 	return (0);
    635  8877   Roger }
    636  8877   Roger 
    637  8877   Roger int
    638  8877   Roger posix_spawn_file_actions_addclosefrom_np(
    639  8877   Roger 	posix_spawn_file_actions_t *file_actions,
    640  8877   Roger 	int lowfiledes)
    641  8877   Roger {
    642  8877   Roger 	file_attr_t *fap;
    643  8877   Roger 
    644  8877   Roger 	if (lowfiledes < 0)
    645  8877   Roger 		return (EBADF);
    646  8877   Roger 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
    647  8877   Roger 		return (ENOMEM);
    648  8877   Roger 	fap->fa_type = FA_CLOSEFROM;
    649  8877   Roger 	fap->fa_filedes = lowfiledes;
    650     0  stevel 	add_file_attr(file_actions, fap);
    651     0  stevel 
    652     0  stevel 	return (0);
    653     0  stevel }
    654     0  stevel 
    655     0  stevel int
    656  6812     raf posix_spawnattr_init(
    657     0  stevel 	posix_spawnattr_t *attr)
    658     0  stevel {
    659  3235     raf 	if ((attr->__spawn_attrp = lmalloc(sizeof (posix_spawnattr_t))) == NULL)
    660     0  stevel 		return (ENOMEM);
    661     0  stevel 	/*
    662     0  stevel 	 * Add default stuff here?
    663     0  stevel 	 */
    664     0  stevel 	return (0);
    665     0  stevel }
    666     0  stevel 
    667     0  stevel int
    668  6812     raf posix_spawnattr_destroy(
    669     0  stevel 	posix_spawnattr_t *attr)
    670     0  stevel {
    671     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    672     0  stevel 
    673     0  stevel 	if (sap == NULL)
    674     0  stevel 		return (EINVAL);
    675     0  stevel 
    676     0  stevel 	/*
    677     0  stevel 	 * deallocate stuff here?
    678     0  stevel 	 */
    679     0  stevel 	lfree(sap, sizeof (*sap));
    680     0  stevel 	attr->__spawn_attrp = NULL;
    681     0  stevel 	return (0);
    682     0  stevel }
    683     0  stevel 
    684     0  stevel int
    685  6812     raf posix_spawnattr_setflags(
    686     0  stevel 	posix_spawnattr_t *attr,
    687     0  stevel 	short flags)
    688     0  stevel {
    689     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    690     0  stevel 
    691     0  stevel 	if (sap == NULL ||
    692     0  stevel 	    (flags & ~ALL_POSIX_SPAWN_FLAGS))
    693     0  stevel 		return (EINVAL);
    694     0  stevel 
    695     0  stevel 	sap->sa_psflags = flags;
    696     0  stevel 	return (0);
    697     0  stevel }
    698     0  stevel 
    699     0  stevel int
    700  6812     raf posix_spawnattr_getflags(
    701     0  stevel 	const posix_spawnattr_t *attr,
    702     0  stevel 	short *flags)
    703     0  stevel {
    704     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    705     0  stevel 
    706     0  stevel 	if (sap == NULL)
    707     0  stevel 		return (EINVAL);
    708     0  stevel 
    709     0  stevel 	*flags = sap->sa_psflags;
    710     0  stevel 	return (0);
    711     0  stevel }
    712     0  stevel 
    713     0  stevel int
    714  6812     raf posix_spawnattr_setpgroup(
    715     0  stevel 	posix_spawnattr_t *attr,
    716     0  stevel 	pid_t pgroup)
    717     0  stevel {
    718     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    719     0  stevel 
    720     0  stevel 	if (sap == NULL)
    721     0  stevel 		return (EINVAL);
    722     0  stevel 
    723     0  stevel 	sap->sa_pgroup = pgroup;
    724     0  stevel 	return (0);
    725     0  stevel }
    726     0  stevel 
    727     0  stevel int
    728  6812     raf posix_spawnattr_getpgroup(
    729     0  stevel 	const posix_spawnattr_t *attr,
    730     0  stevel 	pid_t *pgroup)
    731     0  stevel {
    732     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    733     0  stevel 
    734     0  stevel 	if (sap == NULL)
    735     0  stevel 		return (EINVAL);
    736     0  stevel 
    737     0  stevel 	*pgroup = sap->sa_pgroup;
    738     0  stevel 	return (0);
    739     0  stevel }
    740     0  stevel 
    741     0  stevel int
    742  6812     raf posix_spawnattr_setschedparam(
    743     0  stevel 	posix_spawnattr_t *attr,
    744     0  stevel 	const struct sched_param *schedparam)
    745     0  stevel {
    746     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    747     0  stevel 
    748     0  stevel 	if (sap == NULL)
    749     0  stevel 		return (EINVAL);
    750     0  stevel 
    751     0  stevel 	/*
    752     0  stevel 	 * Check validity?
    753     0  stevel 	 */
    754     0  stevel 	sap->sa_priority = schedparam->sched_priority;
    755     0  stevel 	return (0);
    756     0  stevel }
    757     0  stevel 
    758     0  stevel int
    759  6812     raf posix_spawnattr_getschedparam(
    760     0  stevel 	const posix_spawnattr_t *attr,
    761     0  stevel 	struct sched_param *schedparam)
    762     0  stevel {
    763     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    764     0  stevel 
    765     0  stevel 	if (sap == NULL)
    766     0  stevel 		return (EINVAL);
    767     0  stevel 
    768     0  stevel 	schedparam->sched_priority = sap->sa_priority;
    769     0  stevel 	return (0);
    770     0  stevel }
    771     0  stevel 
    772     0  stevel int
    773  6812     raf posix_spawnattr_setschedpolicy(
    774     0  stevel 	posix_spawnattr_t *attr,
    775     0  stevel 	int schedpolicy)
    776     0  stevel {
    777     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    778     0  stevel 
    779  6247     raf 	if (sap == NULL || schedpolicy == SCHED_SYS)
    780     0  stevel 		return (EINVAL);
    781     0  stevel 
    782  6247     raf 	/*
    783  6247     raf 	 * Cache the policy information for later use
    784  6247     raf 	 * by the vfork() child of posix_spawn().
    785  6247     raf 	 */
    786  6247     raf 	if (get_info_by_policy(schedpolicy) == NULL)
    787  6247     raf 		return (errno);
    788     0  stevel 
    789     0  stevel 	sap->sa_schedpolicy = schedpolicy;
    790     0  stevel 	return (0);
    791     0  stevel }
    792     0  stevel 
    793     0  stevel int
    794  6812     raf posix_spawnattr_getschedpolicy(
    795     0  stevel 	const posix_spawnattr_t *attr,
    796     0  stevel 	int *schedpolicy)
    797     0  stevel {
    798     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    799     0  stevel 
    800     0  stevel 	if (sap == NULL)
    801     0  stevel 		return (EINVAL);
    802     0  stevel 
    803     0  stevel 	*schedpolicy = sap->sa_schedpolicy;
    804     0  stevel 	return (0);
    805     0  stevel }
    806     0  stevel 
    807     0  stevel int
    808  6812     raf posix_spawnattr_setsigdefault(
    809     0  stevel 	posix_spawnattr_t *attr,
    810     0  stevel 	const sigset_t *sigdefault)
    811     0  stevel {
    812     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    813     0  stevel 
    814     0  stevel 	if (sap == NULL)
    815     0  stevel 		return (EINVAL);
    816     0  stevel 
    817     0  stevel 	sap->sa_sigdefault = *sigdefault;
    818     0  stevel 	return (0);
    819     0  stevel }
    820     0  stevel 
    821     0  stevel int
    822  6812     raf posix_spawnattr_getsigdefault(
    823     0  stevel 	const posix_spawnattr_t *attr,
    824     0  stevel 	sigset_t *sigdefault)
    825     0  stevel {
    826     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    827     0  stevel 
    828     0  stevel 	if (sap == NULL)
    829     0  stevel 		return (EINVAL);
    830     0  stevel 
    831     0  stevel 	*sigdefault = sap->sa_sigdefault;
    832     0  stevel 	return (0);
    833     0  stevel }
    834     0  stevel 
    835     0  stevel int
    836  7930   Roger posix_spawnattr_setsigignore_np(
    837  7930   Roger 	posix_spawnattr_t *attr,
    838  7930   Roger 	const sigset_t *sigignore)
    839  7930   Roger {
    840  7930   Roger 	spawn_attr_t *sap = attr->__spawn_attrp;
    841  7930   Roger 
    842  7930   Roger 	if (sap == NULL)
    843  7930   Roger 		return (EINVAL);
    844  7930   Roger 
    845  7930   Roger 	sap->sa_sigignore = *sigignore;
    846  7930   Roger 	return (0);
    847  7930   Roger }
    848  7930   Roger 
    849  7930   Roger int
    850  7930   Roger posix_spawnattr_getsigignore_np(
    851  7930   Roger 	const posix_spawnattr_t *attr,
    852  7930   Roger 	sigset_t *sigignore)
    853  7930   Roger {
    854  7930   Roger 	spawn_attr_t *sap = attr->__spawn_attrp;
    855  7930   Roger 
    856  7930   Roger 	if (sap == NULL)
    857  7930   Roger 		return (EINVAL);
    858  7930   Roger 
    859  7930   Roger 	*sigignore = sap->sa_sigignore;
    860  7930   Roger 	return (0);
    861  7930   Roger }
    862  7930   Roger 
    863  7930   Roger int
    864  6812     raf posix_spawnattr_setsigmask(
    865     0  stevel 	posix_spawnattr_t *attr,
    866     0  stevel 	const sigset_t *sigmask)
    867     0  stevel {
    868     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    869     0  stevel 
    870     0  stevel 	if (sap == NULL)
    871     0  stevel 		return (EINVAL);
    872     0  stevel 
    873     0  stevel 	sap->sa_sigmask = *sigmask;
    874     0  stevel 	return (0);
    875     0  stevel }
    876     0  stevel 
    877     0  stevel int
    878  6812     raf posix_spawnattr_getsigmask(
    879     0  stevel 	const posix_spawnattr_t *attr,
    880     0  stevel 	sigset_t *sigmask)
    881     0  stevel {
    882     0  stevel 	spawn_attr_t *sap = attr->__spawn_attrp;
    883     0  stevel 
    884     0  stevel 	if (sap == NULL)
    885     0  stevel 		return (EINVAL);
    886     0  stevel 
    887     0  stevel 	*sigmask = sap->sa_sigmask;
    888     0  stevel 	return (0);
    889     0  stevel }
    890