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