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