1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "lint.h"
28 #include "thr_uberdata.h"
29 #include <sys/libc_kernel.h>
30 #include <sys/procset.h>
31 #include <sys/fork.h>
32 #include <dirent.h>
33 #include <alloca.h>
34 #include <spawn.h>
35
36 #define ALL_POSIX_SPAWN_FLAGS \
37 (POSIX_SPAWN_RESETIDS | \
38 POSIX_SPAWN_SETPGROUP | \
39 POSIX_SPAWN_SETSIGDEF | \
40 POSIX_SPAWN_SETSIGMASK | \
41 POSIX_SPAWN_SETSCHEDPARAM | \
42 POSIX_SPAWN_SETSCHEDULER | \
43 POSIX_SPAWN_SETSIGIGN_NP | \
44 POSIX_SPAWN_NOSIGCHLD_NP | \
45 POSIX_SPAWN_WAITPID_NP | \
46 POSIX_SPAWN_NOEXECERR_NP)
47
48 typedef struct {
49 int sa_psflags; /* POSIX_SPAWN_* flags */
50 int sa_priority;
51 int sa_schedpolicy;
52 pid_t sa_pgroup;
53 sigset_t sa_sigdefault;
54 sigset_t sa_sigignore;
55 sigset_t sa_sigmask;
56 } spawn_attr_t;
57
58 typedef struct file_attr {
59 struct file_attr *fa_next; /* circular list of file actions */
60 struct file_attr *fa_prev;
61 enum {FA_OPEN, FA_CLOSE, FA_DUP2, FA_CLOSEFROM} fa_type;
62 int fa_need_dirbuf; /* only consulted in the head action */
63 char *fa_path; /* copied pathname for open() */
64 uint_t fa_pathsize; /* size of fa_path[] array */
65 int fa_oflag; /* oflag for open() */
66 mode_t fa_mode; /* mode for open() */
67 int fa_filedes; /* file descriptor for open()/close() */
68 int fa_newfiledes; /* new file descriptor for dup2() */
69 } file_attr_t;
70
71 #if defined(_LP64)
72 #define __open64 __open
73 #define getdents64 getdents
74 #define dirent64_t dirent_t
75 #else
76 extern int getdents64(int, dirent64_t *, size_t);
77 #endif
78
79 /*
80 * Support function:
81 * Close all open file descriptors greater than or equal to lowfd.
82 * This is executed in the child of vfork(), so we must not call
83 * opendir() / readdir() because that would alter the parent's
84 * address space. We use the low-level getdents64() system call.
85 * Return non-zero on error.
86 */
87 static int
spawn_closefrom(int lowfd,void * buf)88 spawn_closefrom(int lowfd, void *buf)
89 {
90 int procfd;
91 int fd;
92 int buflen;
93 dirent64_t *dp;
94 dirent64_t *dpend;
95
96 if (lowfd < 0)
97 lowfd = 0;
98
99 /*
100 * Close lowfd right away as a hedge against failing
101 * to open the /proc file descriptor directory due
102 * all file descriptors being currently used up.
103 */
104 (void) __close(lowfd++);
105
106 if ((procfd = __open64("/proc/self/fd", O_RDONLY, 0)) < 0) {
107 /*
108 * We could not open the /proc file descriptor directory.
109 * Just fail and be done with it.
110 */
111 return (-1);
112 }
113
114 for (;;) {
115 /*
116 * Collect a bunch of open file descriptors and close them.
117 * Repeat until the directory is exhausted.
118 */
119 dp = (dirent64_t *)buf;
120 if ((buflen = getdents64(procfd, dp, DIRBUF)) <= 0) {
121 (void) __close(procfd);
122 break;
123 }
124 dpend = (dirent64_t *)((uintptr_t)buf + buflen);
125 do {
126 /* skip '.', '..' and procfd */
127 if (dp->d_name[0] != '.' &&
128 (fd = atoi(dp->d_name)) != procfd &&
129 fd >= lowfd)
130 (void) __close(fd);
131 dp = (dirent64_t *)((uintptr_t)dp + dp->d_reclen);
132 } while (dp < dpend);
133 }
134
135 return (0);
136 }
137
138 static int
perform_flag_actions(spawn_attr_t * sap)139 perform_flag_actions(spawn_attr_t *sap)
140 {
141 int sig;
142 struct sigaction action;
143
144 if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) {
145 (void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask);
146 }
147
148 if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) {
149 (void) memset(&action, 0, sizeof (action));
150 action.sa_handler = SIG_IGN;
151 for (sig = 1; sig < NSIG; sig++) {
152 if (sigismember(&sap->sa_sigignore, sig))
153 (void) __sigaction(sig, &action, NULL);
154 }
155 }
156
157 if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) {
158 (void) memset(&action, 0, sizeof (action));
159 action.sa_handler = SIG_DFL;
160 for (sig = 1; sig < NSIG; sig++) {
161 if (sigismember(&sap->sa_sigdefault, sig))
162 (void) __sigaction(sig, &action, NULL);
163 }
164 }
165
166 if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) {
167 if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
168 return (errno);
169 }
170
171 if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) {
172 if (setpgid(0, sap->sa_pgroup) != 0)
173 return (errno);
174 }
175
176 if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) {
177 if (setparam(P_LWPID, P_MYID,
178 sap->sa_schedpolicy, sap->sa_priority) == -1)
179 return (errno);
180 } else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) {
181 if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1)
182 return (errno);
183 }
184
185 return (0);
186 }
187
188 static int
perform_file_actions(file_attr_t * fap,void * dirbuf)189 perform_file_actions(file_attr_t *fap, void *dirbuf)
190 {
191 file_attr_t *froot = fap;
192 int fd;
193
194 do {
195 switch (fap->fa_type) {
196 case FA_OPEN:
197 fd = __open(fap->fa_path, fap->fa_oflag, fap->fa_mode);
198 if (fd < 0)
199 return (errno);
200 if (fd != fap->fa_filedes) {
201 if (__fcntl(fd, F_DUP2FD, fap->fa_filedes) < 0)
202 return (errno);
203 (void) __close(fd);
204 }
205 break;
206 case FA_CLOSE:
207 if (__close(fap->fa_filedes) == -1 &&
208 errno != EBADF) /* already closed, no error */
209 return (errno);
210 break;
211 case FA_DUP2:
212 fd = __fcntl(fap->fa_filedes, F_DUP2FD,
213 fap->fa_newfiledes);
214 if (fd < 0)
215 return (errno);
216 break;
217 case FA_CLOSEFROM:
218 if (spawn_closefrom(fap->fa_filedes, dirbuf))
219 return (errno);
220 break;
221 }
222 } while ((fap = fap->fa_next) != froot);
223
224 return (0);
225 }
226
227 static int
forkflags(spawn_attr_t * sap)228 forkflags(spawn_attr_t *sap)
229 {
230 int flags = 0;
231
232 if (sap != NULL) {
233 if (sap->sa_psflags & POSIX_SPAWN_NOSIGCHLD_NP)
234 flags |= FORK_NOSIGCHLD;
235 if (sap->sa_psflags & POSIX_SPAWN_WAITPID_NP)
236 flags |= FORK_WAITPID;
237 }
238
239 return (flags);
240 }
241
242 /*
243 * set_error() / get_error() are used to guarantee that the local variable
244 * 'error' is set correctly in memory on return from vfork() in the parent.
245 */
246
247 static int
set_error(int * errp,int err)248 set_error(int *errp, int err)
249 {
250 return (*errp = err);
251 }
252
253 static int
get_error(int * errp)254 get_error(int *errp)
255 {
256 return (*errp);
257 }
258
259 /*
260 * For MT safety, do not invoke the dynamic linker after calling vfork().
261 * If some other thread was in the dynamic linker when this thread's parent
262 * called vfork() then the dynamic linker's lock would still be held here
263 * (with a defunct owner) and we would deadlock ourself if we invoked it.
264 *
265 * Therefore, all of the functions we call here after returning from
266 * vforkx() in the child are not and must never be exported from libc
267 * as global symbols. To do so would risk invoking the dynamic linker.
268 */
269
270 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[])271 posix_spawn(
272 pid_t *pidp,
273 const char *path,
274 const posix_spawn_file_actions_t *file_actions,
275 const posix_spawnattr_t *attrp,
276 char *const argv[],
277 char *const envp[])
278 {
279 spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
280 file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
281 void *dirbuf = NULL;
282 int error; /* this will be set by the child */
283 pid_t pid;
284
285 if (attrp != NULL && sap == NULL)
286 return (EINVAL);
287
288 if (fap != NULL && fap->fa_need_dirbuf) {
289 /*
290 * Preallocate the buffer for the call to getdents64() in
291 * spawn_closefrom() since we can't do it in the vfork() child.
292 */
293 if ((dirbuf = lmalloc(DIRBUF)) == NULL)
294 return (ENOMEM);
295 }
296
297 switch (pid = vforkx(forkflags(sap))) {
298 case 0: /* child */
299 break;
300 case -1: /* parent, failure */
301 if (dirbuf)
302 lfree(dirbuf, DIRBUF);
303 return (errno);
304 default: /* parent, success */
305 /*
306 * We don't get here until the child exec()s or exit()s
307 */
308 if (pidp != NULL && get_error(&error) == 0)
309 *pidp = pid;
310 if (dirbuf)
311 lfree(dirbuf, DIRBUF);
312 return (get_error(&error));
313 }
314
315 if (sap != NULL)
316 if (set_error(&error, perform_flag_actions(sap)) != 0)
317 _exit(_EVAPORATE);
318
319 if (fap != NULL)
320 if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
321 _exit(_EVAPORATE);
322
323 (void) set_error(&error, 0);
324 (void) execve(path, argv, envp);
325 if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
326 _exit(127);
327 (void) set_error(&error, errno);
328 _exit(_EVAPORATE);
329 return (0); /* not reached */
330 }
331
332 /*
333 * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c).
334 */
335
336 extern int libc__xpg4;
337
338 static const char *
execat(const char * s1,const char * s2,char * si)339 execat(const char *s1, const char *s2, char *si)
340 {
341 int cnt = PATH_MAX + 1;
342 char *s;
343 char c;
344
345 for (s = si; (c = *s1) != '\0' && c != ':'; s1++) {
346 if (cnt > 0) {
347 *s++ = c;
348 cnt--;
349 }
350 }
351 if (si != s && cnt > 0) {
352 *s++ = '/';
353 cnt--;
354 }
355 for (; (c = *s2) != '\0' && cnt > 0; s2++) {
356 *s++ = c;
357 cnt--;
358 }
359 *s = '\0';
360 return (*s1? ++s1: NULL);
361 }
362
363 /* ARGSUSED */
364 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[])365 posix_spawnp(
366 pid_t *pidp,
367 const char *file,
368 const posix_spawn_file_actions_t *file_actions,
369 const posix_spawnattr_t *attrp,
370 char *const argv[],
371 char *const envp[])
372 {
373 spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
374 file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
375 void *dirbuf = NULL;
376 const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : "";
377 int xpg4 = libc__xpg4;
378 int error = 0; /* this will be set by the child */
379 char path[PATH_MAX+4];
380 const char *cp;
381 pid_t pid;
382 char **newargs;
383 int argc;
384 int i;
385 static const char *sun_path = "/bin/sh";
386 static const char *xpg4_path = "/usr/xpg4/bin/sh";
387 static const char *shell = "sh";
388
389 if (attrp != NULL && sap == NULL)
390 return (EINVAL);
391
392 if (*file == '\0')
393 return (EACCES);
394
395 if (fap != NULL && fap->fa_need_dirbuf) {
396 /*
397 * Preallocate the buffer for the call to getdents64() in
398 * spawn_closefrom() since we can't do it in the vfork() child.
399 */
400 if ((dirbuf = lmalloc(DIRBUF)) == NULL)
401 return (ENOMEM);
402 }
403
404 /*
405 * We may need to invoke the shell with a slightly modified
406 * argv[] array. To do this we need to preallocate the array.
407 * We must call alloca() before calling vfork() because doing
408 * it after vfork() (in the child) would corrupt the parent.
409 */
410 for (argc = 0; argv[argc] != NULL; argc++)
411 continue;
412 newargs = alloca((argc + 2) * sizeof (char *));
413
414 switch (pid = vforkx(forkflags(sap))) {
415 case 0: /* child */
416 break;
417 case -1: /* parent, failure */
418 if (dirbuf)
419 lfree(dirbuf, DIRBUF);
420 return (errno);
421 default: /* parent, success */
422 /*
423 * We don't get here until the child exec()s or exit()s
424 */
425 if (pidp != NULL && get_error(&error) == 0)
426 *pidp = pid;
427 if (dirbuf)
428 lfree(dirbuf, DIRBUF);
429 return (get_error(&error));
430 }
431
432 if (sap != NULL)
433 if (set_error(&error, perform_flag_actions(sap)) != 0)
434 _exit(_EVAPORATE);
435
436 if (fap != NULL)
437 if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
438 _exit(_EVAPORATE);
439
440 if (pathstr == NULL) {
441 /*
442 * XPG4: pathstr is equivalent to _CS_PATH, except that
443 * :/usr/sbin is appended when root, and pathstr must end
444 * with a colon when not root. Keep these paths in sync
445 * with _CS_PATH in confstr.c. Note that pathstr must end
446 * with a colon when not root so that when file doesn't
447 * contain '/', the last call to execat() will result in an
448 * attempt to execv file from the current directory.
449 */
450 if (geteuid() == 0 || getuid() == 0) {
451 if (!xpg4)
452 pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin";
453 else
454 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
455 "/usr/bin:/opt/SUNWspro/bin:/usr/sbin";
456 } else {
457 if (!xpg4)
458 pathstr = "/usr/ccs/bin:/usr/bin:";
459 else
460 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
461 "/usr/bin:/opt/SUNWspro/bin:";
462 }
463 }
464
465 cp = pathstr;
466 do {
467 cp = execat(cp, file, path);
468 /*
469 * 4025035 and 4038378
470 * if a filename begins with a "-" prepend "./" so that
471 * the shell can't interpret it as an option
472 */
473 if (*path == '-') {
474 char *s;
475
476 for (s = path; *s != '\0'; s++)
477 continue;
478 for (; s >= path; s--)
479 *(s + 2) = *s;
480 path[0] = '.';
481 path[1] = '/';
482 }
483 (void) set_error(&error, 0);
484 (void) execve(path, argv, envp);
485 if (set_error(&error, errno) == ENOEXEC) {
486 newargs[0] = (char *)shell;
487 newargs[1] = path;
488 for (i = 1; i <= argc; i++)
489 newargs[i + 1] = argv[i];
490 (void) set_error(&error, 0);
491 (void) execve(xpg4? xpg4_path : sun_path,
492 newargs, envp);
493 if (sap != NULL &&
494 (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
495 _exit(127);
496 (void) set_error(&error, errno);
497 _exit(_EVAPORATE);
498 }
499 } while (cp);
500
501 if (sap != NULL &&
502 (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) {
503 (void) set_error(&error, 0);
504 _exit(127);
505 }
506 _exit(_EVAPORATE);
507 return (0); /* not reached */
508 }
509
510 int
posix_spawn_file_actions_init(posix_spawn_file_actions_t * file_actions)511 posix_spawn_file_actions_init(
512 posix_spawn_file_actions_t *file_actions)
513 {
514 file_actions->__file_attrp = NULL;
515 return (0);
516 }
517
518 int
posix_spawn_file_actions_destroy(posix_spawn_file_actions_t * file_actions)519 posix_spawn_file_actions_destroy(
520 posix_spawn_file_actions_t *file_actions)
521 {
522 file_attr_t *froot = file_actions->__file_attrp;
523 file_attr_t *fap;
524 file_attr_t *next;
525
526 if ((fap = froot) != NULL) {
527 do {
528 next = fap->fa_next;
529 if (fap->fa_type == FA_OPEN)
530 lfree(fap->fa_path, fap->fa_pathsize);
531 lfree(fap, sizeof (*fap));
532 } while ((fap = next) != froot);
533 }
534 file_actions->__file_attrp = NULL;
535 return (0);
536 }
537
538 static void
add_file_attr(posix_spawn_file_actions_t * file_actions,file_attr_t * fap)539 add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap)
540 {
541 file_attr_t *froot = file_actions->__file_attrp;
542
543 if (froot == NULL) {
544 fap->fa_next = fap->fa_prev = fap;
545 file_actions->__file_attrp = froot = fap;
546 } else {
547 fap->fa_next = froot;
548 fap->fa_prev = froot->fa_prev;
549 froot->fa_prev->fa_next = fap;
550 froot->fa_prev = fap;
551 }
552
553 /*
554 * Once set, __file_attrp no longer changes, so this assignment
555 * always goes into the first element in the list, as required.
556 */
557 if (fap->fa_type == FA_CLOSEFROM)
558 froot->fa_need_dirbuf = 1;
559 }
560
561 int
posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * file_actions,int filedes,const char * path,int oflag,mode_t mode)562 posix_spawn_file_actions_addopen(
563 posix_spawn_file_actions_t *file_actions,
564 int filedes,
565 const char *path,
566 int oflag,
567 mode_t mode)
568 {
569 file_attr_t *fap;
570
571 if (filedes < 0)
572 return (EBADF);
573 if ((fap = lmalloc(sizeof (*fap))) == NULL)
574 return (ENOMEM);
575
576 fap->fa_pathsize = strlen(path) + 1;
577 if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) {
578 lfree(fap, sizeof (*fap));
579 return (ENOMEM);
580 }
581 (void) strcpy(fap->fa_path, path);
582
583 fap->fa_type = FA_OPEN;
584 fap->fa_oflag = oflag;
585 fap->fa_mode = mode;
586 fap->fa_filedes = filedes;
587 add_file_attr(file_actions, fap);
588
589 return (0);
590 }
591
592 int
posix_spawn_file_actions_addclose(posix_spawn_file_actions_t * file_actions,int filedes)593 posix_spawn_file_actions_addclose(
594 posix_spawn_file_actions_t *file_actions,
595 int filedes)
596 {
597 file_attr_t *fap;
598
599 if (filedes < 0)
600 return (EBADF);
601 if ((fap = lmalloc(sizeof (*fap))) == NULL)
602 return (ENOMEM);
603
604 fap->fa_type = FA_CLOSE;
605 fap->fa_filedes = filedes;
606 add_file_attr(file_actions, fap);
607
608 return (0);
609 }
610
611 int
posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t * file_actions,int filedes,int newfiledes)612 posix_spawn_file_actions_adddup2(
613 posix_spawn_file_actions_t *file_actions,
614 int filedes,
615 int newfiledes)
616 {
617 file_attr_t *fap;
618
619 if (filedes < 0 || newfiledes < 0)
620 return (EBADF);
621 if ((fap = lmalloc(sizeof (*fap))) == NULL)
622 return (ENOMEM);
623
624 fap->fa_type = FA_DUP2;
625 fap->fa_filedes = filedes;
626 fap->fa_newfiledes = newfiledes;
627 add_file_attr(file_actions, fap);
628
629 return (0);
630 }
631
632 int
posix_spawn_file_actions_addclosefrom_np(posix_spawn_file_actions_t * file_actions,int lowfiledes)633 posix_spawn_file_actions_addclosefrom_np(
634 posix_spawn_file_actions_t *file_actions,
635 int lowfiledes)
636 {
637 file_attr_t *fap;
638
639 if (lowfiledes < 0)
640 return (EBADF);
641 if ((fap = lmalloc(sizeof (*fap))) == NULL)
642 return (ENOMEM);
643 fap->fa_type = FA_CLOSEFROM;
644 fap->fa_filedes = lowfiledes;
645 add_file_attr(file_actions, fap);
646
647 return (0);
648 }
649
650 int
posix_spawnattr_init(posix_spawnattr_t * attr)651 posix_spawnattr_init(
652 posix_spawnattr_t *attr)
653 {
654 if ((attr->__spawn_attrp = lmalloc(sizeof (posix_spawnattr_t))) == NULL)
655 return (ENOMEM);
656 /*
657 * Add default stuff here?
658 */
659 return (0);
660 }
661
662 int
posix_spawnattr_destroy(posix_spawnattr_t * attr)663 posix_spawnattr_destroy(
664 posix_spawnattr_t *attr)
665 {
666 spawn_attr_t *sap = attr->__spawn_attrp;
667
668 if (sap == NULL)
669 return (EINVAL);
670
671 /*
672 * deallocate stuff here?
673 */
674 lfree(sap, sizeof (*sap));
675 attr->__spawn_attrp = NULL;
676 return (0);
677 }
678
679 int
posix_spawnattr_setflags(posix_spawnattr_t * attr,short flags)680 posix_spawnattr_setflags(
681 posix_spawnattr_t *attr,
682 short flags)
683 {
684 spawn_attr_t *sap = attr->__spawn_attrp;
685
686 if (sap == NULL ||
687 (flags & ~ALL_POSIX_SPAWN_FLAGS))
688 return (EINVAL);
689
690 sap->sa_psflags = flags;
691 return (0);
692 }
693
694 int
posix_spawnattr_getflags(const posix_spawnattr_t * attr,short * flags)695 posix_spawnattr_getflags(
696 const posix_spawnattr_t *attr,
697 short *flags)
698 {
699 spawn_attr_t *sap = attr->__spawn_attrp;
700
701 if (sap == NULL)
702 return (EINVAL);
703
704 *flags = sap->sa_psflags;
705 return (0);
706 }
707
708 int
posix_spawnattr_setpgroup(posix_spawnattr_t * attr,pid_t pgroup)709 posix_spawnattr_setpgroup(
710 posix_spawnattr_t *attr,
711 pid_t pgroup)
712 {
713 spawn_attr_t *sap = attr->__spawn_attrp;
714
715 if (sap == NULL)
716 return (EINVAL);
717
718 sap->sa_pgroup = pgroup;
719 return (0);
720 }
721
722 int
posix_spawnattr_getpgroup(const posix_spawnattr_t * attr,pid_t * pgroup)723 posix_spawnattr_getpgroup(
724 const posix_spawnattr_t *attr,
725 pid_t *pgroup)
726 {
727 spawn_attr_t *sap = attr->__spawn_attrp;
728
729 if (sap == NULL)
730 return (EINVAL);
731
732 *pgroup = sap->sa_pgroup;
733 return (0);
734 }
735
736 int
posix_spawnattr_setschedparam(posix_spawnattr_t * attr,const struct sched_param * schedparam)737 posix_spawnattr_setschedparam(
738 posix_spawnattr_t *attr,
739 const struct sched_param *schedparam)
740 {
741 spawn_attr_t *sap = attr->__spawn_attrp;
742
743 if (sap == NULL)
744 return (EINVAL);
745
746 /*
747 * Check validity?
748 */
749 sap->sa_priority = schedparam->sched_priority;
750 return (0);
751 }
752
753 int
posix_spawnattr_getschedparam(const posix_spawnattr_t * attr,struct sched_param * schedparam)754 posix_spawnattr_getschedparam(
755 const posix_spawnattr_t *attr,
756 struct sched_param *schedparam)
757 {
758 spawn_attr_t *sap = attr->__spawn_attrp;
759
760 if (sap == NULL)
761 return (EINVAL);
762
763 schedparam->sched_priority = sap->sa_priority;
764 return (0);
765 }
766
767 int
posix_spawnattr_setschedpolicy(posix_spawnattr_t * attr,int schedpolicy)768 posix_spawnattr_setschedpolicy(
769 posix_spawnattr_t *attr,
770 int schedpolicy)
771 {
772 spawn_attr_t *sap = attr->__spawn_attrp;
773
774 if (sap == NULL || schedpolicy == SCHED_SYS)
775 return (EINVAL);
776
777 /*
778 * Cache the policy information for later use
779 * by the vfork() child of posix_spawn().
780 */
781 if (get_info_by_policy(schedpolicy) == NULL)
782 return (errno);
783
784 sap->sa_schedpolicy = schedpolicy;
785 return (0);
786 }
787
788 int
posix_spawnattr_getschedpolicy(const posix_spawnattr_t * attr,int * schedpolicy)789 posix_spawnattr_getschedpolicy(
790 const posix_spawnattr_t *attr,
791 int *schedpolicy)
792 {
793 spawn_attr_t *sap = attr->__spawn_attrp;
794
795 if (sap == NULL)
796 return (EINVAL);
797
798 *schedpolicy = sap->sa_schedpolicy;
799 return (0);
800 }
801
802 int
posix_spawnattr_setsigdefault(posix_spawnattr_t * attr,const sigset_t * sigdefault)803 posix_spawnattr_setsigdefault(
804 posix_spawnattr_t *attr,
805 const sigset_t *sigdefault)
806 {
807 spawn_attr_t *sap = attr->__spawn_attrp;
808
809 if (sap == NULL)
810 return (EINVAL);
811
812 sap->sa_sigdefault = *sigdefault;
813 return (0);
814 }
815
816 int
posix_spawnattr_getsigdefault(const posix_spawnattr_t * attr,sigset_t * sigdefault)817 posix_spawnattr_getsigdefault(
818 const posix_spawnattr_t *attr,
819 sigset_t *sigdefault)
820 {
821 spawn_attr_t *sap = attr->__spawn_attrp;
822
823 if (sap == NULL)
824 return (EINVAL);
825
826 *sigdefault = sap->sa_sigdefault;
827 return (0);
828 }
829
830 int
posix_spawnattr_setsigignore_np(posix_spawnattr_t * attr,const sigset_t * sigignore)831 posix_spawnattr_setsigignore_np(
832 posix_spawnattr_t *attr,
833 const sigset_t *sigignore)
834 {
835 spawn_attr_t *sap = attr->__spawn_attrp;
836
837 if (sap == NULL)
838 return (EINVAL);
839
840 sap->sa_sigignore = *sigignore;
841 return (0);
842 }
843
844 int
posix_spawnattr_getsigignore_np(const posix_spawnattr_t * attr,sigset_t * sigignore)845 posix_spawnattr_getsigignore_np(
846 const posix_spawnattr_t *attr,
847 sigset_t *sigignore)
848 {
849 spawn_attr_t *sap = attr->__spawn_attrp;
850
851 if (sap == NULL)
852 return (EINVAL);
853
854 *sigignore = sap->sa_sigignore;
855 return (0);
856 }
857
858 int
posix_spawnattr_setsigmask(posix_spawnattr_t * attr,const sigset_t * sigmask)859 posix_spawnattr_setsigmask(
860 posix_spawnattr_t *attr,
861 const sigset_t *sigmask)
862 {
863 spawn_attr_t *sap = attr->__spawn_attrp;
864
865 if (sap == NULL)
866 return (EINVAL);
867
868 sap->sa_sigmask = *sigmask;
869 return (0);
870 }
871
872 int
posix_spawnattr_getsigmask(const posix_spawnattr_t * attr,sigset_t * sigmask)873 posix_spawnattr_getsigmask(
874 const posix_spawnattr_t *attr,
875 sigset_t *sigmask)
876 {
877 spawn_attr_t *sap = attr->__spawn_attrp;
878
879 if (sap == NULL)
880 return (EINVAL);
881
882 *sigmask = sap->sa_sigmask;
883 return (0);
884 }
885