xref: /onnv-gate/usr/src/lib/libc/port/threads/spawn.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include "lint.h"
30*0Sstevel@tonic-gate #include "thr_uberdata.h"
31*0Sstevel@tonic-gate #include <sys/procset.h>
32*0Sstevel@tonic-gate #include <sys/rtpriocntl.h>
33*0Sstevel@tonic-gate #include <sys/tspriocntl.h>
34*0Sstevel@tonic-gate #include <sys/rt.h>
35*0Sstevel@tonic-gate #include <sys/ts.h>
36*0Sstevel@tonic-gate #include <alloca.h>
37*0Sstevel@tonic-gate #include <spawn.h>
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #define	ALL_POSIX_SPAWN_FLAGS			\
40*0Sstevel@tonic-gate 		(POSIX_SPAWN_RESETIDS |		\
41*0Sstevel@tonic-gate 		POSIX_SPAWN_SETPGROUP |		\
42*0Sstevel@tonic-gate 		POSIX_SPAWN_SETSIGDEF |		\
43*0Sstevel@tonic-gate 		POSIX_SPAWN_SETSIGMASK |	\
44*0Sstevel@tonic-gate 		POSIX_SPAWN_SETSCHEDPARAM |	\
45*0Sstevel@tonic-gate 		POSIX_SPAWN_SETSCHEDULER)
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate typedef struct {
48*0Sstevel@tonic-gate 	short		sa_psflags;	/* POSIX_SPAWN_* flags */
49*0Sstevel@tonic-gate 	pri_t		sa_priority;
50*0Sstevel@tonic-gate 	int		sa_schedpolicy;
51*0Sstevel@tonic-gate 	pid_t		sa_pgroup;
52*0Sstevel@tonic-gate 	sigset_t	sa_sigdefault;
53*0Sstevel@tonic-gate 	sigset_t	sa_sigmask;
54*0Sstevel@tonic-gate } spawn_attr_t;
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate typedef struct file_attr {
57*0Sstevel@tonic-gate 	struct file_attr *fa_next;	/* circular list of file actions */
58*0Sstevel@tonic-gate 	struct file_attr *fa_prev;
59*0Sstevel@tonic-gate 	enum {FA_OPEN, FA_CLOSE, FA_DUP2} fa_type;
60*0Sstevel@tonic-gate 	uint_t		fa_pathsize;	/* size of fa_path[] array */
61*0Sstevel@tonic-gate 	char		*fa_path;	/* copied pathname for open() */
62*0Sstevel@tonic-gate 	int		fa_oflag;	/* oflag for open() */
63*0Sstevel@tonic-gate 	mode_t		fa_mode;	/* mode for open() */
64*0Sstevel@tonic-gate 	int		fa_filedes;	/* file descriptor for open()/close() */
65*0Sstevel@tonic-gate 	int		fa_newfiledes;	/* new file descriptor for dup2() */
66*0Sstevel@tonic-gate } file_attr_t;
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate extern	pid_t	_vfork(void);
69*0Sstevel@tonic-gate #pragma unknown_control_flow(_vfork)
70*0Sstevel@tonic-gate extern	void	*_private_memset(void *, int, size_t);
71*0Sstevel@tonic-gate extern	int	__lwp_sigmask(int, const sigset_t *, sigset_t *);
72*0Sstevel@tonic-gate extern	int	__open(const char *, int, mode_t);
73*0Sstevel@tonic-gate extern	int	__sigaction(int, const struct sigaction *, struct sigaction *);
74*0Sstevel@tonic-gate extern	int	_private_close(int);
75*0Sstevel@tonic-gate extern	int	_private_execve(const char *, char *const *, char *const *);
76*0Sstevel@tonic-gate extern	int	_private_fcntl(int, int, intptr_t);
77*0Sstevel@tonic-gate extern	int	_private_setgid(gid_t);
78*0Sstevel@tonic-gate extern	int	_private_setpgid(pid_t, pid_t);
79*0Sstevel@tonic-gate extern	int	_private_setuid(uid_t);
80*0Sstevel@tonic-gate extern	int	_private_sigismember(sigset_t *, int);
81*0Sstevel@tonic-gate extern	gid_t	_private_getgid(void);
82*0Sstevel@tonic-gate extern	uid_t	_private_getuid(void);
83*0Sstevel@tonic-gate extern	uid_t	_private_geteuid(void);
84*0Sstevel@tonic-gate extern	void	_private_exit(int);
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate /*
87*0Sstevel@tonic-gate  * We call this function rather than priocntl() because we must not call
88*0Sstevel@tonic-gate  * any function that is exported from libc while in the child of vfork().
89*0Sstevel@tonic-gate  * Also, we are not using PC_GETXPARMS or PC_SETXPARMS so we can use
90*0Sstevel@tonic-gate  * the simple call to __priocntlset() rather than the varargs version.
91*0Sstevel@tonic-gate  */
92*0Sstevel@tonic-gate static long
93*0Sstevel@tonic-gate _private_priocntl(idtype_t idtype, id_t id, int cmd, caddr_t arg)
94*0Sstevel@tonic-gate {
95*0Sstevel@tonic-gate 	extern long _private__priocntlset(int, procset_t *, int, caddr_t, ...);
96*0Sstevel@tonic-gate 	procset_t procset;
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	setprocset(&procset, POP_AND, idtype, id, P_ALL, 0);
99*0Sstevel@tonic-gate 	return (_private__priocntlset(PC_VERSION, &procset, cmd, arg, 0));
100*0Sstevel@tonic-gate }
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate /*
103*0Sstevel@tonic-gate  * The following two functions are blatently stolen from
104*0Sstevel@tonic-gate  * sched_setscheduler() and sched_setparam() in librt.
105*0Sstevel@tonic-gate  * This would be a lot easier if librt were folded into libc.
106*0Sstevel@tonic-gate  */
107*0Sstevel@tonic-gate static int
108*0Sstevel@tonic-gate setscheduler(int policy, pri_t prio)
109*0Sstevel@tonic-gate {
110*0Sstevel@tonic-gate 	pcparms_t	pcparm;
111*0Sstevel@tonic-gate 	tsinfo_t	*tsi;
112*0Sstevel@tonic-gate 	tsparms_t	*tsp;
113*0Sstevel@tonic-gate 	int		scale;
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	switch (policy) {
116*0Sstevel@tonic-gate 	case SCHED_FIFO:
117*0Sstevel@tonic-gate 	case SCHED_RR:
118*0Sstevel@tonic-gate 		if (prio < rt_class.pcc_primin || prio > rt_class.pcc_primax) {
119*0Sstevel@tonic-gate 			errno = EINVAL;
120*0Sstevel@tonic-gate 			return (-1);
121*0Sstevel@tonic-gate 		}
122*0Sstevel@tonic-gate 		pcparm.pc_cid = rt_class.pcc_info.pc_cid;
123*0Sstevel@tonic-gate 		((rtparms_t *)pcparm.pc_clparms)->rt_pri = prio;
124*0Sstevel@tonic-gate 		((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs =
125*0Sstevel@tonic-gate 		    (policy == SCHED_RR ? RT_TQDEF : RT_TQINF);
126*0Sstevel@tonic-gate 		break;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	case SCHED_OTHER:
129*0Sstevel@tonic-gate 		pcparm.pc_cid = ts_class.pcc_info.pc_cid;
130*0Sstevel@tonic-gate 		tsi = (tsinfo_t *)ts_class.pcc_info.pc_clinfo;
131*0Sstevel@tonic-gate 		scale = tsi->ts_maxupri;
132*0Sstevel@tonic-gate 		tsp = (tsparms_t *)pcparm.pc_clparms;
133*0Sstevel@tonic-gate 		tsp->ts_uprilim = tsp->ts_upri = -(scale * prio) / 20;
134*0Sstevel@tonic-gate 		break;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	default:
137*0Sstevel@tonic-gate 		errno = EINVAL;
138*0Sstevel@tonic-gate 		return (-1);
139*0Sstevel@tonic-gate 	}
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	return (_private_priocntl(P_PID, P_MYID,
142*0Sstevel@tonic-gate 	    PC_SETPARMS, (caddr_t)&pcparm));
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate static int
146*0Sstevel@tonic-gate setparam(pcparms_t *pcparmp, pri_t prio)
147*0Sstevel@tonic-gate {
148*0Sstevel@tonic-gate 	tsparms_t	*tsp;
149*0Sstevel@tonic-gate 	tsinfo_t	*tsi;
150*0Sstevel@tonic-gate 	int		scale;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	if (pcparmp->pc_cid == rt_class.pcc_info.pc_cid) {
153*0Sstevel@tonic-gate 		/* SCHED_FIFO or SCHED_RR policy */
154*0Sstevel@tonic-gate 		if (prio < rt_class.pcc_primin || prio > rt_class.pcc_primax) {
155*0Sstevel@tonic-gate 			errno = EINVAL;
156*0Sstevel@tonic-gate 			return (-1);
157*0Sstevel@tonic-gate 		}
158*0Sstevel@tonic-gate 		((rtparms_t *)pcparmp->pc_clparms)->rt_tqnsecs = RT_NOCHANGE;
159*0Sstevel@tonic-gate 		((rtparms_t *)pcparmp->pc_clparms)->rt_pri = prio;
160*0Sstevel@tonic-gate 	} else if (pcparmp->pc_cid == ts_class.pcc_info.pc_cid) {
161*0Sstevel@tonic-gate 		/* SCHED_OTHER policy */
162*0Sstevel@tonic-gate 		tsi = (tsinfo_t *)ts_class.pcc_info.pc_clinfo;
163*0Sstevel@tonic-gate 		scale = tsi->ts_maxupri;
164*0Sstevel@tonic-gate 		tsp = (tsparms_t *)pcparmp->pc_clparms;
165*0Sstevel@tonic-gate 		tsp->ts_uprilim = tsp->ts_upri = -(scale * prio) / 20;
166*0Sstevel@tonic-gate 	} else {
167*0Sstevel@tonic-gate 		errno = EINVAL;
168*0Sstevel@tonic-gate 		return (-1);
169*0Sstevel@tonic-gate 	}
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	return (_private_priocntl(P_PID, P_MYID,
172*0Sstevel@tonic-gate 	    PC_SETPARMS, (caddr_t)pcparmp));
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate static void
176*0Sstevel@tonic-gate perform_flag_actions(spawn_attr_t *sap)
177*0Sstevel@tonic-gate {
178*0Sstevel@tonic-gate 	int sig;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) {
181*0Sstevel@tonic-gate 		(void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask, NULL);
182*0Sstevel@tonic-gate 	}
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) {
185*0Sstevel@tonic-gate 		struct sigaction sigdfl;
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 		(void) _private_memset(&sigdfl, 0, sizeof (sigdfl));
188*0Sstevel@tonic-gate 		for (sig = 1; sig < NSIG; sig++) {
189*0Sstevel@tonic-gate 			if (_private_sigismember(&sap->sa_sigdefault, sig))
190*0Sstevel@tonic-gate 				(void) __sigaction(sig, &sigdfl, NULL);
191*0Sstevel@tonic-gate 		}
192*0Sstevel@tonic-gate 	}
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) {
195*0Sstevel@tonic-gate 		if (_private_setgid(_private_getgid()) != 0 ||
196*0Sstevel@tonic-gate 		    _private_setuid(_private_getuid()) != 0)
197*0Sstevel@tonic-gate 			_private_exit(127);
198*0Sstevel@tonic-gate 	}
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) {
201*0Sstevel@tonic-gate 		if (_private_setpgid(0, sap->sa_pgroup) != 0)
202*0Sstevel@tonic-gate 			_private_exit(127);
203*0Sstevel@tonic-gate 	}
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) {
206*0Sstevel@tonic-gate 		if (setscheduler(sap->sa_schedpolicy, sap->sa_priority) != 0)
207*0Sstevel@tonic-gate 			_private_exit(127);
208*0Sstevel@tonic-gate 	} else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) {
209*0Sstevel@tonic-gate 		/*
210*0Sstevel@tonic-gate 		 * Get the process's current scheduling parameters,
211*0Sstevel@tonic-gate 		 * then modify to set the new priority.
212*0Sstevel@tonic-gate 		 */
213*0Sstevel@tonic-gate 		pcparms_t pcparm;
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 		pcparm.pc_cid = PC_CLNULL;
216*0Sstevel@tonic-gate 		if (_private_priocntl(P_PID, P_MYID,
217*0Sstevel@tonic-gate 		    PC_GETPARMS, (caddr_t)&pcparm) == -1)
218*0Sstevel@tonic-gate 			_private_exit(127);
219*0Sstevel@tonic-gate 		if (setparam(&pcparm, sap->sa_priority) != 0)
220*0Sstevel@tonic-gate 			_private_exit(127);
221*0Sstevel@tonic-gate 	}
222*0Sstevel@tonic-gate }
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate static void
225*0Sstevel@tonic-gate perform_file_actions(file_attr_t *fap)
226*0Sstevel@tonic-gate {
227*0Sstevel@tonic-gate 	file_attr_t *froot = fap;
228*0Sstevel@tonic-gate 	int fd;
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	do {
231*0Sstevel@tonic-gate 		switch (fap->fa_type) {
232*0Sstevel@tonic-gate 		case FA_OPEN:
233*0Sstevel@tonic-gate 			fd = __open(fap->fa_path, fap->fa_oflag, fap->fa_mode);
234*0Sstevel@tonic-gate 			if (fd < 0)
235*0Sstevel@tonic-gate 				_private_exit(127);
236*0Sstevel@tonic-gate 			if (fd != fap->fa_filedes) {
237*0Sstevel@tonic-gate 				if (_private_fcntl(fd, F_DUP2FD,
238*0Sstevel@tonic-gate 				    fap->fa_filedes) < 0)
239*0Sstevel@tonic-gate 					_private_exit(127);
240*0Sstevel@tonic-gate 				(void) _private_close(fd);
241*0Sstevel@tonic-gate 			}
242*0Sstevel@tonic-gate 			break;
243*0Sstevel@tonic-gate 		case FA_CLOSE:
244*0Sstevel@tonic-gate 			if (_private_close(fap->fa_filedes) == -1)
245*0Sstevel@tonic-gate 				_private_exit(127);
246*0Sstevel@tonic-gate 			break;
247*0Sstevel@tonic-gate 		case FA_DUP2:
248*0Sstevel@tonic-gate 			fd = _private_fcntl(fap->fa_filedes, F_DUP2FD,
249*0Sstevel@tonic-gate 				fap->fa_newfiledes);
250*0Sstevel@tonic-gate 			if (fd < 0)
251*0Sstevel@tonic-gate 				_private_exit(127);
252*0Sstevel@tonic-gate 			break;
253*0Sstevel@tonic-gate 		}
254*0Sstevel@tonic-gate 	} while ((fap = fap->fa_next) != froot);
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate /*
258*0Sstevel@tonic-gate  * For MT safety, do not invoke the dynamic linker after calling vfork().
259*0Sstevel@tonic-gate  * If some other thread was in the dynamic linker when this thread's parent
260*0Sstevel@tonic-gate  * called vfork() then the dynamic linker's lock would still be held here
261*0Sstevel@tonic-gate  * (with a defunct owner) and we would deadlock ourself if we invoked it.
262*0Sstevel@tonic-gate  *
263*0Sstevel@tonic-gate  * Therefore, all of the functions we call here after returning from
264*0Sstevel@tonic-gate  * _vfork() in the child are not and must never be exported from libc
265*0Sstevel@tonic-gate  * as global symbols.  To do so would risk invoking the dynamic linker.
266*0Sstevel@tonic-gate  */
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate #pragma weak posix_spawn = _posix_spawn
269*0Sstevel@tonic-gate int
270*0Sstevel@tonic-gate _posix_spawn(
271*0Sstevel@tonic-gate 	pid_t *pidp,
272*0Sstevel@tonic-gate 	const char *path,
273*0Sstevel@tonic-gate 	const posix_spawn_file_actions_t *file_actions,
274*0Sstevel@tonic-gate 	const posix_spawnattr_t *attrp,
275*0Sstevel@tonic-gate 	char *const argv[],
276*0Sstevel@tonic-gate 	char *const envp[])
277*0Sstevel@tonic-gate {
278*0Sstevel@tonic-gate 	spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
279*0Sstevel@tonic-gate 	file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
280*0Sstevel@tonic-gate 	pid_t pid;
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	if (attrp != NULL && sap == NULL)
283*0Sstevel@tonic-gate 		return (EINVAL);
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	switch (pid = _vfork()) {
286*0Sstevel@tonic-gate 	case 0:			/* child */
287*0Sstevel@tonic-gate 		break;
288*0Sstevel@tonic-gate 	case -1:		/* parent, failure */
289*0Sstevel@tonic-gate 		return (errno);
290*0Sstevel@tonic-gate 	default:		/* parent, success */
291*0Sstevel@tonic-gate 		if (pidp != NULL)
292*0Sstevel@tonic-gate 			*pidp = pid;
293*0Sstevel@tonic-gate 		return (0);
294*0Sstevel@tonic-gate 	}
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	if (sap != NULL)
297*0Sstevel@tonic-gate 		perform_flag_actions(sap);
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	if (fap != NULL)
300*0Sstevel@tonic-gate 		perform_file_actions(fap);
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	(void) _private_execve(path, argv, envp);
303*0Sstevel@tonic-gate 	_private_exit(127);
304*0Sstevel@tonic-gate 	return (0);	/* not reached */
305*0Sstevel@tonic-gate }
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate /*
308*0Sstevel@tonic-gate  * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c).
309*0Sstevel@tonic-gate  */
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate extern int __xpg4;	/* defined in xpg4.c; 0 if not xpg4-compiled program */
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate static const char *
314*0Sstevel@tonic-gate execat(const char *s1, const char *s2, char *si)
315*0Sstevel@tonic-gate {
316*0Sstevel@tonic-gate 	int cnt = PATH_MAX + 1;
317*0Sstevel@tonic-gate 	char *s;
318*0Sstevel@tonic-gate 	char c;
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	for (s = si; (c = *s1) != '\0' && c != ':'; s1++) {
321*0Sstevel@tonic-gate 		if (cnt > 0) {
322*0Sstevel@tonic-gate 			*s++ = c;
323*0Sstevel@tonic-gate 			cnt--;
324*0Sstevel@tonic-gate 		}
325*0Sstevel@tonic-gate 	}
326*0Sstevel@tonic-gate 	if (si != s && cnt > 0) {
327*0Sstevel@tonic-gate 		*s++ = '/';
328*0Sstevel@tonic-gate 		cnt--;
329*0Sstevel@tonic-gate 	}
330*0Sstevel@tonic-gate 	for (; (c = *s2) != '\0' && cnt > 0; s2++) {
331*0Sstevel@tonic-gate 		*s++ = c;
332*0Sstevel@tonic-gate 		cnt--;
333*0Sstevel@tonic-gate 	}
334*0Sstevel@tonic-gate 	*s = '\0';
335*0Sstevel@tonic-gate 	return (*s1? ++s1: NULL);
336*0Sstevel@tonic-gate }
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate #pragma weak posix_spawnp = _posix_spawnp
339*0Sstevel@tonic-gate /* ARGSUSED */
340*0Sstevel@tonic-gate int
341*0Sstevel@tonic-gate _posix_spawnp(
342*0Sstevel@tonic-gate 	pid_t *pidp,
343*0Sstevel@tonic-gate 	const char *file,
344*0Sstevel@tonic-gate 	const posix_spawn_file_actions_t *file_actions,
345*0Sstevel@tonic-gate 	const posix_spawnattr_t *attrp,
346*0Sstevel@tonic-gate 	char *const argv[],
347*0Sstevel@tonic-gate 	char *const envp[])
348*0Sstevel@tonic-gate {
349*0Sstevel@tonic-gate 	spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
350*0Sstevel@tonic-gate 	file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
351*0Sstevel@tonic-gate 	const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : "";
352*0Sstevel@tonic-gate 	int xpg4 = __xpg4;
353*0Sstevel@tonic-gate 	char path[PATH_MAX+4];
354*0Sstevel@tonic-gate 	const char *cp;
355*0Sstevel@tonic-gate 	pid_t pid;
356*0Sstevel@tonic-gate 	char **newargs;
357*0Sstevel@tonic-gate 	int argc;
358*0Sstevel@tonic-gate 	int i;
359*0Sstevel@tonic-gate 	static const char *sun_path = "/bin/sh";
360*0Sstevel@tonic-gate 	static const char *xpg4_path = "/usr/xpg4/bin/sh";
361*0Sstevel@tonic-gate 	static const char *shell = "sh";
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	if (attrp != NULL && sap == NULL)
364*0Sstevel@tonic-gate 		return (EINVAL);
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	/*
367*0Sstevel@tonic-gate 	 * We may need to invoke the shell with a slightly modified
368*0Sstevel@tonic-gate 	 * argv[] array.  To do this we need to preallocate the array.
369*0Sstevel@tonic-gate 	 * We must call alloca() before calling vfork() because doing
370*0Sstevel@tonic-gate 	 * it after vfork() (in the child) would corrupt the parent.
371*0Sstevel@tonic-gate 	 */
372*0Sstevel@tonic-gate 	for (argc = 0; argv[argc] != NULL; argc++)
373*0Sstevel@tonic-gate 		continue;
374*0Sstevel@tonic-gate 	newargs = alloca((argc + 2) * sizeof (char *));
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	switch (pid = _vfork()) {
377*0Sstevel@tonic-gate 	case 0:			/* child */
378*0Sstevel@tonic-gate 		break;
379*0Sstevel@tonic-gate 	case -1:		/* parent, failure */
380*0Sstevel@tonic-gate 		return (errno);
381*0Sstevel@tonic-gate 	default:		/* parent, success */
382*0Sstevel@tonic-gate 		if (pidp != NULL)
383*0Sstevel@tonic-gate 			*pidp = pid;
384*0Sstevel@tonic-gate 		return (0);
385*0Sstevel@tonic-gate 	}
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	if (*file == '\0')
388*0Sstevel@tonic-gate 		_private_exit(127);
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	if (sap != NULL)
391*0Sstevel@tonic-gate 		perform_flag_actions(sap);
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	if (fap != NULL)
394*0Sstevel@tonic-gate 		perform_file_actions(fap);
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	if (pathstr == NULL) {
397*0Sstevel@tonic-gate 		/*
398*0Sstevel@tonic-gate 		 * XPG4:  pathstr is equivalent to _CS_PATH, except that
399*0Sstevel@tonic-gate 		 * :/usr/sbin is appended when root, and pathstr must end
400*0Sstevel@tonic-gate 		 * with a colon when not root.  Keep these paths in sync
401*0Sstevel@tonic-gate 		 * with _CS_PATH in confstr.c.  Note that pathstr must end
402*0Sstevel@tonic-gate 		 * with a colon when not root so that when file doesn't
403*0Sstevel@tonic-gate 		 * contain '/', the last call to execat() will result in an
404*0Sstevel@tonic-gate 		 * attempt to execv file from the current directory.
405*0Sstevel@tonic-gate 		 */
406*0Sstevel@tonic-gate 		if (_private_geteuid() == 0 || _private_getuid() == 0) {
407*0Sstevel@tonic-gate 			if (!xpg4)
408*0Sstevel@tonic-gate 				pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin";
409*0Sstevel@tonic-gate 			else
410*0Sstevel@tonic-gate 				pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
411*0Sstevel@tonic-gate 				    "/usr/bin:/opt/SUNWspro/bin:/usr/sbin";
412*0Sstevel@tonic-gate 		} else {
413*0Sstevel@tonic-gate 			if (!xpg4)
414*0Sstevel@tonic-gate 				pathstr = "/usr/ccs/bin:/usr/bin:";
415*0Sstevel@tonic-gate 			else
416*0Sstevel@tonic-gate 				pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
417*0Sstevel@tonic-gate 				    "/usr/bin:/opt/SUNWspro/bin:";
418*0Sstevel@tonic-gate 		}
419*0Sstevel@tonic-gate 	}
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	cp = pathstr;
422*0Sstevel@tonic-gate 	do {
423*0Sstevel@tonic-gate 		cp = execat(cp, file, path);
424*0Sstevel@tonic-gate 		/*
425*0Sstevel@tonic-gate 		 * 4025035 and 4038378
426*0Sstevel@tonic-gate 		 * if a filename begins with a "-" prepend "./" so that
427*0Sstevel@tonic-gate 		 * the shell can't interpret it as an option
428*0Sstevel@tonic-gate 		 */
429*0Sstevel@tonic-gate 		if (*path == '-') {
430*0Sstevel@tonic-gate 			char *s;
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 			for (s = path; *s != '\0'; s++)
433*0Sstevel@tonic-gate 				continue;
434*0Sstevel@tonic-gate 			for (; s >= path; s--)
435*0Sstevel@tonic-gate 				*(s + 2) = *s;
436*0Sstevel@tonic-gate 			path[0] = '.';
437*0Sstevel@tonic-gate 			path[1] = '/';
438*0Sstevel@tonic-gate 		}
439*0Sstevel@tonic-gate 		(void) _private_execve(path, argv, envp);
440*0Sstevel@tonic-gate 		if (errno == ENOEXEC) {
441*0Sstevel@tonic-gate 			newargs[0] = (char *)shell;
442*0Sstevel@tonic-gate 			newargs[1] = path;
443*0Sstevel@tonic-gate 			for (i = 1; i <= argc; i++)
444*0Sstevel@tonic-gate 				newargs[i + 1] = argv[i];
445*0Sstevel@tonic-gate 			(void) _private_execve(xpg4? xpg4_path : sun_path,
446*0Sstevel@tonic-gate 				newargs, envp);
447*0Sstevel@tonic-gate 			_private_exit(127);
448*0Sstevel@tonic-gate 		}
449*0Sstevel@tonic-gate 	} while (cp);
450*0Sstevel@tonic-gate 	_private_exit(127);
451*0Sstevel@tonic-gate 	return (0);	/* not reached */
452*0Sstevel@tonic-gate }
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate #pragma weak posix_spawn_file_actions_init = \
455*0Sstevel@tonic-gate 		_posix_spawn_file_actions_init
456*0Sstevel@tonic-gate int
457*0Sstevel@tonic-gate _posix_spawn_file_actions_init(
458*0Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions)
459*0Sstevel@tonic-gate {
460*0Sstevel@tonic-gate 	file_actions->__file_attrp = NULL;
461*0Sstevel@tonic-gate 	return (0);
462*0Sstevel@tonic-gate }
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate #pragma weak posix_spawn_file_actions_destroy = \
465*0Sstevel@tonic-gate 		_posix_spawn_file_actions_destroy
466*0Sstevel@tonic-gate int
467*0Sstevel@tonic-gate _posix_spawn_file_actions_destroy(
468*0Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions)
469*0Sstevel@tonic-gate {
470*0Sstevel@tonic-gate 	file_attr_t *froot = file_actions->__file_attrp;
471*0Sstevel@tonic-gate 	file_attr_t *fap;
472*0Sstevel@tonic-gate 	file_attr_t *next;
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	if ((fap = froot) != NULL) {
475*0Sstevel@tonic-gate 		do {
476*0Sstevel@tonic-gate 			next = fap->fa_next;
477*0Sstevel@tonic-gate 			if (fap-> fa_type == FA_OPEN)
478*0Sstevel@tonic-gate 				lfree(fap->fa_path, fap->fa_pathsize);
479*0Sstevel@tonic-gate 			lfree(fap, sizeof (*fap));
480*0Sstevel@tonic-gate 		} while ((fap = next) != froot);
481*0Sstevel@tonic-gate 	}
482*0Sstevel@tonic-gate 	file_actions->__file_attrp = NULL;
483*0Sstevel@tonic-gate 	return (0);
484*0Sstevel@tonic-gate }
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate static void
487*0Sstevel@tonic-gate add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap)
488*0Sstevel@tonic-gate {
489*0Sstevel@tonic-gate 	file_attr_t *froot = file_actions->__file_attrp;
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	if (froot == NULL) {
492*0Sstevel@tonic-gate 		fap->fa_next = fap->fa_prev = fap;
493*0Sstevel@tonic-gate 		file_actions->__file_attrp = fap;
494*0Sstevel@tonic-gate 	} else {
495*0Sstevel@tonic-gate 		fap->fa_next = froot;
496*0Sstevel@tonic-gate 		fap->fa_prev = froot->fa_prev;
497*0Sstevel@tonic-gate 		froot->fa_prev->fa_next = fap;
498*0Sstevel@tonic-gate 		froot->fa_prev = fap;
499*0Sstevel@tonic-gate 	}
500*0Sstevel@tonic-gate }
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate #pragma weak posix_spawn_file_actions_addopen = \
503*0Sstevel@tonic-gate 		_posix_spawn_file_actions_addopen
504*0Sstevel@tonic-gate int
505*0Sstevel@tonic-gate _posix_spawn_file_actions_addopen(
506*0Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
507*0Sstevel@tonic-gate 	int filedes,
508*0Sstevel@tonic-gate 	const char *path,
509*0Sstevel@tonic-gate 	int oflag,
510*0Sstevel@tonic-gate 	mode_t mode)
511*0Sstevel@tonic-gate {
512*0Sstevel@tonic-gate 	file_attr_t *fap;
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	if (filedes < 0)
515*0Sstevel@tonic-gate 		return (EBADF);
516*0Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
517*0Sstevel@tonic-gate 		return (ENOMEM);
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	fap->fa_pathsize = strlen(path) + 1;
520*0Sstevel@tonic-gate 	if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) {
521*0Sstevel@tonic-gate 		lfree(fap, sizeof (*fap));
522*0Sstevel@tonic-gate 		return (ENOMEM);
523*0Sstevel@tonic-gate 	}
524*0Sstevel@tonic-gate 	(void) strcpy(fap->fa_path, path);
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 	fap->fa_type = FA_OPEN;
527*0Sstevel@tonic-gate 	fap->fa_oflag = oflag;
528*0Sstevel@tonic-gate 	fap->fa_mode = mode;
529*0Sstevel@tonic-gate 	fap->fa_filedes = filedes;
530*0Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 	return (0);
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate #pragma weak posix_spawn_file_actions_addclose = \
536*0Sstevel@tonic-gate 		_posix_spawn_file_actions_addclose
537*0Sstevel@tonic-gate int
538*0Sstevel@tonic-gate _posix_spawn_file_actions_addclose(
539*0Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
540*0Sstevel@tonic-gate 	int filedes)
541*0Sstevel@tonic-gate {
542*0Sstevel@tonic-gate 	file_attr_t *fap;
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	if (filedes < 0)
545*0Sstevel@tonic-gate 		return (EBADF);
546*0Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
547*0Sstevel@tonic-gate 		return (ENOMEM);
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	fap->fa_type = FA_CLOSE;
550*0Sstevel@tonic-gate 	fap->fa_filedes = filedes;
551*0Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 	return (0);
554*0Sstevel@tonic-gate }
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate #pragma weak posix_spawn_file_actions_adddup2 = \
557*0Sstevel@tonic-gate 		_posix_spawn_file_actions_adddup2
558*0Sstevel@tonic-gate int
559*0Sstevel@tonic-gate _posix_spawn_file_actions_adddup2(
560*0Sstevel@tonic-gate 	posix_spawn_file_actions_t *file_actions,
561*0Sstevel@tonic-gate 	int filedes,
562*0Sstevel@tonic-gate 	int newfiledes)
563*0Sstevel@tonic-gate {
564*0Sstevel@tonic-gate 	file_attr_t *fap;
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	if (filedes < 0 || newfiledes < 0)
567*0Sstevel@tonic-gate 		return (EBADF);
568*0Sstevel@tonic-gate 	if ((fap = lmalloc(sizeof (*fap))) == NULL)
569*0Sstevel@tonic-gate 		return (ENOMEM);
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	fap->fa_type = FA_DUP2;
572*0Sstevel@tonic-gate 	fap->fa_filedes = filedes;
573*0Sstevel@tonic-gate 	fap->fa_newfiledes = newfiledes;
574*0Sstevel@tonic-gate 	add_file_attr(file_actions, fap);
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 	return (0);
577*0Sstevel@tonic-gate }
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate #pragma weak posix_spawnattr_init = \
580*0Sstevel@tonic-gate 		_posix_spawnattr_init
581*0Sstevel@tonic-gate int
582*0Sstevel@tonic-gate _posix_spawnattr_init(
583*0Sstevel@tonic-gate 	posix_spawnattr_t *attr)
584*0Sstevel@tonic-gate {
585*0Sstevel@tonic-gate 	spawn_attr_t *sap;
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	if ((sap = lmalloc(sizeof (*sap))) == NULL)
588*0Sstevel@tonic-gate 		return (ENOMEM);
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 	/*
591*0Sstevel@tonic-gate 	 * Add default stuff here?
592*0Sstevel@tonic-gate 	 */
593*0Sstevel@tonic-gate 	attr->__spawn_attrp = sap;
594*0Sstevel@tonic-gate 	return (0);
595*0Sstevel@tonic-gate }
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate #pragma weak posix_spawnattr_destroy = \
598*0Sstevel@tonic-gate 		_posix_spawnattr_destroy
599*0Sstevel@tonic-gate int
600*0Sstevel@tonic-gate _posix_spawnattr_destroy(
601*0Sstevel@tonic-gate 	posix_spawnattr_t *attr)
602*0Sstevel@tonic-gate {
603*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 	if (sap == NULL)
606*0Sstevel@tonic-gate 		return (EINVAL);
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	/*
609*0Sstevel@tonic-gate 	 * deallocate stuff here?
610*0Sstevel@tonic-gate 	 */
611*0Sstevel@tonic-gate 	lfree(sap, sizeof (*sap));
612*0Sstevel@tonic-gate 	attr->__spawn_attrp = NULL;
613*0Sstevel@tonic-gate 	return (0);
614*0Sstevel@tonic-gate }
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate #pragma weak posix_spawnattr_setflags = \
617*0Sstevel@tonic-gate 		_posix_spawnattr_setflags
618*0Sstevel@tonic-gate int
619*0Sstevel@tonic-gate _posix_spawnattr_setflags(
620*0Sstevel@tonic-gate 	posix_spawnattr_t *attr,
621*0Sstevel@tonic-gate 	short flags)
622*0Sstevel@tonic-gate {
623*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	if (sap == NULL ||
626*0Sstevel@tonic-gate 	    (flags & ~ALL_POSIX_SPAWN_FLAGS))
627*0Sstevel@tonic-gate 		return (EINVAL);
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	if (flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER)) {
630*0Sstevel@tonic-gate 		/*
631*0Sstevel@tonic-gate 		 * Populate ts_class and rt_class.
632*0Sstevel@tonic-gate 		 * We will need them in the child of vfork().
633*0Sstevel@tonic-gate 		 */
634*0Sstevel@tonic-gate 		(void) _map_rtpri_to_gp(0);
635*0Sstevel@tonic-gate 	}
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	sap->sa_psflags = flags;
638*0Sstevel@tonic-gate 	return (0);
639*0Sstevel@tonic-gate }
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate #pragma weak posix_spawnattr_getflags = \
642*0Sstevel@tonic-gate 		_posix_spawnattr_getflags
643*0Sstevel@tonic-gate int
644*0Sstevel@tonic-gate _posix_spawnattr_getflags(
645*0Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
646*0Sstevel@tonic-gate 	short *flags)
647*0Sstevel@tonic-gate {
648*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 	if (sap == NULL)
651*0Sstevel@tonic-gate 		return (EINVAL);
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	*flags = sap->sa_psflags;
654*0Sstevel@tonic-gate 	return (0);
655*0Sstevel@tonic-gate }
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate #pragma weak posix_spawnattr_setpgroup = \
658*0Sstevel@tonic-gate 		_posix_spawnattr_setpgroup
659*0Sstevel@tonic-gate int
660*0Sstevel@tonic-gate _posix_spawnattr_setpgroup(
661*0Sstevel@tonic-gate 	posix_spawnattr_t *attr,
662*0Sstevel@tonic-gate 	pid_t pgroup)
663*0Sstevel@tonic-gate {
664*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	if (sap == NULL)
667*0Sstevel@tonic-gate 		return (EINVAL);
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	sap->sa_pgroup = pgroup;
670*0Sstevel@tonic-gate 	return (0);
671*0Sstevel@tonic-gate }
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate #pragma weak posix_spawnattr_getpgroup = \
674*0Sstevel@tonic-gate 		_posix_spawnattr_getpgroup
675*0Sstevel@tonic-gate int
676*0Sstevel@tonic-gate _posix_spawnattr_getpgroup(
677*0Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
678*0Sstevel@tonic-gate 	pid_t *pgroup)
679*0Sstevel@tonic-gate {
680*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 	if (sap == NULL)
683*0Sstevel@tonic-gate 		return (EINVAL);
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	*pgroup = sap->sa_pgroup;
686*0Sstevel@tonic-gate 	return (0);
687*0Sstevel@tonic-gate }
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate #pragma weak posix_spawnattr_setschedparam = \
690*0Sstevel@tonic-gate 		_posix_spawnattr_setschedparam
691*0Sstevel@tonic-gate int
692*0Sstevel@tonic-gate _posix_spawnattr_setschedparam(
693*0Sstevel@tonic-gate 	posix_spawnattr_t *attr,
694*0Sstevel@tonic-gate 	const struct sched_param *schedparam)
695*0Sstevel@tonic-gate {
696*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	if (sap == NULL)
699*0Sstevel@tonic-gate 		return (EINVAL);
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate 	/*
702*0Sstevel@tonic-gate 	 * Check validity?
703*0Sstevel@tonic-gate 	 */
704*0Sstevel@tonic-gate 	sap->sa_priority = schedparam->sched_priority;
705*0Sstevel@tonic-gate 	return (0);
706*0Sstevel@tonic-gate }
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate #pragma weak posix_spawnattr_getschedparam = \
709*0Sstevel@tonic-gate 		_posix_spawnattr_getschedparam
710*0Sstevel@tonic-gate int
711*0Sstevel@tonic-gate _posix_spawnattr_getschedparam(
712*0Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
713*0Sstevel@tonic-gate 	struct sched_param *schedparam)
714*0Sstevel@tonic-gate {
715*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	if (sap == NULL)
718*0Sstevel@tonic-gate 		return (EINVAL);
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate 	schedparam->sched_priority = sap->sa_priority;
721*0Sstevel@tonic-gate 	return (0);
722*0Sstevel@tonic-gate }
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate #pragma weak posix_spawnattr_setschedpolicy = \
725*0Sstevel@tonic-gate 		_posix_spawnattr_setschedpolicy
726*0Sstevel@tonic-gate int
727*0Sstevel@tonic-gate _posix_spawnattr_setschedpolicy(
728*0Sstevel@tonic-gate 	posix_spawnattr_t *attr,
729*0Sstevel@tonic-gate 	int schedpolicy)
730*0Sstevel@tonic-gate {
731*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
732*0Sstevel@tonic-gate 
733*0Sstevel@tonic-gate 	if (sap == NULL)
734*0Sstevel@tonic-gate 		return (EINVAL);
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	switch (schedpolicy) {
737*0Sstevel@tonic-gate 	case SCHED_OTHER:
738*0Sstevel@tonic-gate 	case SCHED_FIFO:
739*0Sstevel@tonic-gate 	case SCHED_RR:
740*0Sstevel@tonic-gate 		break;
741*0Sstevel@tonic-gate 	default:
742*0Sstevel@tonic-gate 		return (EINVAL);
743*0Sstevel@tonic-gate 	}
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	sap->sa_schedpolicy = schedpolicy;
746*0Sstevel@tonic-gate 	return (0);
747*0Sstevel@tonic-gate }
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate #pragma weak posix_spawnattr_getschedpolicy = \
750*0Sstevel@tonic-gate 		_posix_spawnattr_getschedpolicy
751*0Sstevel@tonic-gate int
752*0Sstevel@tonic-gate _posix_spawnattr_getschedpolicy(
753*0Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
754*0Sstevel@tonic-gate 	int *schedpolicy)
755*0Sstevel@tonic-gate {
756*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 	if (sap == NULL)
759*0Sstevel@tonic-gate 		return (EINVAL);
760*0Sstevel@tonic-gate 
761*0Sstevel@tonic-gate 	*schedpolicy = sap->sa_schedpolicy;
762*0Sstevel@tonic-gate 	return (0);
763*0Sstevel@tonic-gate }
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate #pragma weak posix_spawnattr_setsigdefault = \
766*0Sstevel@tonic-gate 		_posix_spawnattr_setsigdefault
767*0Sstevel@tonic-gate int
768*0Sstevel@tonic-gate _posix_spawnattr_setsigdefault(
769*0Sstevel@tonic-gate 	posix_spawnattr_t *attr,
770*0Sstevel@tonic-gate 	const sigset_t *sigdefault)
771*0Sstevel@tonic-gate {
772*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 	if (sap == NULL)
775*0Sstevel@tonic-gate 		return (EINVAL);
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 	sap->sa_sigdefault = *sigdefault;
778*0Sstevel@tonic-gate 	return (0);
779*0Sstevel@tonic-gate }
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate #pragma weak posix_spawnattr_getsigdefault = \
782*0Sstevel@tonic-gate 		_posix_spawnattr_getsigdefault
783*0Sstevel@tonic-gate int
784*0Sstevel@tonic-gate _posix_spawnattr_getsigdefault(
785*0Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
786*0Sstevel@tonic-gate 	sigset_t *sigdefault)
787*0Sstevel@tonic-gate {
788*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
789*0Sstevel@tonic-gate 
790*0Sstevel@tonic-gate 	if (sap == NULL)
791*0Sstevel@tonic-gate 		return (EINVAL);
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	*sigdefault = sap->sa_sigdefault;
794*0Sstevel@tonic-gate 	return (0);
795*0Sstevel@tonic-gate }
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate #pragma weak posix_spawnattr_setsigmask = \
798*0Sstevel@tonic-gate 		_posix_spawnattr_setsigmask
799*0Sstevel@tonic-gate int
800*0Sstevel@tonic-gate _posix_spawnattr_setsigmask(
801*0Sstevel@tonic-gate 	posix_spawnattr_t *attr,
802*0Sstevel@tonic-gate 	const sigset_t *sigmask)
803*0Sstevel@tonic-gate {
804*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	if (sap == NULL)
807*0Sstevel@tonic-gate 		return (EINVAL);
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 	sap->sa_sigmask = *sigmask;
810*0Sstevel@tonic-gate 	return (0);
811*0Sstevel@tonic-gate }
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate #pragma weak posix_spawnattr_getsigmask = \
814*0Sstevel@tonic-gate 		_posix_spawnattr_getsigmask
815*0Sstevel@tonic-gate int
816*0Sstevel@tonic-gate _posix_spawnattr_getsigmask(
817*0Sstevel@tonic-gate 	const posix_spawnattr_t *attr,
818*0Sstevel@tonic-gate 	sigset_t *sigmask)
819*0Sstevel@tonic-gate {
820*0Sstevel@tonic-gate 	spawn_attr_t *sap = attr->__spawn_attrp;
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 	if (sap == NULL)
823*0Sstevel@tonic-gate 		return (EINVAL);
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	*sigmask = sap->sa_sigmask;
826*0Sstevel@tonic-gate 	return (0);
827*0Sstevel@tonic-gate }
828