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