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 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 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 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 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 248 set_error(int *errp, int err) 249 { 250 return (*errp = err); 251 } 252 253 static int 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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