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
27*462453d2SMatthew Ahrens /*
28*462453d2SMatthew Ahrens * Copyright (c) 2011 by Delphix. All rights reserved.
29*462453d2SMatthew Ahrens */
30*462453d2SMatthew 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
84*462453d2SMatthew Ahrens extern const char **_environ;
85*462453d2SMatthew 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
spawn_closefrom(int lowfd,void * buf)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
perform_flag_actions(spawn_attr_t * sap)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
perform_file_actions(file_attr_t * fap,void * dirbuf)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
forkflags(spawn_attr_t * sap)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
set_error(int * errp,int err)2558ceba33eSraf set_error(int *errp, int err)
2568ceba33eSraf {
2578ceba33eSraf return (*errp = err);
2588ceba33eSraf }
2598ceba33eSraf
2608ceba33eSraf static int
get_error(int * errp)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
posix_spawn(pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])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,
2837c478bd9Sstevel@tonic-gate char *const argv[],
2847c478bd9Sstevel@tonic-gate 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 *
execat(const char * s1,const char * s2,char * si)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
posix_spawnp(pid_t * pidp,const char * file,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])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,
3777c478bd9Sstevel@tonic-gate char *const argv[],
3787c478bd9Sstevel@tonic-gate 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
posix_spawn_file_actions_init(posix_spawn_file_actions_t * file_actions)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
posix_spawn_file_actions_destroy(posix_spawn_file_actions_t * file_actions)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
add_file_attr(posix_spawn_file_actions_t * file_actions,file_attr_t * fap)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
posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * file_actions,int filedes,const char * path,int oflag,mode_t mode)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
posix_spawn_file_actions_addclose(posix_spawn_file_actions_t * file_actions,int filedes)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
posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t * file_actions,int filedes,int newfiledes)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
posix_spawn_file_actions_addclosefrom_np(posix_spawn_file_actions_t * file_actions,int lowfiledes)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
posix_spawnattr_init(posix_spawnattr_t * attr)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
posix_spawnattr_destroy(posix_spawnattr_t * attr)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
posix_spawnattr_setflags(posix_spawnattr_t * attr,short flags)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
posix_spawnattr_getflags(const posix_spawnattr_t * attr,short * flags)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
posix_spawnattr_setpgroup(posix_spawnattr_t * attr,pid_t pgroup)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
posix_spawnattr_getpgroup(const posix_spawnattr_t * attr,pid_t * pgroup)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
posix_spawnattr_setschedparam(posix_spawnattr_t * attr,const struct sched_param * schedparam)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
posix_spawnattr_getschedparam(const posix_spawnattr_t * attr,struct sched_param * schedparam)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
posix_spawnattr_setschedpolicy(posix_spawnattr_t * attr,int schedpolicy)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
posix_spawnattr_getschedpolicy(const posix_spawnattr_t * attr,int * schedpolicy)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
posix_spawnattr_setsigdefault(posix_spawnattr_t * attr,const sigset_t * sigdefault)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
posix_spawnattr_getsigdefault(const posix_spawnattr_t * attr,sigset_t * sigdefault)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
posix_spawnattr_setsigignore_np(posix_spawnattr_t * attr,const sigset_t * sigignore)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
posix_spawnattr_getsigignore_np(const posix_spawnattr_t * attr,sigset_t * sigignore)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
posix_spawnattr_setsigmask(posix_spawnattr_t * attr,const sigset_t * sigmask)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
posix_spawnattr_getsigmask(const posix_spawnattr_t * attr,sigset_t * sigmask)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 }
888*462453d2SMatthew Ahrens
889*462453d2SMatthew Ahrens /*
890*462453d2SMatthew Ahrens * Spawn a process to run "sh -c <cmd>". Return the child's pid (in
891*462453d2SMatthew Ahrens * *pidp), and a file descriptor (in *fdp) for reading or writing to the
892*462453d2SMatthew Ahrens * child process, depending on the 'write' argument.
893*462453d2SMatthew Ahrens * Return 0 on success; otherwise return an error code.
894*462453d2SMatthew Ahrens */
895*462453d2SMatthew Ahrens int
posix_spawn_pipe_np(pid_t * pidp,int * fdp,const char * cmd,boolean_t write,posix_spawn_file_actions_t * fact,posix_spawnattr_t * attr)896*462453d2SMatthew Ahrens posix_spawn_pipe_np(pid_t *pidp, int *fdp,
897*462453d2SMatthew Ahrens const char *cmd, boolean_t write,
898*462453d2SMatthew Ahrens posix_spawn_file_actions_t *fact, posix_spawnattr_t *attr)
899*462453d2SMatthew Ahrens {
900*462453d2SMatthew Ahrens int p[2];
901*462453d2SMatthew Ahrens int myside, yourside, stdio;
902*462453d2SMatthew Ahrens const char *shpath = _PATH_BSHELL;
903*462453d2SMatthew Ahrens const char *argvec[4] = { "sh", "-c", cmd, NULL };
904*462453d2SMatthew Ahrens int error;
905*462453d2SMatthew Ahrens
906*462453d2SMatthew Ahrens if (pipe(p) < 0)
907*462453d2SMatthew Ahrens return (errno);
908*462453d2SMatthew Ahrens
909*462453d2SMatthew Ahrens if (access(shpath, X_OK)) /* XPG4 Requirement: */
910*462453d2SMatthew Ahrens shpath = ""; /* force child to fail immediately */
911*462453d2SMatthew Ahrens
912*462453d2SMatthew Ahrens if (write) {
913*462453d2SMatthew Ahrens /*
914*462453d2SMatthew Ahrens * Data is read from p[0] and written to p[1].
915*462453d2SMatthew Ahrens * 'stdio' is the fd in the child process that should be
916*462453d2SMatthew Ahrens * connected to the pipe.
917*462453d2SMatthew Ahrens */
918*462453d2SMatthew Ahrens myside = p[1];
919*462453d2SMatthew Ahrens yourside = p[0];
920*462453d2SMatthew Ahrens stdio = STDIN_FILENO;
921*462453d2SMatthew Ahrens } else {
922*462453d2SMatthew Ahrens myside = p[0];
923*462453d2SMatthew Ahrens yourside = p[1];
924*462453d2SMatthew Ahrens stdio = STDOUT_FILENO;
925*462453d2SMatthew Ahrens }
926*462453d2SMatthew Ahrens
927*462453d2SMatthew Ahrens error = posix_spawn_file_actions_addclose(fact, myside);
928*462453d2SMatthew Ahrens if (yourside != stdio) {
929*462453d2SMatthew Ahrens if (error == 0) {
930*462453d2SMatthew Ahrens error = posix_spawn_file_actions_adddup2(fact,
931*462453d2SMatthew Ahrens yourside, stdio);
932*462453d2SMatthew Ahrens }
933*462453d2SMatthew Ahrens if (error == 0) {
934*462453d2SMatthew Ahrens error = posix_spawn_file_actions_addclose(fact,
935*462453d2SMatthew Ahrens yourside);
936*462453d2SMatthew Ahrens }
937*462453d2SMatthew Ahrens }
938*462453d2SMatthew Ahrens
939*462453d2SMatthew Ahrens if (error)
940*462453d2SMatthew Ahrens return (error);
941*462453d2SMatthew Ahrens error = posix_spawn(pidp, shpath, fact, attr,
942*462453d2SMatthew Ahrens (char *const *)argvec, (char *const *)_environ);
943*462453d2SMatthew Ahrens (void) close(yourside);
944*462453d2SMatthew Ahrens if (error) {
945*462453d2SMatthew Ahrens (void) close(myside);
946*462453d2SMatthew Ahrens return (error);
947*462453d2SMatthew Ahrens }
948*462453d2SMatthew Ahrens
949*462453d2SMatthew Ahrens *fdp = myside;
950*462453d2SMatthew Ahrens return (0);
951*462453d2SMatthew Ahrens }
952