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