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