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