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