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 /* 235891Sraf * Copyright 2008 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> 320Sstevel@tonic-gate #include <alloca.h> 330Sstevel@tonic-gate #include <spawn.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate #define ALL_POSIX_SPAWN_FLAGS \ 360Sstevel@tonic-gate (POSIX_SPAWN_RESETIDS | \ 370Sstevel@tonic-gate POSIX_SPAWN_SETPGROUP | \ 380Sstevel@tonic-gate POSIX_SPAWN_SETSIGDEF | \ 390Sstevel@tonic-gate POSIX_SPAWN_SETSIGMASK | \ 400Sstevel@tonic-gate POSIX_SPAWN_SETSCHEDPARAM | \ 413235Sraf POSIX_SPAWN_SETSCHEDULER | \ 42*7930SRoger.Faulkner@Sun.COM POSIX_SPAWN_SETSIGIGN_NP | \ 433235Sraf POSIX_SPAWN_NOSIGCHLD_NP | \ 447635SRoger.Faulkner@Sun.COM POSIX_SPAWN_WAITPID_NP | \ 457635SRoger.Faulkner@Sun.COM POSIX_SPAWN_NOEXECERR_NP) 460Sstevel@tonic-gate 470Sstevel@tonic-gate typedef struct { 486247Sraf int sa_psflags; /* POSIX_SPAWN_* flags */ 496247Sraf int sa_priority; 500Sstevel@tonic-gate int sa_schedpolicy; 510Sstevel@tonic-gate pid_t sa_pgroup; 520Sstevel@tonic-gate sigset_t sa_sigdefault; 53*7930SRoger.Faulkner@Sun.COM sigset_t sa_sigignore; 540Sstevel@tonic-gate sigset_t sa_sigmask; 550Sstevel@tonic-gate } spawn_attr_t; 560Sstevel@tonic-gate 570Sstevel@tonic-gate typedef struct file_attr { 580Sstevel@tonic-gate struct file_attr *fa_next; /* circular list of file actions */ 590Sstevel@tonic-gate struct file_attr *fa_prev; 600Sstevel@tonic-gate enum {FA_OPEN, FA_CLOSE, FA_DUP2} fa_type; 610Sstevel@tonic-gate uint_t fa_pathsize; /* size of fa_path[] array */ 620Sstevel@tonic-gate char *fa_path; /* copied pathname for open() */ 630Sstevel@tonic-gate int fa_oflag; /* oflag for open() */ 640Sstevel@tonic-gate mode_t fa_mode; /* mode for open() */ 650Sstevel@tonic-gate int fa_filedes; /* file descriptor for open()/close() */ 660Sstevel@tonic-gate int fa_newfiledes; /* new file descriptor for dup2() */ 670Sstevel@tonic-gate } file_attr_t; 680Sstevel@tonic-gate 690Sstevel@tonic-gate extern int __lwp_sigmask(int, const sigset_t *, sigset_t *); 700Sstevel@tonic-gate extern int __sigaction(int, const struct sigaction *, struct sigaction *); 710Sstevel@tonic-gate 723086Sraf static int 730Sstevel@tonic-gate perform_flag_actions(spawn_attr_t *sap) 740Sstevel@tonic-gate { 750Sstevel@tonic-gate int sig; 76*7930SRoger.Faulkner@Sun.COM struct sigaction action; 770Sstevel@tonic-gate 780Sstevel@tonic-gate if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) { 790Sstevel@tonic-gate (void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask, NULL); 800Sstevel@tonic-gate } 810Sstevel@tonic-gate 82*7930SRoger.Faulkner@Sun.COM if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) { 83*7930SRoger.Faulkner@Sun.COM (void) memset(&action, 0, sizeof (action)); 84*7930SRoger.Faulkner@Sun.COM action.sa_handler = SIG_IGN; 85*7930SRoger.Faulkner@Sun.COM for (sig = 1; sig < NSIG; sig++) { 86*7930SRoger.Faulkner@Sun.COM if (sigismember(&sap->sa_sigignore, sig)) 87*7930SRoger.Faulkner@Sun.COM (void) __sigaction(sig, &action, NULL); 88*7930SRoger.Faulkner@Sun.COM } 89*7930SRoger.Faulkner@Sun.COM } 90*7930SRoger.Faulkner@Sun.COM 910Sstevel@tonic-gate if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) { 92*7930SRoger.Faulkner@Sun.COM (void) memset(&action, 0, sizeof (action)); 93*7930SRoger.Faulkner@Sun.COM action.sa_handler = SIG_DFL; 940Sstevel@tonic-gate for (sig = 1; sig < NSIG; sig++) { 956515Sraf if (sigismember(&sap->sa_sigdefault, sig)) 96*7930SRoger.Faulkner@Sun.COM (void) __sigaction(sig, &action, NULL); 970Sstevel@tonic-gate } 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) { 1016515Sraf if (setgid(getgid()) != 0 || setuid(getuid()) != 0) 1023086Sraf return (errno); 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) { 1066515Sraf if (setpgid(0, sap->sa_pgroup) != 0) 1073086Sraf return (errno); 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) { 1116247Sraf if (setparam(P_LWPID, P_MYID, 1126247Sraf sap->sa_schedpolicy, sap->sa_priority) == -1) 1133086Sraf return (errno); 1140Sstevel@tonic-gate } else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) { 1156247Sraf if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1) 1163086Sraf return (errno); 1170Sstevel@tonic-gate } 1183086Sraf 1193086Sraf return (0); 1200Sstevel@tonic-gate } 1210Sstevel@tonic-gate 1223086Sraf static int 1230Sstevel@tonic-gate perform_file_actions(file_attr_t *fap) 1240Sstevel@tonic-gate { 1250Sstevel@tonic-gate file_attr_t *froot = fap; 1260Sstevel@tonic-gate int fd; 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate do { 1290Sstevel@tonic-gate switch (fap->fa_type) { 1300Sstevel@tonic-gate case FA_OPEN: 1316515Sraf fd = __open(fap->fa_path, 1325891Sraf fap->fa_oflag, fap->fa_mode); 1330Sstevel@tonic-gate if (fd < 0) 1343086Sraf return (errno); 1350Sstevel@tonic-gate if (fd != fap->fa_filedes) { 1366515Sraf if (__fcntl(fd, F_DUP2FD, fap->fa_filedes) < 0) 1373086Sraf return (errno); 1386515Sraf (void) __close(fd); 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate break; 1410Sstevel@tonic-gate case FA_CLOSE: 1426515Sraf if (__close(fap->fa_filedes) == -1) 1433086Sraf return (errno); 1440Sstevel@tonic-gate break; 1450Sstevel@tonic-gate case FA_DUP2: 1466515Sraf fd = __fcntl(fap->fa_filedes, F_DUP2FD, 1475891Sraf fap->fa_newfiledes); 1480Sstevel@tonic-gate if (fd < 0) 1493086Sraf return (errno); 1500Sstevel@tonic-gate break; 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate } while ((fap = fap->fa_next) != froot); 1533086Sraf 1543086Sraf return (0); 1553086Sraf } 1563086Sraf 1573235Sraf static int 1583235Sraf forkflags(spawn_attr_t *sap) 1593235Sraf { 1603235Sraf int flags = 0; 1613235Sraf 1623235Sraf if (sap != NULL) { 1633235Sraf if (sap->sa_psflags & POSIX_SPAWN_NOSIGCHLD_NP) 1643235Sraf flags |= FORK_NOSIGCHLD; 1653235Sraf if (sap->sa_psflags & POSIX_SPAWN_WAITPID_NP) 1663235Sraf flags |= FORK_WAITPID; 1673235Sraf } 1683235Sraf 1693235Sraf return (flags); 1703235Sraf } 1713235Sraf 1723086Sraf /* 1733086Sraf * set_error() / get_error() are used to guarantee that the local variable 1743086Sraf * 'error' is set correctly in memory on return from vfork() in the parent. 1753086Sraf */ 1763086Sraf 1773086Sraf static int 1783086Sraf set_error(int *errp, int err) 1793086Sraf { 1803086Sraf return (*errp = err); 1813086Sraf } 1823086Sraf 1833086Sraf static int 1843086Sraf get_error(int *errp) 1853086Sraf { 1863086Sraf return (*errp); 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate /* 1900Sstevel@tonic-gate * For MT safety, do not invoke the dynamic linker after calling vfork(). 1910Sstevel@tonic-gate * If some other thread was in the dynamic linker when this thread's parent 1920Sstevel@tonic-gate * called vfork() then the dynamic linker's lock would still be held here 1930Sstevel@tonic-gate * (with a defunct owner) and we would deadlock ourself if we invoked it. 1940Sstevel@tonic-gate * 1950Sstevel@tonic-gate * Therefore, all of the functions we call here after returning from 1966812Sraf * vforkx() in the child are not and must never be exported from libc 1970Sstevel@tonic-gate * as global symbols. To do so would risk invoking the dynamic linker. 1980Sstevel@tonic-gate */ 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate int 2016812Sraf posix_spawn( 2020Sstevel@tonic-gate pid_t *pidp, 2030Sstevel@tonic-gate const char *path, 2040Sstevel@tonic-gate const posix_spawn_file_actions_t *file_actions, 2050Sstevel@tonic-gate const posix_spawnattr_t *attrp, 2060Sstevel@tonic-gate char *const argv[], 2070Sstevel@tonic-gate char *const envp[]) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL; 2100Sstevel@tonic-gate file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL; 2113086Sraf int error; /* this will be set by the child */ 2120Sstevel@tonic-gate pid_t pid; 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate if (attrp != NULL && sap == NULL) 2150Sstevel@tonic-gate return (EINVAL); 2160Sstevel@tonic-gate 2176812Sraf switch (pid = vforkx(forkflags(sap))) { 2180Sstevel@tonic-gate case 0: /* child */ 2190Sstevel@tonic-gate break; 2200Sstevel@tonic-gate case -1: /* parent, failure */ 2210Sstevel@tonic-gate return (errno); 2220Sstevel@tonic-gate default: /* parent, success */ 2233086Sraf /* 2243086Sraf * We don't get here until the child exec()s or exit()s 2253086Sraf */ 2263086Sraf if (pidp != NULL && get_error(&error) == 0) 2270Sstevel@tonic-gate *pidp = pid; 2283086Sraf return (get_error(&error)); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate if (sap != NULL) 2323086Sraf if (set_error(&error, perform_flag_actions(sap)) != 0) 2336515Sraf _exit(_EVAPORATE); 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate if (fap != NULL) 2363086Sraf if (set_error(&error, perform_file_actions(fap)) != 0) 2376515Sraf _exit(_EVAPORATE); 2380Sstevel@tonic-gate 2393086Sraf (void) set_error(&error, 0); 2406515Sraf (void) execve(path, argv, envp); 2417635SRoger.Faulkner@Sun.COM if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) 2427635SRoger.Faulkner@Sun.COM _exit(127); 2433086Sraf (void) set_error(&error, errno); 2446515Sraf _exit(_EVAPORATE); 2450Sstevel@tonic-gate return (0); /* not reached */ 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* 2490Sstevel@tonic-gate * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c). 2500Sstevel@tonic-gate */ 2510Sstevel@tonic-gate 2525891Sraf extern int libc__xpg4; 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate static const char * 2550Sstevel@tonic-gate execat(const char *s1, const char *s2, char *si) 2560Sstevel@tonic-gate { 2570Sstevel@tonic-gate int cnt = PATH_MAX + 1; 2580Sstevel@tonic-gate char *s; 2590Sstevel@tonic-gate char c; 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate for (s = si; (c = *s1) != '\0' && c != ':'; s1++) { 2620Sstevel@tonic-gate if (cnt > 0) { 2630Sstevel@tonic-gate *s++ = c; 2640Sstevel@tonic-gate cnt--; 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate if (si != s && cnt > 0) { 2680Sstevel@tonic-gate *s++ = '/'; 2690Sstevel@tonic-gate cnt--; 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate for (; (c = *s2) != '\0' && cnt > 0; s2++) { 2720Sstevel@tonic-gate *s++ = c; 2730Sstevel@tonic-gate cnt--; 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate *s = '\0'; 2760Sstevel@tonic-gate return (*s1? ++s1: NULL); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate /* ARGSUSED */ 2800Sstevel@tonic-gate int 2816812Sraf posix_spawnp( 2820Sstevel@tonic-gate pid_t *pidp, 2830Sstevel@tonic-gate const char *file, 2840Sstevel@tonic-gate const posix_spawn_file_actions_t *file_actions, 2850Sstevel@tonic-gate const posix_spawnattr_t *attrp, 2860Sstevel@tonic-gate char *const argv[], 2870Sstevel@tonic-gate char *const envp[]) 2880Sstevel@tonic-gate { 2890Sstevel@tonic-gate spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL; 2900Sstevel@tonic-gate file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL; 2910Sstevel@tonic-gate const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : ""; 2925891Sraf int xpg4 = libc__xpg4; 2937646SRoger.Faulkner@Sun.COM int error = 0; /* this will be set by the child */ 2940Sstevel@tonic-gate char path[PATH_MAX+4]; 2950Sstevel@tonic-gate const char *cp; 2960Sstevel@tonic-gate pid_t pid; 2970Sstevel@tonic-gate char **newargs; 2980Sstevel@tonic-gate int argc; 2990Sstevel@tonic-gate int i; 3000Sstevel@tonic-gate static const char *sun_path = "/bin/sh"; 3010Sstevel@tonic-gate static const char *xpg4_path = "/usr/xpg4/bin/sh"; 3020Sstevel@tonic-gate static const char *shell = "sh"; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate if (attrp != NULL && sap == NULL) 3050Sstevel@tonic-gate return (EINVAL); 3060Sstevel@tonic-gate 3073086Sraf if (*file == '\0') 3083086Sraf return (EACCES); 3093086Sraf 3100Sstevel@tonic-gate /* 3110Sstevel@tonic-gate * We may need to invoke the shell with a slightly modified 3120Sstevel@tonic-gate * argv[] array. To do this we need to preallocate the array. 3130Sstevel@tonic-gate * We must call alloca() before calling vfork() because doing 3140Sstevel@tonic-gate * it after vfork() (in the child) would corrupt the parent. 3150Sstevel@tonic-gate */ 3160Sstevel@tonic-gate for (argc = 0; argv[argc] != NULL; argc++) 3170Sstevel@tonic-gate continue; 3180Sstevel@tonic-gate newargs = alloca((argc + 2) * sizeof (char *)); 3190Sstevel@tonic-gate 3206812Sraf switch (pid = vforkx(forkflags(sap))) { 3210Sstevel@tonic-gate case 0: /* child */ 3220Sstevel@tonic-gate break; 3230Sstevel@tonic-gate case -1: /* parent, failure */ 3240Sstevel@tonic-gate return (errno); 3250Sstevel@tonic-gate default: /* parent, success */ 3263086Sraf /* 3273086Sraf * We don't get here until the child exec()s or exit()s 3283086Sraf */ 3293086Sraf if (pidp != NULL && get_error(&error) == 0) 3300Sstevel@tonic-gate *pidp = pid; 3313086Sraf return (get_error(&error)); 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate if (sap != NULL) 3353086Sraf if (set_error(&error, perform_flag_actions(sap)) != 0) 3366515Sraf _exit(_EVAPORATE); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate if (fap != NULL) 3393086Sraf if (set_error(&error, perform_file_actions(fap)) != 0) 3406515Sraf _exit(_EVAPORATE); 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate if (pathstr == NULL) { 3430Sstevel@tonic-gate /* 3440Sstevel@tonic-gate * XPG4: pathstr is equivalent to _CS_PATH, except that 3450Sstevel@tonic-gate * :/usr/sbin is appended when root, and pathstr must end 3460Sstevel@tonic-gate * with a colon when not root. Keep these paths in sync 3470Sstevel@tonic-gate * with _CS_PATH in confstr.c. Note that pathstr must end 3480Sstevel@tonic-gate * with a colon when not root so that when file doesn't 3490Sstevel@tonic-gate * contain '/', the last call to execat() will result in an 3500Sstevel@tonic-gate * attempt to execv file from the current directory. 3510Sstevel@tonic-gate */ 3526515Sraf if (geteuid() == 0 || getuid() == 0) { 3530Sstevel@tonic-gate if (!xpg4) 3540Sstevel@tonic-gate pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin"; 3550Sstevel@tonic-gate else 3560Sstevel@tonic-gate pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 3570Sstevel@tonic-gate "/usr/bin:/opt/SUNWspro/bin:/usr/sbin"; 3580Sstevel@tonic-gate } else { 3590Sstevel@tonic-gate if (!xpg4) 3600Sstevel@tonic-gate pathstr = "/usr/ccs/bin:/usr/bin:"; 3610Sstevel@tonic-gate else 3620Sstevel@tonic-gate pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 3630Sstevel@tonic-gate "/usr/bin:/opt/SUNWspro/bin:"; 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate cp = pathstr; 3680Sstevel@tonic-gate do { 3690Sstevel@tonic-gate cp = execat(cp, file, path); 3700Sstevel@tonic-gate /* 3710Sstevel@tonic-gate * 4025035 and 4038378 3720Sstevel@tonic-gate * if a filename begins with a "-" prepend "./" so that 3730Sstevel@tonic-gate * the shell can't interpret it as an option 3740Sstevel@tonic-gate */ 3750Sstevel@tonic-gate if (*path == '-') { 3760Sstevel@tonic-gate char *s; 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate for (s = path; *s != '\0'; s++) 3790Sstevel@tonic-gate continue; 3800Sstevel@tonic-gate for (; s >= path; s--) 3810Sstevel@tonic-gate *(s + 2) = *s; 3820Sstevel@tonic-gate path[0] = '.'; 3830Sstevel@tonic-gate path[1] = '/'; 3840Sstevel@tonic-gate } 3853086Sraf (void) set_error(&error, 0); 3866515Sraf (void) execve(path, argv, envp); 3873086Sraf if (set_error(&error, errno) == ENOEXEC) { 3880Sstevel@tonic-gate newargs[0] = (char *)shell; 3890Sstevel@tonic-gate newargs[1] = path; 3900Sstevel@tonic-gate for (i = 1; i <= argc; i++) 3910Sstevel@tonic-gate newargs[i + 1] = argv[i]; 3923086Sraf (void) set_error(&error, 0); 3936515Sraf (void) execve(xpg4? xpg4_path : sun_path, 3943086Sraf newargs, envp); 3957635SRoger.Faulkner@Sun.COM if (sap != NULL && 3967635SRoger.Faulkner@Sun.COM (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) 3977635SRoger.Faulkner@Sun.COM _exit(127); 3983086Sraf (void) set_error(&error, errno); 3996515Sraf _exit(_EVAPORATE); 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate } while (cp); 4027646SRoger.Faulkner@Sun.COM 4037646SRoger.Faulkner@Sun.COM if (sap != NULL && 4047646SRoger.Faulkner@Sun.COM (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) { 4057646SRoger.Faulkner@Sun.COM (void) set_error(&error, 0); 4067646SRoger.Faulkner@Sun.COM _exit(127); 4077646SRoger.Faulkner@Sun.COM } 4086515Sraf _exit(_EVAPORATE); 4090Sstevel@tonic-gate return (0); /* not reached */ 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate int 4136812Sraf posix_spawn_file_actions_init( 4140Sstevel@tonic-gate posix_spawn_file_actions_t *file_actions) 4150Sstevel@tonic-gate { 4160Sstevel@tonic-gate file_actions->__file_attrp = NULL; 4170Sstevel@tonic-gate return (0); 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate int 4216812Sraf posix_spawn_file_actions_destroy( 4220Sstevel@tonic-gate posix_spawn_file_actions_t *file_actions) 4230Sstevel@tonic-gate { 4240Sstevel@tonic-gate file_attr_t *froot = file_actions->__file_attrp; 4250Sstevel@tonic-gate file_attr_t *fap; 4260Sstevel@tonic-gate file_attr_t *next; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate if ((fap = froot) != NULL) { 4290Sstevel@tonic-gate do { 4300Sstevel@tonic-gate next = fap->fa_next; 4310Sstevel@tonic-gate if (fap-> fa_type == FA_OPEN) 4320Sstevel@tonic-gate lfree(fap->fa_path, fap->fa_pathsize); 4330Sstevel@tonic-gate lfree(fap, sizeof (*fap)); 4340Sstevel@tonic-gate } while ((fap = next) != froot); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate file_actions->__file_attrp = NULL; 4370Sstevel@tonic-gate return (0); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate static void 4410Sstevel@tonic-gate add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap) 4420Sstevel@tonic-gate { 4430Sstevel@tonic-gate file_attr_t *froot = file_actions->__file_attrp; 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate if (froot == NULL) { 4460Sstevel@tonic-gate fap->fa_next = fap->fa_prev = fap; 4470Sstevel@tonic-gate file_actions->__file_attrp = fap; 4480Sstevel@tonic-gate } else { 4490Sstevel@tonic-gate fap->fa_next = froot; 4500Sstevel@tonic-gate fap->fa_prev = froot->fa_prev; 4510Sstevel@tonic-gate froot->fa_prev->fa_next = fap; 4520Sstevel@tonic-gate froot->fa_prev = fap; 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate int 4576812Sraf posix_spawn_file_actions_addopen( 4580Sstevel@tonic-gate posix_spawn_file_actions_t *file_actions, 4590Sstevel@tonic-gate int filedes, 4600Sstevel@tonic-gate const char *path, 4610Sstevel@tonic-gate int oflag, 4620Sstevel@tonic-gate mode_t mode) 4630Sstevel@tonic-gate { 4640Sstevel@tonic-gate file_attr_t *fap; 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate if (filedes < 0) 4670Sstevel@tonic-gate return (EBADF); 4680Sstevel@tonic-gate if ((fap = lmalloc(sizeof (*fap))) == NULL) 4690Sstevel@tonic-gate return (ENOMEM); 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate fap->fa_pathsize = strlen(path) + 1; 4720Sstevel@tonic-gate if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) { 4730Sstevel@tonic-gate lfree(fap, sizeof (*fap)); 4740Sstevel@tonic-gate return (ENOMEM); 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate (void) strcpy(fap->fa_path, path); 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate fap->fa_type = FA_OPEN; 4790Sstevel@tonic-gate fap->fa_oflag = oflag; 4800Sstevel@tonic-gate fap->fa_mode = mode; 4810Sstevel@tonic-gate fap->fa_filedes = filedes; 4820Sstevel@tonic-gate add_file_attr(file_actions, fap); 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate return (0); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate int 4886812Sraf posix_spawn_file_actions_addclose( 4890Sstevel@tonic-gate posix_spawn_file_actions_t *file_actions, 4900Sstevel@tonic-gate int filedes) 4910Sstevel@tonic-gate { 4920Sstevel@tonic-gate file_attr_t *fap; 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate if (filedes < 0) 4950Sstevel@tonic-gate return (EBADF); 4960Sstevel@tonic-gate if ((fap = lmalloc(sizeof (*fap))) == NULL) 4970Sstevel@tonic-gate return (ENOMEM); 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate fap->fa_type = FA_CLOSE; 5000Sstevel@tonic-gate fap->fa_filedes = filedes; 5010Sstevel@tonic-gate add_file_attr(file_actions, fap); 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate return (0); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate int 5076812Sraf posix_spawn_file_actions_adddup2( 5080Sstevel@tonic-gate posix_spawn_file_actions_t *file_actions, 5090Sstevel@tonic-gate int filedes, 5100Sstevel@tonic-gate int newfiledes) 5110Sstevel@tonic-gate { 5120Sstevel@tonic-gate file_attr_t *fap; 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate if (filedes < 0 || newfiledes < 0) 5150Sstevel@tonic-gate return (EBADF); 5160Sstevel@tonic-gate if ((fap = lmalloc(sizeof (*fap))) == NULL) 5170Sstevel@tonic-gate return (ENOMEM); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate fap->fa_type = FA_DUP2; 5200Sstevel@tonic-gate fap->fa_filedes = filedes; 5210Sstevel@tonic-gate fap->fa_newfiledes = newfiledes; 5220Sstevel@tonic-gate add_file_attr(file_actions, fap); 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate return (0); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate int 5286812Sraf posix_spawnattr_init( 5290Sstevel@tonic-gate posix_spawnattr_t *attr) 5300Sstevel@tonic-gate { 5313235Sraf if ((attr->__spawn_attrp = lmalloc(sizeof (posix_spawnattr_t))) == NULL) 5320Sstevel@tonic-gate return (ENOMEM); 5330Sstevel@tonic-gate /* 5340Sstevel@tonic-gate * Add default stuff here? 5350Sstevel@tonic-gate */ 5360Sstevel@tonic-gate return (0); 5370Sstevel@tonic-gate } 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate int 5406812Sraf posix_spawnattr_destroy( 5410Sstevel@tonic-gate posix_spawnattr_t *attr) 5420Sstevel@tonic-gate { 5430Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate if (sap == NULL) 5460Sstevel@tonic-gate return (EINVAL); 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate /* 5490Sstevel@tonic-gate * deallocate stuff here? 5500Sstevel@tonic-gate */ 5510Sstevel@tonic-gate lfree(sap, sizeof (*sap)); 5520Sstevel@tonic-gate attr->__spawn_attrp = NULL; 5530Sstevel@tonic-gate return (0); 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate int 5576812Sraf posix_spawnattr_setflags( 5580Sstevel@tonic-gate posix_spawnattr_t *attr, 5590Sstevel@tonic-gate short flags) 5600Sstevel@tonic-gate { 5610Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate if (sap == NULL || 5640Sstevel@tonic-gate (flags & ~ALL_POSIX_SPAWN_FLAGS)) 5650Sstevel@tonic-gate return (EINVAL); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate sap->sa_psflags = flags; 5680Sstevel@tonic-gate return (0); 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate int 5726812Sraf posix_spawnattr_getflags( 5730Sstevel@tonic-gate const posix_spawnattr_t *attr, 5740Sstevel@tonic-gate short *flags) 5750Sstevel@tonic-gate { 5760Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate if (sap == NULL) 5790Sstevel@tonic-gate return (EINVAL); 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate *flags = sap->sa_psflags; 5820Sstevel@tonic-gate return (0); 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate int 5866812Sraf posix_spawnattr_setpgroup( 5870Sstevel@tonic-gate posix_spawnattr_t *attr, 5880Sstevel@tonic-gate pid_t pgroup) 5890Sstevel@tonic-gate { 5900Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate if (sap == NULL) 5930Sstevel@tonic-gate return (EINVAL); 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate sap->sa_pgroup = pgroup; 5960Sstevel@tonic-gate return (0); 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate int 6006812Sraf posix_spawnattr_getpgroup( 6010Sstevel@tonic-gate const posix_spawnattr_t *attr, 6020Sstevel@tonic-gate pid_t *pgroup) 6030Sstevel@tonic-gate { 6040Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate if (sap == NULL) 6070Sstevel@tonic-gate return (EINVAL); 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate *pgroup = sap->sa_pgroup; 6100Sstevel@tonic-gate return (0); 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate int 6146812Sraf posix_spawnattr_setschedparam( 6150Sstevel@tonic-gate posix_spawnattr_t *attr, 6160Sstevel@tonic-gate const struct sched_param *schedparam) 6170Sstevel@tonic-gate { 6180Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate if (sap == NULL) 6210Sstevel@tonic-gate return (EINVAL); 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* 6240Sstevel@tonic-gate * Check validity? 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate sap->sa_priority = schedparam->sched_priority; 6270Sstevel@tonic-gate return (0); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate int 6316812Sraf posix_spawnattr_getschedparam( 6320Sstevel@tonic-gate const posix_spawnattr_t *attr, 6330Sstevel@tonic-gate struct sched_param *schedparam) 6340Sstevel@tonic-gate { 6350Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate if (sap == NULL) 6380Sstevel@tonic-gate return (EINVAL); 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate schedparam->sched_priority = sap->sa_priority; 6410Sstevel@tonic-gate return (0); 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate int 6456812Sraf posix_spawnattr_setschedpolicy( 6460Sstevel@tonic-gate posix_spawnattr_t *attr, 6470Sstevel@tonic-gate int schedpolicy) 6480Sstevel@tonic-gate { 6490Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 6500Sstevel@tonic-gate 6516247Sraf if (sap == NULL || schedpolicy == SCHED_SYS) 6520Sstevel@tonic-gate return (EINVAL); 6530Sstevel@tonic-gate 6546247Sraf /* 6556247Sraf * Cache the policy information for later use 6566247Sraf * by the vfork() child of posix_spawn(). 6576247Sraf */ 6586247Sraf if (get_info_by_policy(schedpolicy) == NULL) 6596247Sraf return (errno); 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate sap->sa_schedpolicy = schedpolicy; 6620Sstevel@tonic-gate return (0); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate int 6666812Sraf posix_spawnattr_getschedpolicy( 6670Sstevel@tonic-gate const posix_spawnattr_t *attr, 6680Sstevel@tonic-gate int *schedpolicy) 6690Sstevel@tonic-gate { 6700Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate if (sap == NULL) 6730Sstevel@tonic-gate return (EINVAL); 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate *schedpolicy = sap->sa_schedpolicy; 6760Sstevel@tonic-gate return (0); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate int 6806812Sraf posix_spawnattr_setsigdefault( 6810Sstevel@tonic-gate posix_spawnattr_t *attr, 6820Sstevel@tonic-gate const sigset_t *sigdefault) 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 return (EINVAL); 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate sap->sa_sigdefault = *sigdefault; 6900Sstevel@tonic-gate return (0); 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate int 6946812Sraf posix_spawnattr_getsigdefault( 6950Sstevel@tonic-gate const posix_spawnattr_t *attr, 6960Sstevel@tonic-gate sigset_t *sigdefault) 6970Sstevel@tonic-gate { 6980Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate if (sap == NULL) 7010Sstevel@tonic-gate return (EINVAL); 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate *sigdefault = sap->sa_sigdefault; 7040Sstevel@tonic-gate return (0); 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate int 708*7930SRoger.Faulkner@Sun.COM posix_spawnattr_setsigignore_np( 709*7930SRoger.Faulkner@Sun.COM posix_spawnattr_t *attr, 710*7930SRoger.Faulkner@Sun.COM const sigset_t *sigignore) 711*7930SRoger.Faulkner@Sun.COM { 712*7930SRoger.Faulkner@Sun.COM spawn_attr_t *sap = attr->__spawn_attrp; 713*7930SRoger.Faulkner@Sun.COM 714*7930SRoger.Faulkner@Sun.COM if (sap == NULL) 715*7930SRoger.Faulkner@Sun.COM return (EINVAL); 716*7930SRoger.Faulkner@Sun.COM 717*7930SRoger.Faulkner@Sun.COM sap->sa_sigignore = *sigignore; 718*7930SRoger.Faulkner@Sun.COM return (0); 719*7930SRoger.Faulkner@Sun.COM } 720*7930SRoger.Faulkner@Sun.COM 721*7930SRoger.Faulkner@Sun.COM int 722*7930SRoger.Faulkner@Sun.COM posix_spawnattr_getsigignore_np( 723*7930SRoger.Faulkner@Sun.COM const posix_spawnattr_t *attr, 724*7930SRoger.Faulkner@Sun.COM sigset_t *sigignore) 725*7930SRoger.Faulkner@Sun.COM { 726*7930SRoger.Faulkner@Sun.COM spawn_attr_t *sap = attr->__spawn_attrp; 727*7930SRoger.Faulkner@Sun.COM 728*7930SRoger.Faulkner@Sun.COM if (sap == NULL) 729*7930SRoger.Faulkner@Sun.COM return (EINVAL); 730*7930SRoger.Faulkner@Sun.COM 731*7930SRoger.Faulkner@Sun.COM *sigignore = sap->sa_sigignore; 732*7930SRoger.Faulkner@Sun.COM return (0); 733*7930SRoger.Faulkner@Sun.COM } 734*7930SRoger.Faulkner@Sun.COM 735*7930SRoger.Faulkner@Sun.COM int 7366812Sraf posix_spawnattr_setsigmask( 7370Sstevel@tonic-gate posix_spawnattr_t *attr, 7380Sstevel@tonic-gate const sigset_t *sigmask) 7390Sstevel@tonic-gate { 7400Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate if (sap == NULL) 7430Sstevel@tonic-gate return (EINVAL); 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate sap->sa_sigmask = *sigmask; 7460Sstevel@tonic-gate return (0); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate int 7506812Sraf posix_spawnattr_getsigmask( 7510Sstevel@tonic-gate const posix_spawnattr_t *attr, 7520Sstevel@tonic-gate sigset_t *sigmask) 7530Sstevel@tonic-gate { 7540Sstevel@tonic-gate spawn_attr_t *sap = attr->__spawn_attrp; 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate if (sap == NULL) 7570Sstevel@tonic-gate return (EINVAL); 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate *sigmask = sap->sa_sigmask; 7600Sstevel@tonic-gate return (0); 7610Sstevel@tonic-gate } 762