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 /* 28 * Copyright (c) 2011 by Delphix. All rights reserved. 29 */ 30 31 #include "lint.h" 32 #include "thr_uberdata.h" 33 #include <sys/libc_kernel.h> 34 #include <sys/procset.h> 35 #include <sys/fork.h> 36 #include <dirent.h> 37 #include <alloca.h> 38 #include <spawn.h> 39 #include <paths.h> 40 41 #define ALL_POSIX_SPAWN_FLAGS \ 42 (POSIX_SPAWN_RESETIDS | \ 43 POSIX_SPAWN_SETPGROUP | \ 44 POSIX_SPAWN_SETSIGDEF | \ 45 POSIX_SPAWN_SETSIGMASK | \ 46 POSIX_SPAWN_SETSCHEDPARAM | \ 47 POSIX_SPAWN_SETSCHEDULER | \ 48 POSIX_SPAWN_SETSIGIGN_NP | \ 49 POSIX_SPAWN_NOSIGCHLD_NP | \ 50 POSIX_SPAWN_WAITPID_NP | \ 51 POSIX_SPAWN_NOEXECERR_NP) 52 53 typedef struct { 54 int sa_psflags; /* POSIX_SPAWN_* flags */ 55 int sa_priority; 56 int sa_schedpolicy; 57 pid_t sa_pgroup; 58 sigset_t sa_sigdefault; 59 sigset_t sa_sigignore; 60 sigset_t sa_sigmask; 61 } spawn_attr_t; 62 63 typedef struct file_attr { 64 struct file_attr *fa_next; /* circular list of file actions */ 65 struct file_attr *fa_prev; 66 enum {FA_OPEN, FA_CLOSE, FA_DUP2, FA_CLOSEFROM} fa_type; 67 int fa_need_dirbuf; /* only consulted in the head action */ 68 char *fa_path; /* copied pathname for open() */ 69 uint_t fa_pathsize; /* size of fa_path[] array */ 70 int fa_oflag; /* oflag for open() */ 71 mode_t fa_mode; /* mode for open() */ 72 int fa_filedes; /* file descriptor for open()/close() */ 73 int fa_newfiledes; /* new file descriptor for dup2() */ 74 } file_attr_t; 75 76 #if defined(_LP64) 77 #define __open64 __open 78 #define getdents64 getdents 79 #define dirent64_t dirent_t 80 #else 81 extern int getdents64(int, dirent64_t *, size_t); 82 #endif 83 84 extern const char **_environ; 85 86 /* 87 * Support function: 88 * Close all open file descriptors greater than or equal to lowfd. 89 * This is executed in the child of vfork(), so we must not call 90 * opendir() / readdir() because that would alter the parent's 91 * address space. We use the low-level getdents64() system call. 92 * Return non-zero on error. 93 */ 94 static int 95 spawn_closefrom(int lowfd, void *buf) 96 { 97 int procfd; 98 int fd; 99 int buflen; 100 dirent64_t *dp; 101 dirent64_t *dpend; 102 103 if (lowfd < 0) 104 lowfd = 0; 105 106 /* 107 * Close lowfd right away as a hedge against failing 108 * to open the /proc file descriptor directory due 109 * all file descriptors being currently used up. 110 */ 111 (void) __close(lowfd++); 112 113 if ((procfd = __open64("/proc/self/fd", O_RDONLY, 0)) < 0) { 114 /* 115 * We could not open the /proc file descriptor directory. 116 * Just fail and be done with it. 117 */ 118 return (-1); 119 } 120 121 for (;;) { 122 /* 123 * Collect a bunch of open file descriptors and close them. 124 * Repeat until the directory is exhausted. 125 */ 126 dp = (dirent64_t *)buf; 127 if ((buflen = getdents64(procfd, dp, DIRBUF)) <= 0) { 128 (void) __close(procfd); 129 break; 130 } 131 dpend = (dirent64_t *)((uintptr_t)buf + buflen); 132 do { 133 /* skip '.', '..' and procfd */ 134 if (dp->d_name[0] != '.' && 135 (fd = atoi(dp->d_name)) != procfd && 136 fd >= lowfd) 137 (void) __close(fd); 138 dp = (dirent64_t *)((uintptr_t)dp + dp->d_reclen); 139 } while (dp < dpend); 140 } 141 142 return (0); 143 } 144 145 static int 146 perform_flag_actions(spawn_attr_t *sap) 147 { 148 int sig; 149 struct sigaction action; 150 151 if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) { 152 (void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask); 153 } 154 155 if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) { 156 (void) memset(&action, 0, sizeof (action)); 157 action.sa_handler = SIG_IGN; 158 for (sig = 1; sig < NSIG; sig++) { 159 if (sigismember(&sap->sa_sigignore, sig)) 160 (void) __sigaction(sig, &action, NULL); 161 } 162 } 163 164 if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) { 165 (void) memset(&action, 0, sizeof (action)); 166 action.sa_handler = SIG_DFL; 167 for (sig = 1; sig < NSIG; sig++) { 168 if (sigismember(&sap->sa_sigdefault, sig)) 169 (void) __sigaction(sig, &action, NULL); 170 } 171 } 172 173 if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) { 174 if (setgid(getgid()) != 0 || setuid(getuid()) != 0) 175 return (errno); 176 } 177 178 if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) { 179 if (setpgid(0, sap->sa_pgroup) != 0) 180 return (errno); 181 } 182 183 if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) { 184 if (setparam(P_LWPID, P_MYID, 185 sap->sa_schedpolicy, sap->sa_priority) == -1) 186 return (errno); 187 } else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) { 188 if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1) 189 return (errno); 190 } 191 192 return (0); 193 } 194 195 static int 196 perform_file_actions(file_attr_t *fap, void *dirbuf) 197 { 198 file_attr_t *froot = fap; 199 int fd; 200 201 do { 202 switch (fap->fa_type) { 203 case FA_OPEN: 204 fd = __open(fap->fa_path, fap->fa_oflag, fap->fa_mode); 205 if (fd < 0) 206 return (errno); 207 if (fd != fap->fa_filedes) { 208 if (__fcntl(fd, F_DUP2FD, fap->fa_filedes) < 0) 209 return (errno); 210 (void) __close(fd); 211 } 212 break; 213 case FA_CLOSE: 214 if (__close(fap->fa_filedes) == -1 && 215 errno != EBADF) /* already closed, no error */ 216 return (errno); 217 break; 218 case FA_DUP2: 219 fd = __fcntl(fap->fa_filedes, F_DUP2FD, 220 fap->fa_newfiledes); 221 if (fd < 0) 222 return (errno); 223 break; 224 case FA_CLOSEFROM: 225 if (spawn_closefrom(fap->fa_filedes, dirbuf)) 226 return (errno); 227 break; 228 } 229 } while ((fap = fap->fa_next) != froot); 230 231 return (0); 232 } 233 234 static int 235 forkflags(spawn_attr_t *sap) 236 { 237 int flags = 0; 238 239 if (sap != NULL) { 240 if (sap->sa_psflags & POSIX_SPAWN_NOSIGCHLD_NP) 241 flags |= FORK_NOSIGCHLD; 242 if (sap->sa_psflags & POSIX_SPAWN_WAITPID_NP) 243 flags |= FORK_WAITPID; 244 } 245 246 return (flags); 247 } 248 249 /* 250 * set_error() / get_error() are used to guarantee that the local variable 251 * 'error' is set correctly in memory on return from vfork() in the parent. 252 */ 253 254 static int 255 set_error(int *errp, int err) 256 { 257 return (*errp = err); 258 } 259 260 static int 261 get_error(int *errp) 262 { 263 return (*errp); 264 } 265 266 /* 267 * For MT safety, do not invoke the dynamic linker after calling vfork(). 268 * If some other thread was in the dynamic linker when this thread's parent 269 * called vfork() then the dynamic linker's lock would still be held here 270 * (with a defunct owner) and we would deadlock ourself if we invoked it. 271 * 272 * Therefore, all of the functions we call here after returning from 273 * vforkx() in the child are not and must never be exported from libc 274 * as global symbols. To do so would risk invoking the dynamic linker. 275 */ 276 277 int 278 posix_spawn( 279 pid_t *pidp, 280 const char *path, 281 const posix_spawn_file_actions_t *file_actions, 282 const posix_spawnattr_t *attrp, 283 char *const argv[], 284 char *const envp[]) 285 { 286 spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL; 287 file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL; 288 void *dirbuf = NULL; 289 int error; /* this will be set by the child */ 290 pid_t pid; 291 292 if (attrp != NULL && sap == NULL) 293 return (EINVAL); 294 295 if (fap != NULL && fap->fa_need_dirbuf) { 296 /* 297 * Preallocate the buffer for the call to getdents64() in 298 * spawn_closefrom() since we can't do it in the vfork() child. 299 */ 300 if ((dirbuf = lmalloc(DIRBUF)) == NULL) 301 return (ENOMEM); 302 } 303 304 switch (pid = vforkx(forkflags(sap))) { 305 case 0: /* child */ 306 break; 307 case -1: /* parent, failure */ 308 if (dirbuf) 309 lfree(dirbuf, DIRBUF); 310 return (errno); 311 default: /* parent, success */ 312 /* 313 * We don't get here until the child exec()s or exit()s 314 */ 315 if (pidp != NULL && get_error(&error) == 0) 316 *pidp = pid; 317 if (dirbuf) 318 lfree(dirbuf, DIRBUF); 319 return (get_error(&error)); 320 } 321 322 if (sap != NULL) 323 if (set_error(&error, perform_flag_actions(sap)) != 0) 324 _exit(_EVAPORATE); 325 326 if (fap != NULL) 327 if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0) 328 _exit(_EVAPORATE); 329 330 (void) set_error(&error, 0); 331 (void) execve(path, argv, envp); 332 if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) 333 _exit(127); 334 (void) set_error(&error, errno); 335 _exit(_EVAPORATE); 336 return (0); /* not reached */ 337 } 338 339 /* 340 * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c). 341 */ 342 343 extern int libc__xpg4; 344 345 static const char * 346 execat(const char *s1, const char *s2, char *si) 347 { 348 int cnt = PATH_MAX + 1; 349 char *s; 350 char c; 351 352 for (s = si; (c = *s1) != '\0' && c != ':'; s1++) { 353 if (cnt > 0) { 354 *s++ = c; 355 cnt--; 356 } 357 } 358 if (si != s && cnt > 0) { 359 *s++ = '/'; 360 cnt--; 361 } 362 for (; (c = *s2) != '\0' && cnt > 0; s2++) { 363 *s++ = c; 364 cnt--; 365 } 366 *s = '\0'; 367 return (*s1? ++s1: NULL); 368 } 369 370 /* ARGSUSED */ 371 int 372 posix_spawnp( 373 pid_t *pidp, 374 const char *file, 375 const posix_spawn_file_actions_t *file_actions, 376 const posix_spawnattr_t *attrp, 377 char *const argv[], 378 char *const envp[]) 379 { 380 spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL; 381 file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL; 382 void *dirbuf = NULL; 383 const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : ""; 384 int xpg4 = libc__xpg4; 385 int error = 0; /* this will be set by the child */ 386 char path[PATH_MAX+4]; 387 const char *cp; 388 pid_t pid; 389 char **newargs; 390 int argc; 391 int i; 392 393 if (attrp != NULL && sap == NULL) 394 return (EINVAL); 395 396 if (*file == '\0') 397 return (EACCES); 398 399 if (fap != NULL && fap->fa_need_dirbuf) { 400 /* 401 * Preallocate the buffer for the call to getdents64() in 402 * spawn_closefrom() since we can't do it in the vfork() child. 403 */ 404 if ((dirbuf = lmalloc(DIRBUF)) == NULL) 405 return (ENOMEM); 406 } 407 408 /* 409 * We may need to invoke the shell with a slightly modified 410 * argv[] array. To do this we need to preallocate the array. 411 * We must call alloca() before calling vfork() because doing 412 * it after vfork() (in the child) would corrupt the parent. 413 */ 414 for (argc = 0; argv[argc] != NULL; argc++) 415 continue; 416 newargs = alloca((argc + 2) * sizeof (char *)); 417 418 switch (pid = vforkx(forkflags(sap))) { 419 case 0: /* child */ 420 break; 421 case -1: /* parent, failure */ 422 if (dirbuf) 423 lfree(dirbuf, DIRBUF); 424 return (errno); 425 default: /* parent, success */ 426 /* 427 * We don't get here until the child exec()s or exit()s 428 */ 429 if (pidp != NULL && get_error(&error) == 0) 430 *pidp = pid; 431 if (dirbuf) 432 lfree(dirbuf, DIRBUF); 433 return (get_error(&error)); 434 } 435 436 if (sap != NULL) 437 if (set_error(&error, perform_flag_actions(sap)) != 0) 438 _exit(_EVAPORATE); 439 440 if (fap != NULL) 441 if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0) 442 _exit(_EVAPORATE); 443 444 if (pathstr == NULL) { 445 /* 446 * XPG4: pathstr is equivalent to _CS_PATH, except that 447 * :/usr/sbin is appended when root, and pathstr must end 448 * with a colon when not root. Keep these paths in sync 449 * with _CS_PATH in confstr.c. Note that pathstr must end 450 * with a colon when not root so that when file doesn't 451 * contain '/', the last call to execat() will result in an 452 * attempt to execv file from the current directory. 453 */ 454 if (geteuid() == 0 || getuid() == 0) { 455 if (!xpg4) 456 pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin"; 457 else 458 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 459 "/usr/bin:/opt/SUNWspro/bin:/usr/sbin"; 460 } else { 461 if (!xpg4) 462 pathstr = "/usr/ccs/bin:/usr/bin:"; 463 else 464 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 465 "/usr/bin:/opt/SUNWspro/bin:"; 466 } 467 } 468 469 cp = pathstr; 470 do { 471 cp = execat(cp, file, path); 472 /* 473 * 4025035 and 4038378 474 * if a filename begins with a "-" prepend "./" so that 475 * the shell can't interpret it as an option 476 */ 477 if (*path == '-') { 478 char *s; 479 480 for (s = path; *s != '\0'; s++) 481 continue; 482 for (; s >= path; s--) 483 *(s + 2) = *s; 484 path[0] = '.'; 485 path[1] = '/'; 486 } 487 (void) set_error(&error, 0); 488 (void) execve(path, argv, envp); 489 if (set_error(&error, errno) == ENOEXEC) { 490 newargs[0] = "sh"; 491 newargs[1] = path; 492 for (i = 1; i <= argc; i++) 493 newargs[i + 1] = argv[i]; 494 (void) set_error(&error, 0); 495 (void) execve(_PATH_BSHELL, 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 889 /* 890 * Spawn a process to run "sh -c <cmd>". Return the child's pid (in 891 * *pidp), and a file descriptor (in *fdp) for reading or writing to the 892 * child process, depending on the 'write' argument. 893 * Return 0 on success; otherwise return an error code. 894 */ 895 int 896 posix_spawn_pipe_np(pid_t *pidp, int *fdp, 897 const char *cmd, boolean_t write, 898 posix_spawn_file_actions_t *fact, posix_spawnattr_t *attr) 899 { 900 int p[2]; 901 int myside, yourside, stdio; 902 const char *shpath = _PATH_BSHELL; 903 const char *argvec[4] = { "sh", "-c", cmd, NULL }; 904 int error; 905 906 if (pipe(p) < 0) 907 return (errno); 908 909 if (access(shpath, X_OK)) /* XPG4 Requirement: */ 910 shpath = ""; /* force child to fail immediately */ 911 912 if (write) { 913 /* 914 * Data is read from p[0] and written to p[1]. 915 * 'stdio' is the fd in the child process that should be 916 * connected to the pipe. 917 */ 918 myside = p[1]; 919 yourside = p[0]; 920 stdio = STDIN_FILENO; 921 } else { 922 myside = p[0]; 923 yourside = p[1]; 924 stdio = STDOUT_FILENO; 925 } 926 927 error = posix_spawn_file_actions_addclose(fact, myside); 928 if (yourside != stdio) { 929 if (error == 0) { 930 error = posix_spawn_file_actions_adddup2(fact, 931 yourside, stdio); 932 } 933 if (error == 0) { 934 error = posix_spawn_file_actions_addclose(fact, 935 yourside); 936 } 937 } 938 939 if (error) 940 return (error); 941 error = posix_spawn(pidp, shpath, fact, attr, 942 (char *const *)argvec, (char *const *)_environ); 943 (void) close(yourside); 944 if (error) { 945 (void) close(myside); 946 return (error); 947 } 948 949 *fdp = myside; 950 return (0); 951 } 952