1/* 2 * Copyright (c) 2006-2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * [SPN] Support for _POSIX_SPAWN 26 */ 27 28#define CONFIG_MEMORYSTATUS 1 // <rdar://problem/13604997> 29#include <sys/types.h> /* for user_size_t */ 30#include <spawn.h> 31#include <spawn_private.h> 32#include <sys/spawn_internal.h> 33#include <sys/process_policy.h> 34#include <stdlib.h> 35#include <errno.h> 36#include <limits.h> /* for OPEN_MAX, PATH_MAX */ 37#include <string.h> 38#include <strings.h> 39#include <mach/port.h> 40#include <mach/exception_types.h> 41 42#if TARGET_OS_EMBEDDED 43#include <sys/kern_memorystatus.h> 44#endif 45 46/* 47 * posix_spawnattr_init 48 * 49 * Description: Initialize a spawn attributes object attr with default values 50 * 51 * Parameters: attr The spawn attributes object to be 52 * initialized 53 * 54 * Returns: 0 Success 55 * ENOMEM Insufficient memory exists to 56 * initialize the spawn attributes object. 57 * 58 * Note: As an implementation detail, the externally visibily type 59 * posix_spawnattr_t is defined to be a void *, and initialization 60 * involves allocation of a memory object. Subsequent changes to 61 * the spawn attributes may result in reallocation under the 62 * covers. 63 * 64 * Reinitialization of an already initialized spawn attributes 65 * object will result in memory being leaked. Because spawn 66 * attributes are not required to be used in conjunction with a 67 * static initializer, there is no way to distinguish a spawn 68 * attribute with stack garbage from one that's been initialized. 69 * This is arguably an API design error. 70 */ 71int 72posix_spawnattr_init(posix_spawnattr_t *attr) 73{ 74 _posix_spawnattr_t *psattrp = (_posix_spawnattr_t *)attr; 75 int err = 0; 76 77 if ((*psattrp = (_posix_spawnattr_t)malloc(sizeof(struct _posix_spawnattr))) == NULL) { 78 err = ENOMEM; 79 } else { 80 81 /* 82 * The default value of this attribute shall be as if no 83 * flags were set 84 */ 85 (*psattrp)->psa_flags = 0; 86 87 /* 88 * The default value of this attribute shall be an empty 89 * signal set 90 */ 91 (*psattrp)->psa_sigdefault = 0; 92 93 /* The default value of this attribute is unspecified */ 94 (*psattrp)->psa_sigmask = 0; 95 96 /* The default value of this attribute shall be zero */ 97 (*psattrp)->psa_pgroup = 0; /* doesn't matter */ 98 99 /* Default is no binary preferences, i.e. use normal grading */ 100 memset((*psattrp)->psa_binprefs, 0, 101 sizeof((*psattrp)->psa_binprefs)); 102 103 /* Default is no port actions to take */ 104 (*psattrp)->psa_ports = NULL; 105 106 /* 107 * The default value of this attribute shall be an no 108 * process control on resource starvation 109 */ 110 (*psattrp)->psa_pcontrol = 0; 111 112 /* 113 * Initializing the alignment paddings. 114 */ 115 116 (*psattrp)->short_padding = 0; 117 (*psattrp)->flags_padding = 0; 118 (*psattrp)->int_padding = 0; 119 120 121 /* 122 * The default value of this attribute shall be an no 123 * process control on resource starvation 124 */ 125 (*psattrp)->psa_apptype = 0; 126 127 /* Jetsam related */ 128 (*psattrp)->psa_jetsam_flags = 0; 129 (*psattrp)->psa_priority = -1; 130 (*psattrp)->psa_high_water_mark = -1; 131 132 /* Default is no CPU usage monitor active. */ 133 (*psattrp)->psa_cpumonitor_percent = 0; 134 (*psattrp)->psa_cpumonitor_interval = 0; 135 136 /* Default is no MAC policy extensions. */ 137 (*psattrp)->psa_mac_extensions = NULL; 138 } 139 140 return (err); 141} 142 143 144/* 145 * posix_spawnattr_destroy 146 * 147 * Description: Destroy a spawn attributes object that was previously 148 * initialized via posix_spawnattr_init() by freeing any 149 * memory associated with it and setting it to an invalid value. 150 * 151 * Parameters: attr The spawn attributes object to be 152 * destroyed. 153 * 154 * Returns: 0 Success 155 * 156 * Notes: The destroyed spawn attribute results in the void * pointer 157 * being set to NULL; subsequent use without reinitialization 158 * will result in explicit program failure (rather than merely 159 * "undefined behaviour"). 160 * 161 * NOTIMP: Allowed failures (checking NOT required): 162 * EINVAL The value specified by attr is invalid. 163 */ 164static int posix_spawn_destroyportactions_np(posix_spawnattr_t *); 165 166int 167posix_spawnattr_destroy(posix_spawnattr_t *attr) 168{ 169 _posix_spawnattr_t psattr; 170 171 if (attr == NULL || *attr == NULL) 172 return EINVAL; 173 174 psattr = *(_posix_spawnattr_t *)attr; 175 posix_spawn_destroyportactions_np(attr); 176 177 free(psattr); 178 *attr = NULL; 179 180 return (0); 181} 182 183 184/* 185 * posix_spawnattr_setflags 186 * 187 * Description: Set the spawn flags attribute for the spawn attribute object 188 * referred to by 'attr'. 189 * 190 * Parameters: attr The spawn attributes object whose flags 191 * are to be set 192 * flags The flags value to set 193 * 194 * Returns: 0 Success 195 * 196 * NOTIMP: Allowed failures (checking NOT required): 197 * EINVAL The value specified by attr is invalid. 198 * EINVAL The value of the attribute being set is not valid. 199 */ 200int 201posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags) 202{ 203 _posix_spawnattr_t psattr; 204 205 if (attr == NULL || *attr == NULL) 206 return EINVAL; 207 208 psattr = *(_posix_spawnattr_t *)attr; 209 psattr->psa_flags = flags; 210 211 return (0); 212} 213 214 215/* 216 * posix_spawnattr_getflags 217 * 218 * Description: Retrieve the spawn attributes flag for the spawn attributes 219 * object referenced by 'attr' and place them in the memory 220 * location referenced by 'flagsp' 221 * 222 * Parameters: attr The spawn attributes object whose flags 223 * are to be retrieved 224 * flagsp A pointer to a short value to receive 225 * the flags 226 * 227 * Returns: 0 Success 228 * 229 * Implicit Returns: 230 * *flagps (modified) The flags value from the spawn 231 * attributes object 232 * 233 * NOTIMP: Allowed failures (checking NOT required): 234 * EINVAL The value specified by attr is invalid. 235 * EINVAL The value of the attribute being set is not valid. 236 */ 237int 238posix_spawnattr_getflags(const posix_spawnattr_t * __restrict attr, 239 short * __restrict flagsp) 240{ 241 _posix_spawnattr_t psattr; 242 243 if (attr == NULL || *attr == NULL) 244 return EINVAL; 245 246 psattr = *(_posix_spawnattr_t *)attr; 247 *flagsp = psattr->psa_flags; 248 249 return (0); 250} 251 252 253/* 254 * posix_spawnattr_getsigdefault 255 * 256 * Description: Retrieve the set of signals to be set to default according to 257 * the spawn attribute value referenced by 'attr' and place the 258 * result into the memory containing the sigset_t referenced by 259 * 'sigdefault' 260 * 261 * Parameters: attr The spawn attributes object whose 262 * signal set for default signals is to 263 * be retrieved 264 * sigdefault A pointer to the sigset_t to receive 265 * the signal set 266 * 267 * Returns: 0 Success 268 * 269 * Implicit Returns: 270 * *sigdefault (modified) The signal set of signals to default 271 * from the spawn attributes object 272 */ 273int 274posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict attr, 275 sigset_t * __restrict sigdefault) 276{ 277 _posix_spawnattr_t psattr; 278 279 if (attr == NULL || *attr == NULL) 280 return EINVAL; 281 282 psattr = *(_posix_spawnattr_t *)attr; 283 *sigdefault = psattr->psa_sigdefault; 284 285 return (0); 286} 287 288 289/* 290 * posix_spawnattr_getpgroup 291 * 292 * Description: Obtain the value of the spawn process group attribute from the 293 * spawn attributes object referenced by 'attr' and place the 294 * results in the memory location referenced by 'pgroup' 295 * 296 * Parameters: attr The spawn attributes object whose 297 * process group information is to be 298 * retrieved 299 * pgroup A pointer to the pid_t to receive the 300 * process group 301 * 302 * Returns: 0 Success 303 * 304 * Implicit Returns: 305 * *pgroup (modified) The process group information from the 306 * spawn attributes object 307 */ 308int 309posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict attr, 310 pid_t * __restrict pgroup) 311{ 312 _posix_spawnattr_t psattr; 313 314 if (attr == NULL || *attr == NULL) 315 return EINVAL; 316 317 psattr = *(_posix_spawnattr_t *)attr; 318 *pgroup = psattr->psa_pgroup; 319 320 return (0); 321} 322 323 324/* 325 * posix_spawnattr_getsigmask 326 * 327 * Description: Obtain the value of the spawn signal mask attribute from the 328 * spawn attributes object referenced by 'attr' and place the 329 * result into the memory containing the sigset_t referenced by 330 * 'sigmask' 331 * 332 * Parameters: attr The spawn attributes object whose 333 * signal set for masked signals is to 334 * be retrieved 335 * sigmask A pointer to the sigset_t to receive 336 * the signal set 337 * 338 * Returns: 0 Success 339 * 340 * Implicit Returns: 341 * *sigmask (modified) The signal set of signals to mask 342 * from the spawn attributes object 343 */ 344int 345posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict attr, 346 sigset_t * __restrict sigmask) 347{ 348 _posix_spawnattr_t psattr; 349 350 if (attr == NULL || *attr == NULL) 351 return EINVAL; 352 353 psattr = *(_posix_spawnattr_t *)attr; 354 *sigmask = psattr->psa_sigmask; 355 356 return (0); 357} 358 359/* 360 * posix_spawnattr_getbinpref_np 361 * 362 * Description: Obtain the value of the spawn binary preferences attribute from 363 * the spawn attributes object referenced by 'attr' and place the 364 * result into the memory referenced by 'pref'. 365 * 366 * Parameters: attr The spawn attributes object whose 367 * binary preferences are to be retrieved 368 * count The size of the cpu_type_t array 369 * pref An array of cpu types 370 * ocount The actual number copied 371 * 372 * Returns: 0 No binary preferences found 373 * > 0 The number of cpu types (less than 374 * count) copied over from 'attr'. 375 * 376 * Implicit Returns: 377 * *pref (modified) The binary preferences array 378 * from the spawn attributes object 379 */ 380int 381posix_spawnattr_getbinpref_np(const posix_spawnattr_t * __restrict attr, 382 size_t count, cpu_type_t *pref, size_t * __restrict ocount) 383{ 384 _posix_spawnattr_t psattr; 385 int i = 0; 386 387 if (attr == NULL || *attr == NULL) 388 return EINVAL; 389 390 psattr = *(_posix_spawnattr_t *)attr; 391 for (i = 0; i < count && i < 4; i++) { 392 pref[i] = psattr->psa_binprefs[i]; 393 } 394 395 if (ocount) 396 *ocount = i; 397 return 0; 398} 399 400 401/* 402 * posix_spawnattr_getpcontrol_np 403 * 404 * Description: Retrieve the process control property set default according to 405 * the spawn attribute value referenced by 'attr' and place the 406 * result into the memory containing the control referenced by 407 * 'pcontrol' 408 * 409 * Parameters: attr The spawn attributes object whose 410 * signal set for default signals is to 411 * be retrieved 412 * pcontrol A pointer to an int to receive 413 * the process control info 414 * 415 * Returns: 0 Success 416 * 417 * Implicit Returns: 418 * *pcontrol (modified) The signal set of signals to default 419 * from the spawn attributes object 420 */ 421int 422posix_spawnattr_getpcontrol_np(const posix_spawnattr_t * __restrict attr, 423 int * __restrict pcontrol) 424{ 425 _posix_spawnattr_t psattr; 426 427 if (attr == NULL || *attr == NULL) 428 return EINVAL; 429 430 psattr = *(_posix_spawnattr_t *)attr; 431 *pcontrol = psattr->psa_pcontrol; 432 433 return (0); 434} 435 436/* 437 * posix_spawnattr_getprocesstype_np 438 * 439 * Description: Retrieve the process specific behaviors and app launch types 440 * spawn attribute value referenced by 'attr' and place the 441 * result into the memory containing the control referenced by 442 * 'proctype' 443 * 444 * Parameters: attr The spawn attributes object whose 445 * signal set for default signals is to 446 * be retrieved 447 * proctype A pointer to an int to receive 448 * the process type info 449 * 450 * Returns: 0 Success 451 * 452 * Implicit Returns: 453 * *proctype (modified) The process type set to value 454 * from the spawn attributes object 455 */ 456int 457posix_spawnattr_getprocesstype_np(const posix_spawnattr_t * __restrict attr, 458 int * __restrict proctype) 459{ 460 _posix_spawnattr_t psattr; 461 462 if (attr == NULL || *attr == NULL) 463 return EINVAL; 464 465 psattr = *(_posix_spawnattr_t *)attr; 466 *proctype = psattr->psa_apptype; 467 468 return (0); 469} 470/* 471 * posix_spawnattr_setsigdefault 472 * 473 * Description: Set the set of signals to be set to default for the spawn 474 * attribute value referenced by 'attr' from the memory 475 * containing the sigset_t referenced by 'sigdefault' 476 * 477 * Parameters: attr The spawn attributes object whose 478 * signal set for default signals is to 479 * be set 480 * sigdefault A pointer to the sigset_t from which to 481 * obtain the signal set 482 * 483 * Returns: 0 Success 484 */ 485int 486posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict attr, 487 const sigset_t * __restrict sigdefault) 488{ 489 _posix_spawnattr_t psattr; 490 491 if (attr == NULL || *attr == NULL) 492 return EINVAL; 493 494 psattr = *(_posix_spawnattr_t *)attr; 495 psattr->psa_sigdefault = *sigdefault; 496 497 return (0); 498} 499 500 501/* 502 * posix_spawnattr_setpgroup 503 * 504 * Description: Set the value of the spawn process group attribute for the 505 * spawn attributes object referenced by 'attr' from the value 506 * of 'pgroup' 507 * 508 * Parameters: attr The spawn attributes object for which 509 * the process group information is to be 510 * set 511 * pgroup The process group to set 512 * 513 * Returns: 0 Success 514 */ 515int 516posix_spawnattr_setpgroup(posix_spawnattr_t * attr, pid_t pgroup) 517{ 518 _posix_spawnattr_t psattr; 519 520 if (attr == NULL || *attr == NULL) 521 return EINVAL; 522 523 psattr = *(_posix_spawnattr_t *)attr; 524 psattr->psa_pgroup = pgroup; 525 526 return (0); 527} 528 529 530/* 531 * posix_spawnattr_setsigmask 532 * 533 * Description: Set the set of signals to be masked for the spawn attribute 534 * value referenced by 'attr' from the memory containing the 535 * sigset_t referenced by 'sigmask' 536 * 537 * Parameters: attr The spawn attributes object whose 538 * signal set for masked signals is to 539 * be set 540 * sigmask A pointer to the sigset_t from which to 541 * obtain the signal set 542 * 543 * Returns: 0 Success 544 */ 545int 546posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict attr, 547 const sigset_t * __restrict sigmask) 548{ 549 _posix_spawnattr_t psattr; 550 551 if (attr == NULL || *attr == NULL) 552 return EINVAL; 553 554 psattr = *(_posix_spawnattr_t *)attr; 555 psattr->psa_sigmask = *sigmask; 556 557 return (0); 558} 559 560 561/* 562 * posix_spawnattr_setbinpref_np 563 * 564 * Description: Set the universal binary preferences for the spawn attribute 565 * value referenced by 'attr' from the memory containing the 566 * cpu_type_t array referenced by 'pref', size of 'count' 567 * 568 * Parameters: attr The spawn attributes object whose 569 * binary preferences are to be set 570 * count Size of the array pointed to by 'pref' 571 * pref cpu_type_t array of binary preferences 572 * ocount The actual number copied 573 * 574 * Returns: 0 No preferences copied 575 * > 0 Number of preferences copied 576 * 577 * Note: The posix_spawnattr_t currently only holds four cpu_type_t's. 578 * If the caller provides more preferences than this limit, they 579 * will be ignored, as reflected in the return value. 580 */ 581int 582posix_spawnattr_setbinpref_np(posix_spawnattr_t * __restrict attr, 583 size_t count, cpu_type_t *pref, size_t * __restrict ocount) 584{ 585 _posix_spawnattr_t psattr; 586 int i = 0; 587 588 if (attr == NULL || *attr == NULL) 589 return EINVAL; 590 591 psattr = *(_posix_spawnattr_t *)attr; 592 for (i = 0; i < count && i < 4; i++) { 593 psattr->psa_binprefs[i] = pref[i]; 594 } 595 596 /* return number of binprefs copied over */ 597 if (ocount) 598 *ocount = i; 599 return 0; 600} 601 602 603/* 604 * posix_spawnattr_setpcontrol_np 605 * 606 * Description: Set the process control property according to 607 * attribute value referenced by 'attr' from the memory 608 * containing the int value 'pcontrol' 609 * 610 * Parameters: attr The spawn attributes object whose 611 * signal set for default signals is to 612 * be set 613 * pcontrol An int value of the process control info 614 * 615 * Returns: 0 Success 616 */ 617int 618posix_spawnattr_setpcontrol_np(posix_spawnattr_t * __restrict attr, 619 const int pcontrol) 620{ 621 _posix_spawnattr_t psattr; 622 623 if (attr == NULL || *attr == NULL) 624 return EINVAL; 625 626 psattr = *(_posix_spawnattr_t *)attr; 627 psattr->psa_pcontrol = pcontrol; 628 629 return (0); 630} 631 632 633/* 634 * posix_spawnattr_setprocesstype_np 635 * 636 * Description: Set the process specific behaviors and app launch type 637 * attribute value referenced by 'attr' from the memory 638 * containing the int value 'proctype' 639 * 640 * Parameters: attr The spawn attributes object whose 641 * signal set for default signals is to 642 * be set 643 * proctype An int value of the process type info 644 * 645 * Returns: 0 Success 646 */ 647int 648posix_spawnattr_setprocesstype_np(posix_spawnattr_t * __restrict attr, 649 const int proctype) 650{ 651 _posix_spawnattr_t psattr; 652 653 if (attr == NULL || *attr == NULL) 654 return EINVAL; 655 656 psattr = *(_posix_spawnattr_t *)attr; 657 psattr->psa_apptype = proctype; 658 659 return (0); 660} 661 662/* 663 * posix_spawn_createportactions_np 664 * Description: create a new posix_spawn_port_actions struct and link 665 * it into the posix_spawnattr. 666 */ 667static int 668posix_spawn_createportactions_np(posix_spawnattr_t *attr) 669{ 670 _posix_spawnattr_t psattr; 671 _posix_spawn_port_actions_t acts; 672 673 if (attr == NULL || *attr == NULL) 674 return EINVAL; 675 676 psattr = *(_posix_spawnattr_t *)attr; 677 acts = (_posix_spawn_port_actions_t)malloc(PS_PORT_ACTIONS_SIZE(2)); 678 if (acts == NULL) 679 return ENOMEM; 680 681 acts->pspa_alloc = 2; 682 acts->pspa_count = 0; 683 684 psattr->psa_ports = acts; 685 return 0; 686} 687 688/* 689 * posix_spawn_growportactions_np 690 * Description: Enlarge the size of portactions if necessary 691 */ 692static int 693posix_spawn_growportactions_np(posix_spawnattr_t *attr) 694{ 695 _posix_spawnattr_t psattr; 696 _posix_spawn_port_actions_t acts; 697 int newnum; 698 699 if (attr == NULL || *attr == NULL) 700 return EINVAL; 701 702 psattr = *(_posix_spawnattr_t *)attr; 703 acts = psattr->psa_ports; 704 if (acts == NULL) 705 return EINVAL; 706 707 /* Double number of port actions allocated for */ 708 newnum = 2 * acts->pspa_alloc; 709 acts = realloc(acts, PS_PORT_ACTIONS_SIZE(newnum)); 710 if (acts == NULL) 711 return ENOMEM; 712 713 acts->pspa_alloc = newnum; 714 psattr->psa_ports = acts; 715 return 0; 716} 717 718/* 719 * posix_spawn_destroyportactions_np 720 * Description: clean up portactions struct in posix_spawnattr_t attr 721 */ 722static int 723posix_spawn_destroyportactions_np(posix_spawnattr_t *attr) 724{ 725 _posix_spawnattr_t psattr; 726 _posix_spawn_port_actions_t acts; 727 728 if (attr == NULL || *attr == NULL) 729 return EINVAL; 730 731 psattr = *(_posix_spawnattr_t *)attr; 732 acts = psattr->psa_ports; 733 if (acts == NULL) 734 return EINVAL; 735 736 free(acts); 737 return 0; 738} 739 740/* 741 * posix_spawn_appendportaction_np 742 * Description: append a port action, grow the array if necessary 743 */ 744static int 745posix_spawn_appendportaction_np(posix_spawnattr_t *attr, _ps_port_action_t *act) 746{ 747 _posix_spawnattr_t psattr; 748 _posix_spawn_port_actions_t acts; 749 750 if (attr == NULL || *attr == NULL || act == NULL) { 751 return EINVAL; 752 } 753 754 psattr = *(_posix_spawnattr_t *)attr; 755 acts = psattr->psa_ports; 756 757 // Have any port actions been created yet? 758 if (acts == NULL) { 759 int err = posix_spawn_createportactions_np(attr); 760 if (err) { 761 return err; 762 } 763 acts = psattr->psa_ports; 764 } 765 766 // Is there enough room? 767 if (acts->pspa_alloc == acts->pspa_count) { 768 int err = posix_spawn_growportactions_np(attr); 769 if (err) { 770 return err; 771 } 772 acts = psattr->psa_ports; 773 } 774 775 // Add this action to next spot in array 776 acts->pspa_actions[acts->pspa_count] = *act; 777 acts->pspa_count++; 778 779 return 0; 780} 781 782/* 783 * posix_spawnattr_setspecialport_np 784 * 785 * Description: Set a new value for a mach special port in the spawned task. 786 * 787 * Parameters: attr The spawn attributes object for the 788 * new process 789 * new_port The new value for the special port 790 * which The particular port to be set 791 * (see task_set_special_port for details) 792 * 793 * Returns: 0 Success 794 * ENOMEM Couldn't allocate memory 795 */ 796int 797posix_spawnattr_setspecialport_np( 798 posix_spawnattr_t *attr, 799 mach_port_t new_port, 800 int which) 801{ 802 _ps_port_action_t action = { 803 .port_type = PSPA_SPECIAL, 804 .new_port = new_port, 805 .which = which, 806 }; 807 return posix_spawn_appendportaction_np(attr, &action); 808} 809 810/* 811 * posix_spawnattr_setexceptionports_np 812 * 813 * Description: Set a new port for a set of exception ports in the spawned task. 814 * 815 * Parameters: attr The spawn attributes object for the 816 * new process 817 * mask A bitfield indicating which exceptions 818 * to associate the port with 819 * new_port The new value for the exception port 820 * behavior The default behavior for the port 821 * flavor The default flavor for the port 822 * (see task_set_exception_ports) 823 * 824 * Returns: 0 Success 825 */ 826int 827posix_spawnattr_setexceptionports_np( 828 posix_spawnattr_t *attr, 829 exception_mask_t mask, 830 mach_port_t new_port, 831 exception_behavior_t behavior, 832 thread_state_flavor_t flavor) 833{ 834 _ps_port_action_t action = { 835 .port_type = PSPA_EXCEPTION, 836 .mask = mask, 837 .new_port = new_port, 838 .behavior = behavior, 839 .flavor = flavor, 840 }; 841 return posix_spawn_appendportaction_np(attr, &action); 842} 843 844/* 845 * posix_spawnattr_setauditsessionport_np 846 * 847 * Description: Set the audit session port rights attribute in the spawned task. 848 * This is used to securely set the audit session information for 849 * the new task. 850 * 851 * Parameters: attr The spawn attributes object for the 852 * new process 853 * au_sessionport The audit session send port right 854 * 855 * Returns: 0 Success 856 */ 857int 858posix_spawnattr_setauditsessionport_np( 859 posix_spawnattr_t *attr, 860 mach_port_t au_sessionport) 861{ 862 _ps_port_action_t action = { 863 .port_type = PSPA_AU_SESSION, 864 .new_port = au_sessionport, 865 }; 866 return posix_spawn_appendportaction_np(attr, &action); 867} 868 869 870/* 871 * posix_spawn_file_actions_init 872 * 873 * Description: Initialize a spawn file actions object attr with default values 874 * 875 * Parameters: file_actions The spawn file actions object to be 876 * initialized 877 * 878 * Returns: 0 Success 879 * ENOMEM Insufficient memory exists to 880 * initialize the spawn file actions 881 * object. 882 * 883 * Note: As an implementation detail, the externally visibily type 884 * posix_spawn_file_actions_t is defined to be a void *, and 885 * initialization involves allocation of a memory object. 886 * Subsequent changes to the spawn file actions may result in 887 * reallocation under the covers. 888 * 889 * Reinitialization of an already initialized spawn file actions 890 * object will result in memory being leaked. Because spawn 891 * file actions are not required to be used in conjunction with a 892 * static initializer, there is no way to distinguish a spawn 893 * file actions with stack garbage from one that's been 894 * initialized. This is arguably an API design error. 895 */ 896int 897posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions) 898{ 899 _posix_spawn_file_actions_t *psactsp = (_posix_spawn_file_actions_t *)file_actions; 900 int err = 0; 901 902 if ((*psactsp = (_posix_spawn_file_actions_t)malloc(PSF_ACTIONS_SIZE(PSF_ACTIONS_INIT_COUNT))) == NULL) { 903 err = ENOMEM; 904 } else { 905 (*psactsp)->psfa_act_alloc = PSF_ACTIONS_INIT_COUNT; 906 (*psactsp)->psfa_act_count = 0; 907 } 908 909 return (err); 910} 911 912 913/* 914 * posix_spawn_file_actions_destroy 915 * 916 * Description: Destroy a spawn file actions object that was previously 917 * initialized via posix_spawn_file_actions_init() by freeing any 918 * memory associated with it and setting it to an invalid value. 919 * 920 * Parameters: attr The spawn file actions object to be 921 * destroyed. 922 * 923 * Returns: 0 Success 924 * 925 * Notes: The destroyed spawn file actions results in the void * pointer 926 * being set to NULL; subsequent use without reinitialization 927 * will result in explicit program failure (rather than merely 928 * "undefined behaviour"). 929 * 930 * NOTIMP: Allowed failures (checking NOT required): 931 * EINVAL The value specified by file_actions is invalid. 932 */ 933int 934posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions) 935{ 936 _posix_spawn_file_actions_t psacts; 937 938 if (file_actions == NULL || *file_actions == NULL) 939 return EINVAL; 940 941 psacts = *(_posix_spawn_file_actions_t *)file_actions; 942 free(psacts); 943 *file_actions = NULL; 944 945 return (0); 946} 947 948 949/* 950 * _posix_spawn_file_actions_grow 951 * 952 * Description: Grow the available list of file actions associated with the 953 * pointer to the structure provided; replace the contents of the 954 * pointer as a side effect. 955 * 956 * Parameters: psactsp Pointer to _posix_spawn_file_actions_t 957 * to grow 958 * 959 * Returns: 0 Success 960 * ENOMEM Insufficient memory for operation 961 * 962 * Notes: This code is common to all posix_spawn_file_actions_*() 963 * functions, since we use a naieve data structure implementation 964 * at present. Future optimization will likely change this. 965 */ 966static int 967_posix_spawn_file_actions_grow(_posix_spawn_file_actions_t *psactsp) 968{ 969 int new_alloc = (*psactsp)->psfa_act_alloc * 2; 970 _posix_spawn_file_actions_t new_psacts; 971 972 /* 973 * XXX may want to impose an administrative limit here; POSIX does 974 * XXX not provide for an administrative error return in this case, 975 * XXX so it's probably acceptable to just fail catastrophically 976 * XXX instead of implementing one. 977 */ 978 if ((new_psacts = (_posix_spawn_file_actions_t)realloc((*psactsp), PSF_ACTIONS_SIZE(new_alloc))) == NULL) { 979 return (ENOMEM); 980 } 981 new_psacts->psfa_act_alloc = new_alloc; 982 *psactsp = new_psacts; 983 984 return (0); 985} 986 987 988/* 989 * posix_spawn_file_actions_addopen 990 * 991 * Description: Add an open action to the object referenced by 'file_actions' 992 * that will cause the file named by 'path' to be attempted to be 993 * opened with flags 'oflag' and mode 'mode', and, if successful, 994 * return as descriptor 'filedes' to the spawned process. 995 * 996 * Parameters: file_actions File action object to augment 997 * filedes fd that open is to use 998 * path path to file to open 999 * oflag open file flags 1000 * mode open file mode 1001 * 1002 * Returns: 0 Success 1003 * EBADF The value specified by fildes is 1004 * negative or greater than or equal to 1005 * {OPEN_MAX}. 1006 * ENOMEM Insufficient memory exists to add to 1007 * the spawn file actions object. 1008 * 1009 * NOTIMP: Allowed failures (checking NOT required): 1010 * EINVAL The value specified by file_actions is invalid. 1011 */ 1012int 1013posix_spawn_file_actions_addopen( 1014 posix_spawn_file_actions_t * __restrict file_actions, 1015 int filedes, const char * __restrict path, int oflag, 1016 mode_t mode) 1017{ 1018 _posix_spawn_file_actions_t *psactsp; 1019 _psfa_action_t *psfileact; 1020 1021 if (file_actions == NULL || *file_actions == NULL) 1022 return EINVAL; 1023 1024 psactsp = (_posix_spawn_file_actions_t *)file_actions; 1025 /* Range check; required by POSIX */ 1026 if (filedes < 0 || filedes >= OPEN_MAX) 1027 return (EBADF); 1028 1029 /* If we do not have enough slots, grow the structure */ 1030 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) { 1031 /* need to grow file actions structure */ 1032 if (_posix_spawn_file_actions_grow(psactsp)) 1033 return (ENOMEM); 1034 } 1035 1036 /* 1037 * Allocate next available slot and fill it out 1038 */ 1039 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++]; 1040 1041 psfileact->psfaa_type = PSFA_OPEN; 1042 psfileact->psfaa_filedes = filedes; 1043 psfileact->psfaa_openargs.psfao_oflag = oflag; 1044 psfileact->psfaa_openargs.psfao_mode = mode; 1045 strlcpy(psfileact->psfaa_openargs.psfao_path, path, PATH_MAX); 1046 1047 return (0); 1048} 1049 1050 1051/* 1052 * posix_spawn_file_actions_addclose 1053 * 1054 * Description: Add a close action to the object referenced by 'file_actions' 1055 * that will cause the file referenced by 'filedes' to be 1056 * attempted to be closed in the spawned process. 1057 * 1058 * Parameters: file_actions File action object to augment 1059 * filedes fd to close 1060 * 1061 * Returns: 0 Success 1062 * EBADF The value specified by fildes is 1063 * negative or greater than or equal to 1064 * {OPEN_MAX}. 1065 * ENOMEM Insufficient memory exists to add to 1066 * the spawn file actions object. 1067 * 1068 * NOTIMP: Allowed failures (checking NOT required): 1069 * EINVAL The value specified by file_actions is invalid. 1070 */ 1071int 1072posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, 1073 int filedes) 1074{ 1075 _posix_spawn_file_actions_t *psactsp; 1076 _psfa_action_t *psfileact; 1077 1078 if (file_actions == NULL || *file_actions == NULL) 1079 return EINVAL; 1080 1081 psactsp = (_posix_spawn_file_actions_t *)file_actions; 1082 /* Range check; required by POSIX */ 1083 if (filedes < 0 || filedes >= OPEN_MAX) 1084 return (EBADF); 1085 1086 /* If we do not have enough slots, grow the structure */ 1087 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) { 1088 /* need to grow file actions structure */ 1089 if (_posix_spawn_file_actions_grow(psactsp)) 1090 return (ENOMEM); 1091 } 1092 1093 /* 1094 * Allocate next available slot and fill it out 1095 */ 1096 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++]; 1097 1098 psfileact->psfaa_type = PSFA_CLOSE; 1099 psfileact->psfaa_filedes = filedes; 1100 1101 return (0); 1102} 1103 1104 1105/* 1106 * posix_spawn_file_actions_adddup2 1107 * 1108 * Description: Add a dup2 action to the object referenced by 'file_actions' 1109 * that will cause the file referenced by 'filedes' to be 1110 * attempted to be dup2'ed to the descriptor 'newfiledes' in the 1111 * spawned process. 1112 * 1113 * Parameters: file_actions File action object to augment 1114 * filedes fd to dup2 1115 * newfiledes fd to dup2 it to 1116 * 1117 * Returns: 0 Success 1118 * EBADF The value specified by either fildes 1119 * or by newfiledes is negative or greater 1120 * than or equal to {OPEN_MAX}. 1121 * ENOMEM Insufficient memory exists to add to 1122 * the spawn file actions object. 1123 * 1124 * NOTIMP: Allowed failures (checking NOT required): 1125 * EINVAL The value specified by file_actions is invalid. 1126 */ 1127int 1128posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions, 1129 int filedes, int newfiledes) 1130{ 1131 _posix_spawn_file_actions_t *psactsp; 1132 _psfa_action_t *psfileact; 1133 1134 if (file_actions == NULL || *file_actions == NULL) 1135 return EINVAL; 1136 1137 psactsp = (_posix_spawn_file_actions_t *)file_actions; 1138 /* Range check; required by POSIX */ 1139 if (filedes < 0 || filedes >= OPEN_MAX || 1140 newfiledes < 0 || newfiledes >= OPEN_MAX) 1141 return (EBADF); 1142 1143 /* If we do not have enough slots, grow the structure */ 1144 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) { 1145 /* need to grow file actions structure */ 1146 if (_posix_spawn_file_actions_grow(psactsp)) 1147 return (ENOMEM); 1148 } 1149 1150 /* 1151 * Allocate next available slot and fill it out 1152 */ 1153 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++]; 1154 1155 psfileact->psfaa_type = PSFA_DUP2; 1156 psfileact->psfaa_filedes = filedes; 1157 psfileact->psfaa_openargs.psfao_oflag = newfiledes; 1158 1159 return (0); 1160} 1161 1162/* 1163 * posix_spawn_file_actions_addinherit_np 1164 * 1165 * Description: Add the "inherit" action to the object referenced by 1166 * 'file_actions' that will cause the file referenced by 1167 * 'filedes' to continue to be available in the spawned 1168 * process via the same descriptor. 1169 * 1170 * Inheritance is the normal default behaviour for 1171 * file descriptors across exec and spawn; but if the 1172 * POSIX_SPAWN_CLOEXEC_DEFAULT flag is set, the usual 1173 * default is reversed for the purposes of the spawn 1174 * invocation. Any pre-existing descriptors that 1175 * need to be made available to the spawned process can 1176 * be marked explicitly as 'inherit' via this interface. 1177 * Otherwise they will be automatically closed. 1178 * 1179 * Note that any descriptors created via the other file 1180 * actions interfaces are automatically marked as 'inherit'. 1181 * 1182 * Parameters: file_actions File action object to augment 1183 * filedes fd to inherit. 1184 * 1185 * Returns: 0 Success 1186 * EBADF The value specified by fildes is 1187 * negative or greater than or equal to 1188 * {OPEN_MAX}. 1189 * ENOMEM Insufficient memory exists to add to 1190 * the spawn file actions object. 1191 * 1192 * NOTIMP: Allowed failures (checking NOT required): 1193 * EINVAL The value specified by file_actions is invalid. 1194 */ 1195int 1196posix_spawn_file_actions_addinherit_np(posix_spawn_file_actions_t *file_actions, 1197 int filedes) 1198{ 1199 _posix_spawn_file_actions_t *psactsp; 1200 _psfa_action_t *psfileact; 1201 1202 if (file_actions == NULL || *file_actions == NULL) 1203 return (EINVAL); 1204 1205 psactsp = (_posix_spawn_file_actions_t *)file_actions; 1206 /* Range check; required by POSIX */ 1207 if (filedes < 0 || filedes >= OPEN_MAX) 1208 return (EBADF); 1209 1210#if defined(POSIX_SPAWN_CLOEXEC_DEFAULT) // TODO: delete this check 1211 /* If we do not have enough slots, grow the structure */ 1212 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) { 1213 /* need to grow file actions structure */ 1214 if (_posix_spawn_file_actions_grow(psactsp)) 1215 return (ENOMEM); 1216 } 1217 1218 /* 1219 * Allocate next available slot and fill it out 1220 */ 1221 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++]; 1222 1223 psfileact->psfaa_type = PSFA_INHERIT; 1224 psfileact->psfaa_filedes = filedes; 1225#endif 1226 return (0); 1227} 1228 1229int 1230posix_spawnattr_setcpumonitor_default(posix_spawnattr_t * __restrict attr) 1231{ 1232 return (posix_spawnattr_setcpumonitor(attr, PROC_POLICY_CPUMON_DEFAULTS, 0)); 1233} 1234 1235int 1236posix_spawnattr_setcpumonitor(posix_spawnattr_t * __restrict attr, 1237 uint64_t percent, uint64_t interval) 1238{ 1239 _posix_spawnattr_t psattr; 1240 1241 if (attr == NULL || *attr == NULL) 1242 return (EINVAL); 1243 1244 psattr = *(_posix_spawnattr_t *)attr; 1245 1246 psattr->psa_cpumonitor_percent = percent; 1247 psattr->psa_cpumonitor_interval = interval; 1248 1249 return (0); 1250} 1251 1252int 1253posix_spawnattr_getcpumonitor(posix_spawnattr_t * __restrict attr, 1254 uint64_t *percent, uint64_t *interval) 1255{ 1256 _posix_spawnattr_t psattr; 1257 1258 if (attr == NULL || *attr == NULL) 1259 return (EINVAL); 1260 1261 psattr = *(_posix_spawnattr_t *)attr; 1262 1263 *percent = psattr->psa_cpumonitor_percent; 1264 *interval = psattr->psa_cpumonitor_interval; 1265 1266 return (0); 1267} 1268 1269#if TARGET_OS_EMBEDDED 1270/* 1271 * posix_spawnattr_setjetsam 1272 * 1273 * Description: Set jetsam attributes for the spawn attribute object 1274 * referred to by 'attr'. 1275 * 1276 * Parameters: flags The flags value to set 1277 * priority Relative jetsam priority 1278 * high_water_mark Value in pages; resident page 1279 * counts above this level can 1280 * result in termination 1281 * 1282 * Returns: 0 Success 1283 */ 1284int 1285posix_spawnattr_setjetsam(posix_spawnattr_t * __restrict attr, 1286 short flags, int priority, int high_water_mark) 1287{ 1288 _posix_spawnattr_t psattr; 1289 1290 if (attr == NULL || *attr == NULL) 1291 return EINVAL; 1292 1293 psattr = *(_posix_spawnattr_t *)attr; 1294 1295 psattr->psa_jetsam_flags = flags; 1296 psattr->psa_jetsam_flags |= POSIX_SPAWN_JETSAM_SET; 1297 psattr->psa_priority = priority; 1298 psattr->psa_high_water_mark = high_water_mark; 1299 1300 return (0); 1301} 1302#endif 1303 1304 1305/* 1306 * posix_spawnattr_set_importancewatch_port_np 1307 * 1308 * Description: Mark ports referred to by these rights 1309 * to boost the new task instead of their current task 1310 * for the spawn attribute object referred to by 'attr'. 1311 * Ports must be valid at posix_spawn time. They will NOT be 1312 * consumed by the kernel, so they must be deallocated after the spawn returns. 1313 * (If you are SETEXEC-ing, they are cleaned up by the exec operation). 1314 * 1315 * The maximum number of watch ports allowed is defined by POSIX_SPAWN_IMPORTANCE_PORT_COUNT. 1316 * 1317 * Parameters: count Number of ports in portarray 1318 * portarray Array of rights 1319 * 1320 * Returns: 0 Success 1321 * EINVAL Bad port count 1322 * ENOMEM Insufficient memory exists to add to 1323 * the spawn port actions object. 1324 */ 1325int 1326posix_spawnattr_set_importancewatch_port_np(posix_spawnattr_t * __restrict attr, 1327 int count, mach_port_t portarray[]) 1328{ 1329 int err = 0, i; 1330 1331 if (count < 0 || count > POSIX_SPAWN_IMPORTANCE_PORT_COUNT) { 1332 return EINVAL; 1333 } 1334 1335 for (i = 0; i < count; i++) { 1336 _ps_port_action_t action = { 1337 .port_type = PSPA_IMP_WATCHPORTS, 1338 .new_port = portarray[i], 1339 }; 1340 int err = posix_spawn_appendportaction_np(attr, &action); 1341 if (err) { 1342 break; 1343 } 1344 } 1345 return err; 1346} 1347 1348 1349 1350static 1351_ps_mac_policy_extension_t * 1352posix_spawnattr_macpolicyinfo_lookup(_posix_spawn_mac_policy_extensions_t psmx, const char *policyname) 1353{ 1354 int i; 1355 1356 if (psmx == NULL) 1357 return NULL; 1358 1359 for (i = 0; i < psmx->psmx_count; i++) { 1360 _ps_mac_policy_extension_t *extension = &psmx->psmx_extensions[i]; 1361 if (strcmp(extension->policyname, policyname) == 0) 1362 return extension; 1363 } 1364 return NULL; 1365} 1366 1367int 1368posix_spawnattr_getmacpolicyinfo_np(const posix_spawnattr_t * __restrict attr, 1369 const char *policyname, void **datap, size_t *datalenp) 1370{ 1371 _posix_spawnattr_t psattr; 1372 _ps_mac_policy_extension_t *extension; 1373 1374 if (attr == NULL || *attr == NULL || policyname == NULL || datap == NULL) 1375 return EINVAL; 1376 1377 psattr = *(_posix_spawnattr_t *)attr; 1378 extension = posix_spawnattr_macpolicyinfo_lookup(psattr->psa_mac_extensions, policyname); 1379 if (extension == NULL) 1380 return ESRCH; 1381 *datap = (void *)(uintptr_t)extension->data; 1382 if (datalenp != NULL) 1383 *datalenp = extension->datalen; 1384 return 0; 1385} 1386 1387int 1388posix_spawnattr_setmacpolicyinfo_np(posix_spawnattr_t * __restrict attr, 1389 const char *policyname, void *data, size_t datalen) 1390{ 1391 _posix_spawnattr_t psattr; 1392 _posix_spawn_mac_policy_extensions_t psmx; 1393 _ps_mac_policy_extension_t *extension; 1394 1395 if (attr == NULL || *attr == NULL || policyname == NULL) 1396 return EINVAL; 1397 1398 psattr = *(_posix_spawnattr_t *)attr; 1399 psmx = psattr->psa_mac_extensions; 1400 extension = posix_spawnattr_macpolicyinfo_lookup(psattr->psa_mac_extensions, policyname); 1401 if (extension != NULL) { 1402 extension->data = (uintptr_t)data; 1403 extension->datalen = datalen; 1404 return 0; 1405 } 1406 else if (psmx == NULL) { 1407 psmx = psattr->psa_mac_extensions = malloc(PS_MAC_EXTENSIONS_SIZE(PS_MAC_EXTENSIONS_INIT_COUNT)); 1408 if (psmx == NULL) 1409 return ENOMEM; 1410 psmx->psmx_alloc = PS_MAC_EXTENSIONS_INIT_COUNT; 1411 psmx->psmx_count = 0; 1412 } 1413 else if (psmx->psmx_count == psmx->psmx_alloc) { 1414 psmx = psattr->psa_mac_extensions = reallocf(psmx, PS_MAC_EXTENSIONS_SIZE(psmx->psmx_alloc * 2)); 1415 if (psmx == NULL) 1416 return ENOMEM; 1417 psmx->psmx_alloc *= 2; 1418 } 1419 extension = &psmx->psmx_extensions[psmx->psmx_count]; 1420 strlcpy(extension->policyname, policyname, sizeof(extension->policyname)); 1421 extension->data = (uintptr_t)data; 1422 extension->datalen = datalen; 1423 psmx->psmx_count += 1; 1424 return 0; 1425} 1426 1427/* 1428 * posix_spawn 1429 * 1430 * Description: Create a new process from the process image corresponding to 1431 * the supplied 'path' argument. 1432 * 1433 * Parameters: pid Pointer to pid_t to receive the 1434 * PID of the spawned process, if 1435 * successful and 'pid' != NULL 1436 * path Path of image file to spawn 1437 * file_actions spawn file actions object which 1438 * describes file actions to be 1439 * performed during the spawn 1440 * attrp spawn attributes object which 1441 * describes attributes to be 1442 * applied during the spawn 1443 * argv argument vector array; NULL 1444 * terminated 1445 * envp environment vector array; NULL 1446 * terminated 1447 * 1448 * Returns: 0 Success 1449 * !0 An errno value indicating the 1450 * cause of the failure to spawn 1451 * 1452 * Notes: Unlike other system calls, the return value of this system 1453 * call is expected to either be a 0 or an errno, rather than a 1454 * 0 or a -1, with the 'errno' variable being set. 1455 */ 1456extern int __posix_spawn(pid_t * __restrict, const char * __restrict, 1457 struct _posix_spawn_args_desc *, 1458 char *const argv[ __restrict], char *const envp[ __restrict]); 1459 1460int 1461posix_spawn(pid_t * __restrict pid, const char * __restrict path, 1462 const posix_spawn_file_actions_t *file_actions, 1463 const posix_spawnattr_t * __restrict attrp, 1464 char *const argv[ __restrict], char *const envp[ __restrict]) 1465{ 1466 int saveerrno = errno; 1467 int ret; 1468 /* 1469 * Only do extra work if we have file actions or attributes to push 1470 * down. We use a descriptor to push this information down, since we 1471 * want to have size information, which will let us (1) preallocate a 1472 * single chunk of memory for the copyin(), and (2) allow us to do a 1473 * single copyin() per attributes or file actions as a monlithic block. 1474 * 1475 * Note: A future implementation may attempt to do the same 1476 * thing for the argv/envp data, which could potentially 1477 * result in a performance improvement due to increased 1478 * kernel efficiency, even though it would mean copying 1479 * the data in user space. 1480 */ 1481 if ((file_actions != NULL && (*file_actions != NULL) && (*(_posix_spawn_file_actions_t *)file_actions)->psfa_act_count > 0) || attrp != NULL) { 1482 struct _posix_spawn_args_desc ad; 1483 1484 memset(&ad, 0, sizeof(ad)); 1485 if (attrp != NULL && *attrp != NULL) { 1486 _posix_spawnattr_t psattr = *(_posix_spawnattr_t *)attrp; 1487 ad.attr_size = sizeof(struct _posix_spawnattr); 1488 ad.attrp = psattr; 1489 1490 if (psattr->psa_ports != NULL) { 1491 ad.port_actions = psattr->psa_ports; 1492 ad.port_actions_size = PS_PORT_ACTIONS_SIZE( 1493 ad.port_actions->pspa_count); 1494 } 1495 if (psattr->psa_mac_extensions != NULL) { 1496 ad.mac_extensions = psattr->psa_mac_extensions; 1497 ad.mac_extensions_size = PS_MAC_EXTENSIONS_SIZE( 1498 ad.mac_extensions->psmx_count); 1499 } 1500 } 1501 if (file_actions != NULL && *file_actions != NULL) { 1502 _posix_spawn_file_actions_t psactsp = 1503 *(_posix_spawn_file_actions_t *)file_actions; 1504 1505 if (psactsp->psfa_act_count > 0) { 1506 ad.file_actions_size = PSF_ACTIONS_SIZE(psactsp->psfa_act_count); 1507 ad.file_actions = psactsp; 1508 } 1509 } 1510 1511 ret = __posix_spawn(pid, path, &ad, argv, envp); 1512 } else 1513 ret = __posix_spawn(pid, path, NULL, argv, envp); 1514 1515 if (ret < 0) 1516 ret = errno; 1517 errno = saveerrno; 1518 return ret; 1519} 1520 1521