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