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