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 * Copyright 2026 Oxide Computer Company 30 * Copyright 2026 RackTop Systems, Inc. 31 */ 32 33 #include "lint.h" 34 #include "thr_uberdata.h" 35 #include <sys/sysmacros.h> 36 #include <limits.h> 37 #include <spawn.h> 38 #include <stdbool.h> 39 #include <sys/spawn_impl.h> 40 #include <paths.h> 41 42 extern const char **_environ; 43 extern int libc__xpg4; 44 45 extern pid_t __spawn(const char *, const void *, uint32_t, const void *, 46 uint32_t); 47 48 /* 49 * Add sz to the running total *lenp, refusing if the total would exceed 50 * ARG_MAX. ARG_MAX is well below UINT32_MAX, so capping there also keeps the 51 * marshalled totals and offsets within their uint32_t fields. 52 */ 53 static inline bool 54 spawn_addlen(size_t *lenp, size_t sz) 55 { 56 if (sz > ARG_MAX - *lenp) 57 return (false); 58 *lenp += sz; 59 return (true); 60 } 61 62 /* 63 * Pack the argv[] and envp[] string vectors into sargs->sa_data as a single 64 * blob of NUL-terminated strings. Called first with sargs == NULL to compute 65 * the required buffer size, then again to populate the data and record the 66 * offsets and counts. Returns false if the combined size would exceed ARG_MAX 67 * or, on the second pass, would overflow the allocated buffer. 68 */ 69 static bool 70 spawn_marshal_argenv(spawn_args_t *sargs, char *const *argp, char *const *envp, 71 size_t *lenp) 72 { 73 struct vec { 74 char *const *vec; 75 uint32_t *off; 76 uint32_t *cnt; 77 } vecs[] = { 78 { .vec = argp }, 79 { .vec = envp } 80 }; 81 82 if (sargs != NULL) { 83 vecs[0].off = &sargs->sa_arg_off; 84 vecs[0].cnt = &sargs->sa_arg_cnt; 85 vecs[1].off = &sargs->sa_env_off; 86 vecs[1].cnt = &sargs->sa_env_cnt; 87 } 88 89 for (size_t i = 0; i < ARRAY_SIZE(vecs); i++) { 90 struct vec *vec = &vecs[i]; 91 uint32_t cnt = 0; 92 char *const *p; 93 94 if (vec->off != NULL) 95 *vec->off = (uint32_t)*lenp; 96 97 for (p = vec->vec; p != NULL && *p != NULL; p++) { 98 size_t sz = strlen(*p) + 1; 99 100 if (sargs != NULL) { 101 if (*lenp + sz > sargs->sa_datalen) 102 return (false); 103 (void) memcpy(&sargs->sa_data[*lenp], *p, sz); 104 } 105 if (!spawn_addlen(lenp, sz)) 106 return (false); 107 cnt++; 108 } 109 110 if (vec->cnt != NULL) 111 *vec->cnt = cnt; 112 } 113 114 return (true); 115 } 116 117 /* 118 * Pack the spawn_attr_t, the resolved scheduling attributes, the circular 119 * list of file_attr_t records and, for posix_spawnp(), the shell and search 120 * path strings into sparam->sp_data. 121 * Called first with sparam == NULL to compute the required buffer size, then 122 * again to populate the data and record the offsets, lengths and counts. 123 * Returns false if the combined size would exceed ARG_MAX or, on the second 124 * pass, would overflow the allocated buffer. 125 */ 126 static bool 127 spawn_marshal_param(spawn_param_t *sparam, const spawn_attr_t *sa, 128 const kspawn_sched_t *ksched, const file_attr_t *fa, const char *shell, 129 const char *pathstr, size_t *lenp) 130 { 131 if (sa != NULL) { 132 size_t sz = sizeof (*sa); 133 134 if (sparam != NULL) { 135 if (*lenp + sz > sparam->sp_datalen) 136 return (false); 137 sparam->sp_attr_off = (uint32_t)*lenp; 138 sparam->sp_attr_len = (uint32_t)sz; 139 (void) memcpy(&sparam->sp_data[*lenp], sa, sz); 140 } 141 if (!spawn_addlen(lenp, sz)) 142 return (false); 143 } 144 145 if (ksched != NULL) { 146 size_t sz = sizeof (*ksched); 147 148 if (sparam != NULL) { 149 if (*lenp + sz > sparam->sp_datalen) 150 return (false); 151 sparam->sp_sched_off = (uint32_t)*lenp; 152 sparam->sp_sched_len = (uint32_t)sz; 153 (void) memcpy(&sparam->sp_data[*lenp], ksched, sz); 154 } 155 if (!spawn_addlen(lenp, sz)) 156 return (false); 157 } 158 159 if (fa != NULL) { 160 const file_attr_t *froot = fa; 161 uint32_t cnt = 0; 162 163 if (sparam != NULL) 164 sparam->sp_fattr_off = (uint32_t)*lenp; 165 166 do { 167 /* 168 * Each record is padded so that the next remains 169 * 32-bit aligned. 170 */ 171 size_t sz = P2ROUNDUP( 172 sizeof (kfile_attr_t) + fa->fa_pathsize, 173 sizeof (uint32_t)); 174 175 if (sparam != NULL) { 176 kfile_attr_t *ka; 177 178 if (*lenp + sz > sparam->sp_datalen) 179 return (false); 180 181 ka = (kfile_attr_t *)&sparam->sp_data[*lenp]; 182 ka->kfa_len = sz; 183 ka->kfa_type = fa->fa_type; 184 ka->kfa_pathsize = fa->fa_pathsize; 185 186 switch (fa->fa_type) { 187 case FA_OPEN: 188 ka->kfa_filedes = fa->fa_filedes; 189 ka->kfa_oflag = fa->fa_oflag; 190 ka->kfa_mode = fa->fa_mode; 191 /* FALLTHROUGH */ 192 case FA_CHDIR: 193 (void) memcpy(ka->kfa_path, 194 fa->fa_path, fa->fa_pathsize); 195 break; 196 case FA_DUP2: 197 ka->kfa_newfiledes = fa->fa_newfiledes; 198 /* FALLTHROUGH */ 199 case FA_CLOSE: 200 case FA_CLOSEFROM: 201 case FA_FCHDIR: 202 ka->kfa_filedes = fa->fa_filedes; 203 break; 204 } 205 } 206 if (!spawn_addlen(lenp, sz)) 207 return (false); 208 cnt++; 209 } while ((fa = fa->fa_next) != froot); 210 211 if (sparam != NULL) 212 sparam->sp_fattr_cnt = cnt; 213 } 214 215 if (shell != NULL) { 216 size_t sz = strlen(shell) + 1; 217 218 if (sparam != NULL) { 219 if (*lenp + sz > sparam->sp_datalen) 220 return (false); 221 sparam->sp_shell_off = (uint32_t)*lenp; 222 sparam->sp_shell_len = (uint32_t)sz; 223 (void) memcpy(&sparam->sp_data[*lenp], shell, sz); 224 } 225 if (!spawn_addlen(lenp, sz)) 226 return (false); 227 } 228 229 if (pathstr != NULL) { 230 size_t sz = strlen(pathstr) + 1; 231 232 if (sparam != NULL) { 233 if (*lenp + sz > sparam->sp_datalen) 234 return (false); 235 sparam->sp_path_off = (uint32_t)*lenp; 236 sparam->sp_path_len = (uint32_t)sz; 237 (void) memcpy(&sparam->sp_data[*lenp], pathstr, sz); 238 } 239 if (!spawn_addlen(lenp, sz)) 240 return (false); 241 } 242 243 return (true); 244 } 245 246 static int 247 posix_spawn_common(pid_t *pidp, const char *path, 248 const posix_spawn_file_actions_t *file_actions, 249 const posix_spawnattr_t *attrp, char *const *argp, char *const *envp, 250 const char *shell, const char *pathstr) 251 { 252 spawn_attr_t *sa = (attrp != NULL) ? attrp->__spawn_attrp : NULL; 253 file_attr_t *fa = (file_actions != NULL) ? file_actions->__file_attrp : 254 NULL; 255 const kspawn_sched_t *ksched = NULL; 256 kspawn_sched_t ks; 257 spawn_args_t *sargs = NULL; 258 spawn_param_t *sparam = NULL; 259 pid_t pid; 260 size_t datalen, len; 261 int ret = 0; 262 263 if (attrp != NULL && sa == NULL) 264 return (EINVAL); 265 266 /* 267 * The scheduling attributes are resolved here into the form that the 268 * child applies to itself in the kernel. 269 */ 270 if (sa != NULL && (sa->sa_psflags & 271 (POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_SETSCHEDPARAM)) != 0) { 272 ret = spawn_sched_resolve(sa->sa_psflags, sa->sa_schedpolicy, 273 sa->sa_priority, &ks); 274 if (ret != 0) 275 return (ret); 276 ksched = &ks; 277 } 278 279 /* 280 * spawn(2) creates a brand-new child process that does not share the 281 * parent's address space, so every piece of state needed to set up the 282 * child must be copied into the kernel ahead of time. Marshal the 283 * spawn attributes, the list of file actions and, for posix_spawnp(), 284 * the shell and search path, into a single contiguous blob that the 285 * kernel can copy in and retain. 286 */ 287 datalen = 0; 288 if (!spawn_marshal_param(NULL, sa, ksched, fa, shell, pathstr, 289 &datalen)) { 290 ret = E2BIG; 291 goto out; 292 } 293 if (datalen > 0) { 294 len = sizeof (*sparam) + datalen; 295 sparam = lmalloc(len); 296 if (sparam == NULL) { 297 ret = errno; 298 goto out; 299 } 300 sparam->sp_size = len; 301 sparam->sp_datalen = datalen; 302 303 datalen = 0; 304 if (!spawn_marshal_param(sparam, sa, ksched, fa, shell, 305 pathstr, &datalen) || datalen != sparam->sp_datalen) { 306 ret = EINVAL; 307 goto out; 308 } 309 } 310 311 /* 312 * Likewise the argument and environment vectors. As supplied by the 313 * caller these are arrays of pointers into strings that may well be 314 * scattered around the parent's address space. Flatten the strings 315 * into a single contiguous blob that the kernel can copy in. 316 */ 317 datalen = 0; 318 if (!spawn_marshal_argenv(NULL, argp, envp, &datalen)) { 319 ret = E2BIG; 320 goto out; 321 } 322 len = sizeof (*sargs) + datalen; 323 sargs = lmalloc(len); 324 if (sargs == NULL) { 325 ret = errno; 326 goto out; 327 } 328 sargs->sa_size = len; 329 sargs->sa_datalen = datalen; 330 331 datalen = 0; 332 if (!spawn_marshal_argenv(sargs, argp, envp, &datalen) || 333 datalen != sargs->sa_datalen) { 334 ret = EINVAL; 335 goto out; 336 } 337 338 pid = __spawn(path, sparam, sparam != NULL ? sparam->sp_size : 0, 339 sargs, sargs->sa_size); 340 341 if (pid == -1) { 342 ret = errno; 343 goto out; 344 } 345 346 if (pidp != NULL) 347 *pidp = pid; 348 349 out: 350 if (sparam != NULL) 351 lfree(sparam, sparam->sp_size); 352 if (sargs != NULL) 353 lfree(sargs, sargs->sa_size); 354 return (ret); 355 } 356 357 int 358 posix_spawn(pid_t *pidp, const char *path, 359 const posix_spawn_file_actions_t *file_actions, 360 const posix_spawnattr_t *attrp, char *const *argp, char *const *envp) 361 { 362 return (posix_spawn_common(pidp, path, file_actions, attrp, 363 argp, envp, NULL, NULL)); 364 } 365 366 int 367 posix_spawnp(pid_t *pidp, const char *file, 368 const posix_spawn_file_actions_t *file_actions, 369 const posix_spawnattr_t *attrp, char *const *argp, char *const *envp) 370 { 371 const char *pathstr = 372 (strchr(file, '/') == NULL) ? getenv("PATH") : ""; 373 374 if (*file == '\0') 375 return (EACCES); 376 377 if (pathstr == NULL) { 378 /* 379 * XPG4: pathstr is equivalent to _CS_PATH, except that 380 * :/usr/sbin is appended when root, and pathstr must end 381 * with a colon when not root. Keep these paths in sync 382 * with _CS_PATH in confstr.c. Note that pathstr must end 383 * with a colon when not root so that when file doesn't 384 * contain '/', the last attempt will be to exec the file 385 * from the current directory. 386 */ 387 if (geteuid() == 0 || getuid() == 0) { 388 if (!libc__xpg4) { 389 pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin"; 390 } else { 391 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 392 "/usr/bin:/opt/SUNWspro/bin:/usr/sbin"; 393 } 394 } else { 395 if (!libc__xpg4) { 396 pathstr = "/usr/ccs/bin:/usr/bin:"; 397 } else { 398 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 399 "/usr/bin:/opt/SUNWspro/bin:"; 400 } 401 } 402 } 403 404 return (posix_spawn_common(pidp, file, file_actions, attrp, 405 argp, envp, _PATH_BSHELL, pathstr)); 406 } 407 408 int 409 posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions) 410 { 411 file_actions->__file_attrp = NULL; 412 return (0); 413 } 414 415 int 416 posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions) 417 { 418 file_attr_t *froot = file_actions->__file_attrp; 419 file_attr_t *fap; 420 file_attr_t *next; 421 422 if ((fap = froot) != NULL) { 423 do { 424 next = fap->fa_next; 425 if (fap->fa_type == FA_OPEN || fap->fa_type == FA_CHDIR) 426 lfree(fap->fa_path, fap->fa_pathsize); 427 lfree(fap, sizeof (*fap)); 428 } while ((fap = next) != froot); 429 } 430 file_actions->__file_attrp = NULL; 431 return (0); 432 } 433 434 static void 435 add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap) 436 { 437 file_attr_t *froot = file_actions->__file_attrp; 438 439 if (froot == NULL) { 440 fap->fa_next = fap->fa_prev = fap; 441 file_actions->__file_attrp = froot = fap; 442 } else { 443 fap->fa_next = froot; 444 fap->fa_prev = froot->fa_prev; 445 froot->fa_prev->fa_next = fap; 446 froot->fa_prev = fap; 447 } 448 } 449 450 int 451 posix_spawn_file_actions_addopen( 452 posix_spawn_file_actions_t *restrict file_actions, 453 int filedes, const char *restrict path, int oflag, mode_t mode) 454 { 455 file_attr_t *fap; 456 457 if (filedes < 0) 458 return (EBADF); 459 if ((fap = lmalloc(sizeof (*fap))) == NULL) 460 return (ENOMEM); 461 462 fap->fa_pathsize = strlen(path) + 1; 463 if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) { 464 lfree(fap, sizeof (*fap)); 465 return (ENOMEM); 466 } 467 (void) memcpy(fap->fa_path, path, fap->fa_pathsize); 468 469 fap->fa_type = FA_OPEN; 470 fap->fa_oflag = oflag; 471 fap->fa_mode = mode; 472 fap->fa_filedes = filedes; 473 add_file_attr(file_actions, fap); 474 475 return (0); 476 } 477 478 int 479 posix_spawn_file_actions_addclose( 480 posix_spawn_file_actions_t *restrict file_actions, int filedes) 481 { 482 file_attr_t *fap; 483 484 if (filedes < 0) 485 return (EBADF); 486 if ((fap = lmalloc(sizeof (*fap))) == NULL) 487 return (ENOMEM); 488 489 fap->fa_type = FA_CLOSE; 490 fap->fa_filedes = filedes; 491 add_file_attr(file_actions, fap); 492 493 return (0); 494 } 495 496 int 497 posix_spawn_file_actions_adddup2( 498 posix_spawn_file_actions_t *restrict file_actions, 499 int filedes, int newfiledes) 500 { 501 file_attr_t *fap; 502 503 if (filedes < 0 || newfiledes < 0) 504 return (EBADF); 505 if ((fap = lmalloc(sizeof (*fap))) == NULL) 506 return (ENOMEM); 507 508 fap->fa_type = FA_DUP2; 509 fap->fa_filedes = filedes; 510 fap->fa_newfiledes = newfiledes; 511 add_file_attr(file_actions, fap); 512 513 return (0); 514 } 515 516 int 517 posix_spawn_file_actions_addclosefrom_np( 518 posix_spawn_file_actions_t *restrict file_actions, int lowfiledes) 519 { 520 file_attr_t *fap; 521 522 if (lowfiledes < 0) 523 return (EBADF); 524 if ((fap = lmalloc(sizeof (*fap))) == NULL) 525 return (ENOMEM); 526 fap->fa_type = FA_CLOSEFROM; 527 fap->fa_filedes = lowfiledes; 528 add_file_attr(file_actions, fap); 529 530 return (0); 531 } 532 533 int 534 posix_spawn_file_actions_addchdir( 535 posix_spawn_file_actions_t *restrict file_actions, 536 const char *restrict path) 537 { 538 file_attr_t *fap; 539 540 if ((fap = lmalloc(sizeof (*fap))) == NULL) 541 return (ENOMEM); 542 543 fap->fa_pathsize = strlen(path) + 1; 544 if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) { 545 lfree(fap, sizeof (*fap)); 546 return (ENOMEM); 547 } 548 (void) memcpy(fap->fa_path, path, fap->fa_pathsize); 549 550 fap->fa_type = FA_CHDIR; 551 add_file_attr(file_actions, fap); 552 553 return (0); 554 } 555 556 int 557 posix_spawn_file_actions_addchdir_np( 558 posix_spawn_file_actions_t *restrict file_actions, 559 const char *restrict path) 560 { 561 return (posix_spawn_file_actions_addchdir(file_actions, path)); 562 } 563 564 int 565 posix_spawn_file_actions_addfchdir( 566 posix_spawn_file_actions_t *restrict file_actions, int fd) 567 { 568 file_attr_t *fap; 569 570 if (fd < 0) 571 return (EBADF); 572 if ((fap = lmalloc(sizeof (*fap))) == NULL) 573 return (ENOMEM); 574 fap->fa_type = FA_FCHDIR; 575 fap->fa_filedes = fd; 576 add_file_attr(file_actions, fap); 577 return (0); 578 } 579 580 int 581 posix_spawn_file_actions_addfchdir_np( 582 posix_spawn_file_actions_t *restrict file_actions, int fd) 583 { 584 return (posix_spawn_file_actions_addfchdir(file_actions, fd)); 585 } 586 587 int 588 posix_spawnattr_init(posix_spawnattr_t *attr) 589 { 590 spawn_attr_t *sap; 591 592 if ((sap = lmalloc(sizeof (*sap))) == NULL) 593 return (ENOMEM); 594 595 attr->__spawn_attrp = sap; 596 597 /* 598 * Add default stuff here? 599 */ 600 return (0); 601 } 602 603 int 604 posix_spawnattr_destroy(posix_spawnattr_t *attr) 605 { 606 spawn_attr_t *sap = attr->__spawn_attrp; 607 608 if (sap == NULL) 609 return (EINVAL); 610 611 /* 612 * deallocate stuff here? 613 */ 614 lfree(sap, sizeof (*sap)); 615 attr->__spawn_attrp = NULL; 616 return (0); 617 } 618 619 int 620 posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags) 621 { 622 spawn_attr_t *sap = attr->__spawn_attrp; 623 624 if (sap == NULL || 625 (flags & ~ALL_POSIX_SPAWN_FLAGS)) 626 return (EINVAL); 627 628 sap->sa_psflags = flags; 629 return (0); 630 } 631 632 int 633 posix_spawnattr_getflags(const posix_spawnattr_t *attr, short *flags) 634 { 635 spawn_attr_t *sap = attr->__spawn_attrp; 636 637 if (sap == NULL) 638 return (EINVAL); 639 640 *flags = sap->sa_psflags; 641 return (0); 642 } 643 644 int 645 posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup) 646 { 647 spawn_attr_t *sap = attr->__spawn_attrp; 648 649 if (sap == NULL) 650 return (EINVAL); 651 652 sap->sa_pgroup = pgroup; 653 return (0); 654 } 655 656 int 657 posix_spawnattr_getpgroup(const posix_spawnattr_t *attr, pid_t *pgroup) 658 { 659 spawn_attr_t *sap = attr->__spawn_attrp; 660 661 if (sap == NULL) 662 return (EINVAL); 663 664 *pgroup = sap->sa_pgroup; 665 return (0); 666 } 667 668 int 669 posix_spawnattr_setschedparam(posix_spawnattr_t *attr, 670 const struct sched_param *schedparam) 671 { 672 spawn_attr_t *sap = attr->__spawn_attrp; 673 674 if (sap == NULL) 675 return (EINVAL); 676 677 /* 678 * Check validity? 679 */ 680 sap->sa_priority = schedparam->sched_priority; 681 return (0); 682 } 683 684 int 685 posix_spawnattr_getschedparam(const posix_spawnattr_t *attr, 686 struct sched_param *schedparam) 687 { 688 spawn_attr_t *sap = attr->__spawn_attrp; 689 690 if (sap == NULL) 691 return (EINVAL); 692 693 schedparam->sched_priority = sap->sa_priority; 694 return (0); 695 } 696 697 int 698 posix_spawnattr_setschedpolicy(posix_spawnattr_t *attr, int schedpolicy) 699 { 700 spawn_attr_t *sap = attr->__spawn_attrp; 701 702 if (sap == NULL || schedpolicy == SCHED_SYS) 703 return (EINVAL); 704 705 /* 706 * Cache the policy information for later use by posix_spawn(). 707 */ 708 if (get_info_by_policy(schedpolicy) == NULL) 709 return (errno); 710 711 sap->sa_schedpolicy = schedpolicy; 712 return (0); 713 } 714 715 int 716 posix_spawnattr_getschedpolicy(const posix_spawnattr_t *attr, int *schedpolicy) 717 { 718 spawn_attr_t *sap = attr->__spawn_attrp; 719 720 if (sap == NULL) 721 return (EINVAL); 722 723 *schedpolicy = sap->sa_schedpolicy; 724 return (0); 725 } 726 727 int 728 posix_spawnattr_setsigdefault(posix_spawnattr_t *attr, 729 const sigset_t *sigdefault) 730 { 731 spawn_attr_t *sap = attr->__spawn_attrp; 732 733 if (sap == NULL) 734 return (EINVAL); 735 736 sap->sa_sigdefault = *sigdefault; 737 return (0); 738 } 739 740 int 741 posix_spawnattr_getsigdefault(const posix_spawnattr_t *attr, 742 sigset_t *sigdefault) 743 { 744 spawn_attr_t *sap = attr->__spawn_attrp; 745 746 if (sap == NULL) 747 return (EINVAL); 748 749 *sigdefault = sap->sa_sigdefault; 750 return (0); 751 } 752 753 int 754 posix_spawnattr_setsigignore_np(posix_spawnattr_t *attr, 755 const sigset_t *sigignore) 756 { 757 spawn_attr_t *sap = attr->__spawn_attrp; 758 759 if (sap == NULL) 760 return (EINVAL); 761 762 sap->sa_sigignore = *sigignore; 763 return (0); 764 } 765 766 int 767 posix_spawnattr_getsigignore_np(const posix_spawnattr_t *attr, 768 sigset_t *sigignore) 769 { 770 spawn_attr_t *sap = attr->__spawn_attrp; 771 772 if (sap == NULL) 773 return (EINVAL); 774 775 *sigignore = sap->sa_sigignore; 776 return (0); 777 } 778 779 int 780 posix_spawnattr_setsigmask(posix_spawnattr_t *attr, 781 const sigset_t *sigmask) 782 { 783 spawn_attr_t *sap = attr->__spawn_attrp; 784 785 if (sap == NULL) 786 return (EINVAL); 787 788 sap->sa_sigmask = *sigmask; 789 return (0); 790 } 791 792 int 793 posix_spawnattr_getsigmask(const posix_spawnattr_t *attr, 794 sigset_t *sigmask) 795 { 796 spawn_attr_t *sap = attr->__spawn_attrp; 797 798 if (sap == NULL) 799 return (EINVAL); 800 801 *sigmask = sap->sa_sigmask; 802 return (0); 803 } 804 805 /* 806 * Spawn a process to run "sh -c <cmd>". Return the child's pid (in 807 * *pidp), and a file descriptor (in *fdp) for reading or writing to the 808 * child process, depending on the 'write' argument. 809 * Return 0 on success; otherwise return an error code. 810 */ 811 int 812 posix_spawn_pipe_np(pid_t *pidp, int *fdp, 813 const char *cmd, boolean_t write, 814 posix_spawn_file_actions_t *fact, posix_spawnattr_t *attr) 815 { 816 int p[2]; 817 int myside, yourside, stdio; 818 const char *shpath = _PATH_BSHELL; 819 const char *argvec[4] = { "sh", "-c", cmd, NULL }; 820 int error; 821 822 if (pipe(p) < 0) 823 return (errno); 824 825 if (access(shpath, X_OK)) /* XPG4 Requirement: */ 826 shpath = ""; /* force child to fail immediately */ 827 828 if (write) { 829 /* 830 * Data is read from p[0] and written to p[1]. 831 * 'stdio' is the fd in the child process that should be 832 * connected to the pipe. 833 */ 834 myside = p[1]; 835 yourside = p[0]; 836 stdio = STDIN_FILENO; 837 } else { 838 myside = p[0]; 839 yourside = p[1]; 840 stdio = STDOUT_FILENO; 841 } 842 843 error = posix_spawn_file_actions_addclose(fact, myside); 844 if (yourside != stdio) { 845 if (error == 0) { 846 error = posix_spawn_file_actions_adddup2(fact, 847 yourside, stdio); 848 } 849 if (error == 0) { 850 error = posix_spawn_file_actions_addclose(fact, 851 yourside); 852 } 853 } 854 855 if (error) 856 return (error); 857 error = posix_spawn(pidp, shpath, fact, attr, 858 (char *const *)argvec, (char *const *)_environ); 859 (void) close(yourside); 860 if (error) { 861 (void) close(myside); 862 return (error); 863 } 864 865 *fdp = myside; 866 return (0); 867 } 868