2 * Copyright (c) 2006-2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * [SPN] Support for _POSIX_SPAWN
28 #define CONFIG_MEMORYSTATUS 1 // <rdar://problem/13604997>
29 #include <sys/types.h> /* for user_size_t */
31 #include <spawn_private.h>
32 #include <sys/spawn_internal.h>
33 #include <sys/process_policy.h>
36 #include <limits.h> /* for OPEN_MAX, PATH_MAX */
39 #include <mach/port.h>
40 #include <mach/mach_param.h> /* for TASK_PORT_REGISTER_MAX */
41 #include <mach/exception_types.h>
42 #include <mach/coalition.h> /* for COALITION_TYPE_MAX */
43 #include <sys/kern_memorystatus.h>
46 * posix_spawnattr_init
48 * Description: Initialize a spawn attributes object attr with default values
50 * Parameters: attr The spawn attributes object to be
54 * ENOMEM Insufficient memory exists to
55 * initialize the spawn attributes object.
57 * Note: As an implementation detail, the externally visibily type
58 * posix_spawnattr_t is defined to be a void *, and initialization
59 * involves allocation of a memory object. Subsequent changes to
60 * the spawn attributes may result in reallocation under the
63 * Reinitialization of an already initialized spawn attributes
64 * object will result in memory being leaked. Because spawn
65 * attributes are not required to be used in conjunction with a
66 * static initializer, there is no way to distinguish a spawn
67 * attribute with stack garbage from one that's been initialized.
68 * This is arguably an API design error.
71 posix_spawnattr_init(posix_spawnattr_t
*attr
)
73 _posix_spawnattr_t
*psattrp
= (_posix_spawnattr_t
*)attr
;
76 if ((*psattrp
= (_posix_spawnattr_t
)malloc(sizeof(struct _posix_spawnattr
))) == NULL
) {
80 * The default value of this attribute shall be as if no
83 (*psattrp
)->psa_flags
= 0;
86 * The default value of this attribute shall be an empty
89 (*psattrp
)->psa_sigdefault
= 0;
91 /* The default value of this attribute is unspecified */
92 (*psattrp
)->psa_sigmask
= 0;
94 /* The default value of this attribute shall be zero */
95 (*psattrp
)->psa_pgroup
= 0; /* doesn't matter */
97 /* Default is no binary preferences, i.e. use normal grading */
98 memset((*psattrp
)->psa_binprefs
, 0,
99 sizeof((*psattrp
)->psa_binprefs
));
101 /* Default is no port actions to take */
102 (*psattrp
)->psa_ports
= NULL
;
105 * The default value of this attribute shall be an no
106 * process control on resource starvation
108 (*psattrp
)->psa_pcontrol
= 0;
111 * Initializing the alignment paddings.
114 (*psattrp
)->short_padding
= 0;
115 (*psattrp
)->flags_padding
= 0;
117 /* Default is no new apptype requested */
118 (*psattrp
)->psa_apptype
= POSIX_SPAWN_PROCESS_TYPE_DEFAULT
;
121 (*psattrp
)->psa_jetsam_flags
= 0;
122 (*psattrp
)->psa_priority
= -1;
123 (*psattrp
)->psa_memlimit_active
= -1;
124 (*psattrp
)->psa_memlimit_inactive
= -1;
126 /* Default is no thread limit */
127 (*psattrp
)->psa_thread_limit
= 0;
129 /* Default is no CPU usage monitor active. */
130 (*psattrp
)->psa_cpumonitor_percent
= 0;
131 (*psattrp
)->psa_cpumonitor_interval
= 0;
133 /* Default is no MAC policy extensions. */
134 (*psattrp
)->psa_mac_extensions
= NULL
;
136 /* Default is to inherit parent's coalition(s) */
137 (*psattrp
)->psa_coalition_info
= NULL
;
139 (*psattrp
)->psa_persona_info
= NULL
;
141 (*psattrp
)->psa_posix_cred_info
= NULL
;
144 * old coalition field
145 * For backwards compatibility reasons, we set this to 1
146 * which is the first valid coalition id. This will allow
147 * newer user space code to properly spawn processes on
149 * (they will just all end up in the same coalition).
151 (*psattrp
)->psa_reserved
= 1;
153 /* Default is no new clamp */
154 (*psattrp
)->psa_qos_clamp
= POSIX_SPAWN_PROC_CLAMP_NONE
;
156 /* Default is no change to role */
157 (*psattrp
)->psa_darwin_role
= POSIX_SPAWN_DARWIN_ROLE_NONE
;
159 (*psattrp
)->psa_max_addr
= 0;
167 * posix_spawnattr_destroy
169 * Description: Destroy a spawn attributes object that was previously
170 * initialized via posix_spawnattr_init() by freeing any
171 * memory associated with it and setting it to an invalid value.
173 * Parameters: attr The spawn attributes object to be
178 * Notes: The destroyed spawn attribute results in the void * pointer
179 * being set to NULL; subsequent use without reinitialization
180 * will result in explicit program failure (rather than merely
181 * "undefined behaviour").
183 * NOTIMP: Allowed failures (checking NOT required):
184 * EINVAL The value specified by attr is invalid.
186 static int posix_spawn_destroyportactions_np(posix_spawnattr_t
*);
187 static int posix_spawn_destroycoalition_info_np(posix_spawnattr_t
*);
188 static int posix_spawn_destroypersona_info_np(posix_spawnattr_t
*);
189 static int posix_spawn_destroyposix_cred_info_np(posix_spawnattr_t
*);
190 static int posix_spawn_destroymacpolicy_info_np(posix_spawnattr_t
*);
193 posix_spawnattr_destroy(posix_spawnattr_t
*attr
)
195 _posix_spawnattr_t psattr
;
197 if (attr
== NULL
|| *attr
== NULL
) {
201 psattr
= *(_posix_spawnattr_t
*)attr
;
202 posix_spawn_destroyportactions_np(attr
);
203 posix_spawn_destroycoalition_info_np(attr
);
204 posix_spawn_destroypersona_info_np(attr
);
205 posix_spawn_destroyposix_cred_info_np(attr
);
206 posix_spawn_destroymacpolicy_info_np(attr
);
216 * posix_spawnattr_setflags
218 * Description: Set the spawn flags attribute for the spawn attribute object
219 * referred to by 'attr'.
221 * Parameters: attr The spawn attributes object whose flags
223 * flags The flags value to set
227 * NOTIMP: Allowed failures (checking NOT required):
228 * EINVAL The value specified by attr is invalid.
229 * EINVAL The value of the attribute being set is not valid.
232 posix_spawnattr_setflags(posix_spawnattr_t
*attr
, short flags
)
234 _posix_spawnattr_t psattr
;
236 if (attr
== NULL
|| *attr
== NULL
) {
240 psattr
= *(_posix_spawnattr_t
*)attr
;
241 psattr
->psa_flags
= flags
;
248 * posix_spawnattr_getflags
250 * Description: Retrieve the spawn attributes flag for the spawn attributes
251 * object referenced by 'attr' and place them in the memory
252 * location referenced by 'flagsp'
254 * Parameters: attr The spawn attributes object whose flags
255 * are to be retrieved
256 * flagsp A pointer to a short value to receive
262 * *flagps (modified) The flags value from the spawn
265 * NOTIMP: Allowed failures (checking NOT required):
266 * EINVAL The value specified by attr is invalid.
267 * EINVAL The value of the attribute being set is not valid.
270 posix_spawnattr_getflags(const posix_spawnattr_t
* __restrict attr
,
271 short * __restrict flagsp
)
273 _posix_spawnattr_t psattr
;
275 if (attr
== NULL
|| *attr
== NULL
) {
279 psattr
= *(_posix_spawnattr_t
*)attr
;
280 *flagsp
= psattr
->psa_flags
;
287 * posix_spawnattr_getsigdefault
289 * Description: Retrieve the set of signals to be set to default according to
290 * the spawn attribute value referenced by 'attr' and place the
291 * result into the memory containing the sigset_t referenced by
294 * Parameters: attr The spawn attributes object whose
295 * signal set for default signals is to
297 * sigdefault A pointer to the sigset_t to receive
303 * *sigdefault (modified) The signal set of signals to default
304 * from the spawn attributes object
307 posix_spawnattr_getsigdefault(const posix_spawnattr_t
* __restrict attr
,
308 sigset_t
* __restrict sigdefault
)
310 _posix_spawnattr_t psattr
;
312 if (attr
== NULL
|| *attr
== NULL
) {
316 psattr
= *(_posix_spawnattr_t
*)attr
;
317 *sigdefault
= psattr
->psa_sigdefault
;
324 * posix_spawnattr_getpgroup
326 * Description: Obtain the value of the spawn process group attribute from the
327 * spawn attributes object referenced by 'attr' and place the
328 * results in the memory location referenced by 'pgroup'
330 * Parameters: attr The spawn attributes object whose
331 * process group information is to be
333 * pgroup A pointer to the pid_t to receive the
339 * *pgroup (modified) The process group information from the
340 * spawn attributes object
343 posix_spawnattr_getpgroup(const posix_spawnattr_t
* __restrict attr
,
344 pid_t
* __restrict pgroup
)
346 _posix_spawnattr_t psattr
;
348 if (attr
== NULL
|| *attr
== NULL
) {
352 psattr
= *(_posix_spawnattr_t
*)attr
;
353 *pgroup
= psattr
->psa_pgroup
;
360 * posix_spawnattr_getsigmask
362 * Description: Obtain the value of the spawn signal mask attribute from the
363 * spawn attributes object referenced by 'attr' and place the
364 * result into the memory containing the sigset_t referenced by
367 * Parameters: attr The spawn attributes object whose
368 * signal set for masked signals is to
370 * sigmask A pointer to the sigset_t to receive
376 * *sigmask (modified) The signal set of signals to mask
377 * from the spawn attributes object
380 posix_spawnattr_getsigmask(const posix_spawnattr_t
* __restrict attr
,
381 sigset_t
* __restrict sigmask
)
383 _posix_spawnattr_t psattr
;
385 if (attr
== NULL
|| *attr
== NULL
) {
389 psattr
= *(_posix_spawnattr_t
*)attr
;
390 *sigmask
= psattr
->psa_sigmask
;
396 * posix_spawnattr_getbinpref_np
398 * Description: Obtain the value of the spawn binary preferences attribute from
399 * the spawn attributes object referenced by 'attr' and place the
400 * result into the memory referenced by 'pref'.
402 * Parameters: attr The spawn attributes object whose
403 * binary preferences are to be retrieved
404 * count The size of the cpu_type_t array
405 * pref An array of cpu types
406 * ocount The actual number copied
408 * Returns: 0 No binary preferences found
409 * > 0 The number of cpu types (less than
410 * count) copied over from 'attr'.
413 * *pref (modified) The binary preferences array
414 * from the spawn attributes object
417 posix_spawnattr_getbinpref_np(const posix_spawnattr_t
* __restrict attr
,
418 size_t count
, cpu_type_t
*pref
, size_t * __restrict ocount
)
420 _posix_spawnattr_t psattr
;
423 if (attr
== NULL
|| *attr
== NULL
) {
427 psattr
= *(_posix_spawnattr_t
*)attr
;
428 for (i
= 0; i
< count
&& i
< 4; i
++) {
429 pref
[i
] = psattr
->psa_binprefs
[i
];
440 * posix_spawnattr_getpcontrol_np
442 * Description: Retrieve the process control property set default according to
443 * the spawn attribute value referenced by 'attr' and place the
444 * result into the memory containing the control referenced by
447 * Parameters: attr The spawn attributes object whose
448 * signal set for default signals is to
450 * pcontrol A pointer to an int to receive
451 * the process control info
456 * *pcontrol (modified) The signal set of signals to default
457 * from the spawn attributes object
460 posix_spawnattr_getpcontrol_np(const posix_spawnattr_t
* __restrict attr
,
461 int * __restrict pcontrol
)
463 _posix_spawnattr_t psattr
;
465 if (attr
== NULL
|| *attr
== NULL
) {
469 psattr
= *(_posix_spawnattr_t
*)attr
;
470 *pcontrol
= psattr
->psa_pcontrol
;
476 * posix_spawnattr_getprocesstype_np
478 * Description: Retrieve the process specific behaviors and app launch types
479 * spawn attribute value referenced by 'attr' and place the
480 * result into the memory containing the control referenced by
483 * Parameters: attr The spawn attributes object whose
484 * signal set for default signals is to
486 * proctype A pointer to an int to receive
487 * the process type info
492 * *proctype (modified) The process type set to value
493 * from the spawn attributes object
496 posix_spawnattr_getprocesstype_np(const posix_spawnattr_t
* __restrict attr
,
497 int * __restrict proctype
)
499 _posix_spawnattr_t psattr
;
501 if (attr
== NULL
|| *attr
== NULL
) {
505 psattr
= *(_posix_spawnattr_t
*)attr
;
506 *proctype
= psattr
->psa_apptype
;
511 * posix_spawnattr_setsigdefault
513 * Description: Set the set of signals to be set to default for the spawn
514 * attribute value referenced by 'attr' from the memory
515 * containing the sigset_t referenced by 'sigdefault'
517 * Parameters: attr The spawn attributes object whose
518 * signal set for default signals is to
520 * sigdefault A pointer to the sigset_t from which to
521 * obtain the signal set
526 posix_spawnattr_setsigdefault(posix_spawnattr_t
* __restrict attr
,
527 const sigset_t
* __restrict sigdefault
)
529 _posix_spawnattr_t psattr
;
531 if (attr
== NULL
|| *attr
== NULL
) {
535 psattr
= *(_posix_spawnattr_t
*)attr
;
536 psattr
->psa_sigdefault
= *sigdefault
;
543 * posix_spawnattr_setpgroup
545 * Description: Set the value of the spawn process group attribute for the
546 * spawn attributes object referenced by 'attr' from the value
549 * Parameters: attr The spawn attributes object for which
550 * the process group information is to be
552 * pgroup The process group to set
557 posix_spawnattr_setpgroup(posix_spawnattr_t
* attr
, pid_t pgroup
)
559 _posix_spawnattr_t psattr
;
561 if (attr
== NULL
|| *attr
== NULL
) {
565 psattr
= *(_posix_spawnattr_t
*)attr
;
566 psattr
->psa_pgroup
= pgroup
;
573 * posix_spawnattr_setsigmask
575 * Description: Set the set of signals to be masked for the spawn attribute
576 * value referenced by 'attr' from the memory containing the
577 * sigset_t referenced by 'sigmask'
579 * Parameters: attr The spawn attributes object whose
580 * signal set for masked signals is to
582 * sigmask A pointer to the sigset_t from which to
583 * obtain the signal set
588 posix_spawnattr_setsigmask(posix_spawnattr_t
* __restrict attr
,
589 const sigset_t
* __restrict sigmask
)
591 _posix_spawnattr_t psattr
;
593 if (attr
== NULL
|| *attr
== NULL
) {
597 psattr
= *(_posix_spawnattr_t
*)attr
;
598 psattr
->psa_sigmask
= *sigmask
;
605 * posix_spawnattr_setbinpref_np
607 * Description: Set the universal binary preferences for the spawn attribute
608 * value referenced by 'attr' from the memory containing the
609 * cpu_type_t array referenced by 'pref', size of 'count'
611 * Parameters: attr The spawn attributes object whose
612 * binary preferences are to be set
613 * count Size of the array pointed to by 'pref'
614 * pref cpu_type_t array of binary preferences
615 * ocount The actual number copied
617 * Returns: 0 No preferences copied
618 * > 0 Number of preferences copied
620 * Note: The posix_spawnattr_t currently only holds four cpu_type_t's.
621 * If the caller provides more preferences than this limit, they
622 * will be ignored, as reflected in the return value.
625 posix_spawnattr_setbinpref_np(posix_spawnattr_t
* __restrict attr
,
626 size_t count
, cpu_type_t
*pref
, size_t * __restrict ocount
)
628 _posix_spawnattr_t psattr
;
631 if (attr
== NULL
|| *attr
== NULL
) {
635 psattr
= *(_posix_spawnattr_t
*)attr
;
636 for (i
= 0; i
< count
&& i
< 4; i
++) {
637 psattr
->psa_binprefs
[i
] = pref
[i
];
640 /* return number of binprefs copied over */
649 * posix_spawnattr_setpcontrol_np
651 * Description: Set the process control property according to
652 * attribute value referenced by 'attr' from the memory
653 * containing the int value 'pcontrol'
655 * Parameters: attr The spawn attributes object whose
656 * signal set for default signals is to
658 * pcontrol An int value of the process control info
663 posix_spawnattr_setpcontrol_np(posix_spawnattr_t
* __restrict attr
,
666 _posix_spawnattr_t psattr
;
668 if (attr
== NULL
|| *attr
== NULL
) {
672 psattr
= *(_posix_spawnattr_t
*)attr
;
673 psattr
->psa_pcontrol
= pcontrol
;
680 * posix_spawnattr_setprocesstype_np
682 * Description: Set the process specific behaviors and app launch type
683 * attribute value referenced by 'attr' from the memory
684 * containing the int value 'proctype'
686 * Parameters: attr The spawn attributes object whose
687 * signal set for default signals is to
689 * proctype An int value of the process type info
694 posix_spawnattr_setprocesstype_np(posix_spawnattr_t
* __restrict attr
,
697 _posix_spawnattr_t psattr
;
699 if (attr
== NULL
|| *attr
== NULL
) {
703 psattr
= *(_posix_spawnattr_t
*)attr
;
704 psattr
->psa_apptype
= proctype
;
710 * posix_spawn_createportactions_np
711 * Description: create a new posix_spawn_port_actions struct and link
712 * it into the posix_spawnattr.
715 posix_spawn_createportactions_np(posix_spawnattr_t
*attr
)
717 _posix_spawnattr_t psattr
;
718 _posix_spawn_port_actions_t acts
;
720 if (attr
== NULL
|| *attr
== NULL
) {
724 psattr
= *(_posix_spawnattr_t
*)attr
;
725 acts
= (_posix_spawn_port_actions_t
)malloc(PS_PORT_ACTIONS_SIZE(2));
730 acts
->pspa_alloc
= 2;
731 acts
->pspa_count
= 0;
733 psattr
->psa_ports
= acts
;
738 * posix_spawn_growportactions_np
739 * Description: Enlarge the size of portactions if necessary
742 posix_spawn_growportactions_np(posix_spawnattr_t
*attr
)
744 _posix_spawnattr_t psattr
;
745 _posix_spawn_port_actions_t acts
;
747 if (attr
== NULL
|| *attr
== NULL
) {
751 psattr
= *(_posix_spawnattr_t
*)attr
;
752 acts
= psattr
->psa_ports
;
757 /* Double number of port actions allocated for */
759 if (os_mul_overflow(acts
->pspa_alloc
, 2, &newnum
)) {
762 size_t newsize
= PS_PORT_ACTIONS_SIZE(newnum
);
767 acts
= realloc(acts
, newsize
);
772 acts
->pspa_alloc
= newnum
;
773 psattr
->psa_ports
= acts
;
778 * posix_spawn_destroyportactions_np
779 * Description: clean up portactions struct in posix_spawnattr_t attr
782 posix_spawn_destroyportactions_np(posix_spawnattr_t
*attr
)
784 _posix_spawnattr_t psattr
;
785 _posix_spawn_port_actions_t acts
;
787 if (attr
== NULL
|| *attr
== NULL
) {
791 psattr
= *(_posix_spawnattr_t
*)attr
;
792 acts
= psattr
->psa_ports
;
802 * posix_spawn_destroycoalition_info_np
803 * Description: clean up coalition_info struct in posix_spawnattr_t attr
806 posix_spawn_destroycoalition_info_np(posix_spawnattr_t
*attr
)
808 _posix_spawnattr_t psattr
;
809 struct _posix_spawn_coalition_info
*coal_info
;
811 if (attr
== NULL
|| *attr
== NULL
) {
815 psattr
= *(_posix_spawnattr_t
*)attr
;
816 coal_info
= psattr
->psa_coalition_info
;
817 if (coal_info
== NULL
) {
821 psattr
->psa_coalition_info
= NULL
;
827 * posix_spawn_destroypersona_info_np
828 * Description: clean up persona_info struct in posix_spawnattr_t attr
831 posix_spawn_destroypersona_info_np(posix_spawnattr_t
*attr
)
833 _posix_spawnattr_t psattr
;
834 struct _posix_spawn_persona_info
*persona
;
836 if (attr
== NULL
|| *attr
== NULL
) {
840 psattr
= *(_posix_spawnattr_t
*)attr
;
841 persona
= psattr
->psa_persona_info
;
842 if (persona
== NULL
) {
846 psattr
->psa_persona_info
= NULL
;
852 * posix_spawn_destroyposix_cred_info_np
853 * Description: clean up posix_cred_info struct in posix_spawnattr_t attr
856 posix_spawn_destroyposix_cred_info_np(posix_spawnattr_t
*attr
)
858 _posix_spawnattr_t psattr
;
859 struct _posix_spawn_posix_cred_info
*pspci
;
861 if (attr
== NULL
|| *attr
== NULL
) {
865 psattr
= *(_posix_spawnattr_t
*)attr
;
866 pspci
= psattr
->psa_posix_cred_info
;
871 psattr
->psa_posix_cred_info
= NULL
;
877 * posix_spawn_appendportaction_np
878 * Description: append a port action, grow the array if necessary
881 posix_spawn_appendportaction_np(posix_spawnattr_t
*attr
, _ps_port_action_t
*act
)
883 _posix_spawnattr_t psattr
;
884 _posix_spawn_port_actions_t acts
;
886 if (attr
== NULL
|| *attr
== NULL
|| act
== NULL
) {
890 psattr
= *(_posix_spawnattr_t
*)attr
;
891 acts
= psattr
->psa_ports
;
893 // Have any port actions been created yet?
895 int err
= posix_spawn_createportactions_np(attr
);
899 acts
= psattr
->psa_ports
;
902 // Is there enough room?
903 if (acts
->pspa_alloc
== acts
->pspa_count
) {
904 int err
= posix_spawn_growportactions_np(attr
);
908 acts
= psattr
->psa_ports
;
911 // Add this action to next spot in array
912 acts
->pspa_actions
[acts
->pspa_count
] = *act
;
919 * posix_spawnattr_setspecialport_np
921 * Description: Set a new value for a mach special port in the spawned task.
923 * Parameters: attr The spawn attributes object for the
925 * new_port The new value for the special port
926 * which The particular port to be set
927 * (see task_set_special_port for details)
930 * ENOMEM Couldn't allocate memory
933 posix_spawnattr_setspecialport_np(
934 posix_spawnattr_t
*attr
,
935 mach_port_t new_port
,
938 _ps_port_action_t action
= {
939 .port_type
= PSPA_SPECIAL
,
940 .new_port
= new_port
,
943 return posix_spawn_appendportaction_np(attr
, &action
);
947 * posix_spawnattr_setsuidcredport_np
949 * Description: Set an suid cred port to be used to execute with a different UID.
951 * Parameters: attr The spawn attributes object for the
953 * port The suid cred port
958 posix_spawnattr_setsuidcredport_np(posix_spawnattr_t
*attr
, mach_port_t port
)
960 _ps_port_action_t action
= {
961 .port_type
= PSPA_SUID_CRED
,
964 return posix_spawn_appendportaction_np(attr
, &action
);
968 * posix_spawnattr_setexceptionports_np
970 * Description: Set a new port for a set of exception ports in the spawned task.
972 * Parameters: attr The spawn attributes object for the
974 * mask A bitfield indicating which exceptions
975 * to associate the port with
976 * new_port The new value for the exception port
977 * behavior The default behavior for the port
978 * flavor The default flavor for the port
979 * (see task_set_exception_ports)
984 posix_spawnattr_setexceptionports_np(
985 posix_spawnattr_t
*attr
,
986 exception_mask_t mask
,
987 mach_port_t new_port
,
988 exception_behavior_t behavior
,
989 thread_state_flavor_t flavor
)
991 _ps_port_action_t action
= {
992 .port_type
= PSPA_EXCEPTION
,
994 .new_port
= new_port
,
995 .behavior
= behavior
,
998 return posix_spawn_appendportaction_np(attr
, &action
);
1002 * posix_spawnattr_setauditsessionport_np
1004 * Description: Set the audit session port rights attribute in the spawned task.
1005 * This is used to securely set the audit session information for
1008 * Parameters: attr The spawn attributes object for the
1010 * au_sessionport The audit session send port right
1012 * Returns: 0 Success
1015 posix_spawnattr_setauditsessionport_np(
1016 posix_spawnattr_t
*attr
,
1017 mach_port_t au_sessionport
)
1019 _ps_port_action_t action
= {
1020 .port_type
= PSPA_AU_SESSION
,
1021 .new_port
= au_sessionport
,
1023 return posix_spawn_appendportaction_np(attr
, &action
);
1028 * posix_spawn_file_actions_init
1030 * Description: Initialize a spawn file actions object attr with default values
1032 * Parameters: file_actions The spawn file actions object to be
1035 * Returns: 0 Success
1036 * ENOMEM Insufficient memory exists to
1037 * initialize the spawn file actions
1040 * Note: As an implementation detail, the externally visibily type
1041 * posix_spawn_file_actions_t is defined to be a void *, and
1042 * initialization involves allocation of a memory object.
1043 * Subsequent changes to the spawn file actions may result in
1044 * reallocation under the covers.
1046 * Reinitialization of an already initialized spawn file actions
1047 * object will result in memory being leaked. Because spawn
1048 * file actions are not required to be used in conjunction with a
1049 * static initializer, there is no way to distinguish a spawn
1050 * file actions with stack garbage from one that's been
1051 * initialized. This is arguably an API design error.
1054 posix_spawn_file_actions_init(posix_spawn_file_actions_t
*file_actions
)
1056 _posix_spawn_file_actions_t
*psactsp
= (_posix_spawn_file_actions_t
*)file_actions
;
1059 if ((*psactsp
= (_posix_spawn_file_actions_t
)malloc(PSF_ACTIONS_SIZE(PSF_ACTIONS_INIT_COUNT
))) == NULL
) {
1062 (*psactsp
)->psfa_act_alloc
= PSF_ACTIONS_INIT_COUNT
;
1063 (*psactsp
)->psfa_act_count
= 0;
1071 * posix_spawn_file_actions_destroy
1073 * Description: Destroy a spawn file actions object that was previously
1074 * initialized via posix_spawn_file_actions_init() by freeing any
1075 * memory associated with it and setting it to an invalid value.
1077 * Parameters: attr The spawn file actions object to be
1080 * Returns: 0 Success
1082 * Notes: The destroyed spawn file actions results in the void * pointer
1083 * being set to NULL; subsequent use without reinitialization
1084 * will result in explicit program failure (rather than merely
1085 * "undefined behaviour").
1087 * NOTIMP: Allowed failures (checking NOT required):
1088 * EINVAL The value specified by file_actions is invalid.
1091 posix_spawn_file_actions_destroy(posix_spawn_file_actions_t
*file_actions
)
1093 _posix_spawn_file_actions_t psacts
;
1095 if (file_actions
== NULL
|| *file_actions
== NULL
) {
1099 psacts
= *(_posix_spawn_file_actions_t
*)file_actions
;
1101 *file_actions
= NULL
;
1108 * _posix_spawn_file_actions_grow
1110 * Description: Grow the available list of file actions associated with the
1111 * pointer to the structure provided; replace the contents of the
1112 * pointer as a side effect.
1114 * Parameters: psactsp Pointer to _posix_spawn_file_actions_t
1117 * Returns: 0 Success
1118 * ENOMEM Insufficient memory for operation
1120 * Notes: This code is common to all posix_spawn_file_actions_*()
1121 * functions, since we use a naieve data structure implementation
1122 * at present. Future optimization will likely change this.
1125 _posix_spawn_file_actions_grow(_posix_spawn_file_actions_t
*psactsp
)
1128 if (os_mul_overflow((*psactsp
)->psfa_act_alloc
, 2, &newnum
)) {
1132 size_t newsize
= PSF_ACTIONS_SIZE(newnum
);
1138 * XXX may want to impose an administrative limit here; POSIX does
1139 * XXX not provide for an administrative error return in this case,
1140 * XXX so it's probably acceptable to just fail catastrophically
1141 * XXX instead of implementing one.
1143 _posix_spawn_file_actions_t new_psacts
;
1144 if ((new_psacts
= (_posix_spawn_file_actions_t
)realloc((*psactsp
), newsize
)) == NULL
) {
1147 new_psacts
->psfa_act_alloc
= newnum
;
1148 *psactsp
= new_psacts
;
1155 * posix_spawn_file_actions_addopen
1157 * Description: Add an open action to the object referenced by 'file_actions'
1158 * that will cause the file named by 'path' to be attempted to be
1159 * opened with flags 'oflag' and mode 'mode', and, if successful,
1160 * return as descriptor 'filedes' to the spawned process.
1162 * Parameters: file_actions File action object to augment
1163 * filedes fd that open is to use
1164 * path path to file to open
1165 * oflag open file flags
1166 * mode open file mode
1168 * Returns: 0 Success
1169 * EBADF The value specified by fildes is
1170 * negative or greater than or equal to
1172 * ENOMEM Insufficient memory exists to add to
1173 * the spawn file actions object.
1175 * NOTIMP: Allowed failures (checking NOT required):
1176 * EINVAL The value specified by file_actions is invalid.
1179 posix_spawn_file_actions_addopen(
1180 posix_spawn_file_actions_t
* __restrict file_actions
,
1181 int filedes
, const char * __restrict path
, int oflag
,
1184 _posix_spawn_file_actions_t
*psactsp
;
1185 _psfa_action_t
*psfileact
;
1187 if (file_actions
== NULL
|| *file_actions
== NULL
) {
1191 psactsp
= (_posix_spawn_file_actions_t
*)file_actions
;
1192 /* Range check; required by POSIX */
1193 if (filedes
< 0 || filedes
>= OPEN_MAX
) {
1197 /* If we do not have enough slots, grow the structure */
1198 if ((*psactsp
)->psfa_act_count
== (*psactsp
)->psfa_act_alloc
) {
1199 /* need to grow file actions structure */
1200 if (_posix_spawn_file_actions_grow(psactsp
)) {
1206 * Allocate next available slot and fill it out
1208 psfileact
= &(*psactsp
)->psfa_act_acts
[(*psactsp
)->psfa_act_count
++];
1210 psfileact
->psfaa_type
= PSFA_OPEN
;
1211 psfileact
->psfaa_filedes
= filedes
;
1212 psfileact
->psfaa_openargs
.psfao_oflag
= oflag
;
1213 psfileact
->psfaa_openargs
.psfao_mode
= mode
;
1214 strlcpy(psfileact
->psfaa_openargs
.psfao_path
, path
, PATH_MAX
);
1221 * posix_spawn_file_actions_addclose
1223 * Description: Add a close action to the object referenced by 'file_actions'
1224 * that will cause the file referenced by 'filedes' to be
1225 * attempted to be closed in the spawned process.
1227 * Parameters: file_actions File action object to augment
1228 * filedes fd to close
1230 * Returns: 0 Success
1231 * EBADF The value specified by fildes is
1232 * negative or greater than or equal to
1234 * ENOMEM Insufficient memory exists to add to
1235 * the spawn file actions object.
1237 * NOTIMP: Allowed failures (checking NOT required):
1238 * EINVAL The value specified by file_actions is invalid.
1241 posix_spawn_file_actions_addclose(posix_spawn_file_actions_t
*file_actions
,
1244 _posix_spawn_file_actions_t
*psactsp
;
1245 _psfa_action_t
*psfileact
;
1247 if (file_actions
== NULL
|| *file_actions
== NULL
) {
1251 psactsp
= (_posix_spawn_file_actions_t
*)file_actions
;
1252 /* Range check; required by POSIX */
1253 if (filedes
< 0 || filedes
>= OPEN_MAX
) {
1257 /* If we do not have enough slots, grow the structure */
1258 if ((*psactsp
)->psfa_act_count
== (*psactsp
)->psfa_act_alloc
) {
1259 /* need to grow file actions structure */
1260 if (_posix_spawn_file_actions_grow(psactsp
)) {
1266 * Allocate next available slot and fill it out
1268 psfileact
= &(*psactsp
)->psfa_act_acts
[(*psactsp
)->psfa_act_count
++];
1270 psfileact
->psfaa_type
= PSFA_CLOSE
;
1271 psfileact
->psfaa_filedes
= filedes
;
1278 * posix_spawn_file_actions_adddup2
1280 * Description: Add a dup2 action to the object referenced by 'file_actions'
1281 * that will cause the file referenced by 'filedes' to be
1282 * attempted to be dup2'ed to the descriptor 'newfiledes' in the
1285 * Parameters: file_actions File action object to augment
1286 * filedes fd to dup2
1287 * newfiledes fd to dup2 it to
1289 * Returns: 0 Success
1290 * EBADF The value specified by either fildes
1291 * or by newfiledes is negative or greater
1292 * than or equal to {OPEN_MAX}.
1293 * ENOMEM Insufficient memory exists to add to
1294 * the spawn file actions object.
1296 * NOTIMP: Allowed failures (checking NOT required):
1297 * EINVAL The value specified by file_actions is invalid.
1300 posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t
*file_actions
,
1301 int filedes
, int newfiledes
)
1303 _posix_spawn_file_actions_t
*psactsp
;
1304 _psfa_action_t
*psfileact
;
1306 if (file_actions
== NULL
|| *file_actions
== NULL
) {
1310 psactsp
= (_posix_spawn_file_actions_t
*)file_actions
;
1311 /* Range check; required by POSIX */
1312 if (filedes
< 0 || filedes
>= OPEN_MAX
||
1313 newfiledes
< 0 || newfiledes
>= OPEN_MAX
) {
1317 /* If we do not have enough slots, grow the structure */
1318 if ((*psactsp
)->psfa_act_count
== (*psactsp
)->psfa_act_alloc
) {
1319 /* need to grow file actions structure */
1320 if (_posix_spawn_file_actions_grow(psactsp
)) {
1326 * Allocate next available slot and fill it out
1328 psfileact
= &(*psactsp
)->psfa_act_acts
[(*psactsp
)->psfa_act_count
++];
1330 psfileact
->psfaa_type
= PSFA_DUP2
;
1331 psfileact
->psfaa_filedes
= filedes
;
1332 psfileact
->psfaa_dup2args
.psfad_newfiledes
= newfiledes
;
1338 * posix_spawn_file_actions_add_fileportdup2_np
1340 * Description: Add a dup2 action to the object referenced by 'file_actions'
1341 * that will cause the file referenced by 'fileport' to be
1342 * attempted to be dup2'ed to the descriptor 'newfiledes' in the
1345 * Parameters: file_actions File action object to augment
1346 * filedes fileport to dup2
1347 * newfiledes fd to dup2 it to
1349 * Returns: 0 Success
1350 * EBADF fileport isn't a valid port, or the
1351 * value specified by newfiledes is
1352 * negative or greater than or equal to
1354 * ENOMEM Insufficient memory exists to add to
1355 * the spawn file actions object.
1357 * NOTIMP: Allowed failures (checking NOT required):
1358 * EINVAL The value specified by file_actions is invalid.
1361 posix_spawn_file_actions_add_fileportdup2_np(
1362 posix_spawn_file_actions_t
*file_actions
,
1363 mach_port_t fileport
, int newfiledes
)
1365 _posix_spawn_file_actions_t
*psactsp
;
1366 _psfa_action_t
*psfileact
;
1368 if (file_actions
== NULL
|| *file_actions
== NULL
) {
1372 psactsp
= (_posix_spawn_file_actions_t
*)file_actions
;
1373 /* Range check; required by POSIX */
1374 if (!MACH_PORT_VALID(fileport
) ||
1375 newfiledes
< 0 || newfiledes
>= OPEN_MAX
) {
1379 /* If we do not have enough slots, grow the structure */
1380 if ((*psactsp
)->psfa_act_count
== (*psactsp
)->psfa_act_alloc
) {
1381 /* need to grow file actions structure */
1382 if (_posix_spawn_file_actions_grow(psactsp
)) {
1388 * Allocate next available slot and fill it out
1390 psfileact
= &(*psactsp
)->psfa_act_acts
[(*psactsp
)->psfa_act_count
++];
1392 psfileact
->psfaa_type
= PSFA_FILEPORT_DUP2
;
1393 psfileact
->psfaa_fileport
= fileport
;
1394 psfileact
->psfaa_dup2args
.psfad_newfiledes
= newfiledes
;
1400 * posix_spawn_file_actions_addinherit_np
1402 * Description: Add the "inherit" action to the object referenced by
1403 * 'file_actions' that will cause the file referenced by
1404 * 'filedes' to continue to be available in the spawned
1405 * process via the same descriptor.
1407 * Inheritance is the normal default behaviour for
1408 * file descriptors across exec and spawn; but if the
1409 * POSIX_SPAWN_CLOEXEC_DEFAULT flag is set, the usual
1410 * default is reversed for the purposes of the spawn
1411 * invocation. Any pre-existing descriptors that
1412 * need to be made available to the spawned process can
1413 * be marked explicitly as 'inherit' via this interface.
1414 * Otherwise they will be automatically closed.
1416 * Note that any descriptors created via the other file
1417 * actions interfaces are automatically marked as 'inherit'.
1419 * Parameters: file_actions File action object to augment
1420 * filedes fd to inherit.
1422 * Returns: 0 Success
1423 * EBADF The value specified by fildes is
1424 * negative or greater than or equal to
1426 * ENOMEM Insufficient memory exists to add to
1427 * the spawn file actions object.
1429 * NOTIMP: Allowed failures (checking NOT required):
1430 * EINVAL The value specified by file_actions is invalid.
1433 posix_spawn_file_actions_addinherit_np(posix_spawn_file_actions_t
*file_actions
,
1436 _posix_spawn_file_actions_t
*psactsp
;
1437 _psfa_action_t
*psfileact
;
1439 if (file_actions
== NULL
|| *file_actions
== NULL
) {
1443 psactsp
= (_posix_spawn_file_actions_t
*)file_actions
;
1444 /* Range check; required by POSIX */
1445 if (filedes
< 0 || filedes
>= OPEN_MAX
) {
1449 #if defined(POSIX_SPAWN_CLOEXEC_DEFAULT) // TODO: delete this check
1450 /* If we do not have enough slots, grow the structure */
1451 if ((*psactsp
)->psfa_act_count
== (*psactsp
)->psfa_act_alloc
) {
1452 /* need to grow file actions structure */
1453 if (_posix_spawn_file_actions_grow(psactsp
)) {
1459 * Allocate next available slot and fill it out
1461 psfileact
= &(*psactsp
)->psfa_act_acts
[(*psactsp
)->psfa_act_count
++];
1463 psfileact
->psfaa_type
= PSFA_INHERIT
;
1464 psfileact
->psfaa_filedes
= filedes
;
1471 * posix_spawn_file_actions_addchdir_np
1473 * Description: Add a chdir action to the object referenced by 'file_actions'
1474 * that will cause the current working directory to attempt to be changed
1475 * to that referenced by 'path' in the spawned process.
1477 * Parameters: file_actions File action object to augment
1478 * path path of the desired working directory
1480 * Returns: 0 Success
1481 * ENOMEM Insufficient memory exists to add to
1482 * the spawn file actions object.
1483 * ENAMETOOLONG The supplied path exceeded PATH_MAX.
1485 * NOTIMP: Allowed failures (checking NOT required):
1486 * EINVAL The value specified by file_actions is invalid.
1489 posix_spawn_file_actions_addchdir_np(
1490 posix_spawn_file_actions_t
* __restrict file_actions
,
1491 const char * __restrict path
)
1493 _posix_spawn_file_actions_t
*psactsp
;
1494 _psfa_action_t
*psfileact
;
1496 if (file_actions
== NULL
|| *file_actions
== NULL
) {
1500 psactsp
= (_posix_spawn_file_actions_t
*)file_actions
;
1502 /* If we do not have enough slots, grow the structure */
1503 if ((*psactsp
)->psfa_act_count
== (*psactsp
)->psfa_act_alloc
) {
1504 /* need to grow file actions structure */
1505 if (_posix_spawn_file_actions_grow(psactsp
)) {
1511 * Allocate next available slot and fill it out
1513 psfileact
= &(*psactsp
)->psfa_act_acts
[(*psactsp
)->psfa_act_count
++];
1515 psfileact
->psfaa_type
= PSFA_CHDIR
;
1516 if (strlcpy(psfileact
->psfaa_chdirargs
.psfac_path
, path
, PATH_MAX
) >= PATH_MAX
) {
1517 (*psactsp
)->psfa_act_count
--;
1518 return ENAMETOOLONG
;
1526 * posix_spawn_file_actions_fchdir_np
1528 * Description: Add a fchdir action to the object referenced by 'file_actions'
1529 * that will cause the current working directory to attempt to be changed
1530 * to that referenced by the descriptor 'filedes' in the spawned process.
1532 * Parameters: file_actions File action object to augment
1533 * filedes fd to chdir to
1535 * Returns: 0 Success
1536 * EBADF The value specified by either fildes is negative or
1537 * greater than or equal to {OPEN_MAX}.
1538 * ENOMEM Insufficient memory exists to add to
1539 * the spawn file actions object.
1541 * NOTIMP: Allowed failures (checking NOT required):
1542 * EINVAL The value specified by file_actions is invalid.
1545 posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t
*file_actions
,
1548 _posix_spawn_file_actions_t
*psactsp
;
1549 _psfa_action_t
*psfileact
;
1551 if (file_actions
== NULL
|| *file_actions
== NULL
) {
1555 psactsp
= (_posix_spawn_file_actions_t
*)file_actions
;
1556 /* Range check; in spirit of POSIX */
1557 if (filedes
< 0 || filedes
>= OPEN_MAX
) {
1561 /* If we do not have enough slots, grow the structure */
1562 if ((*psactsp
)->psfa_act_count
== (*psactsp
)->psfa_act_alloc
) {
1563 /* need to grow file actions structure */
1564 if (_posix_spawn_file_actions_grow(psactsp
)) {
1570 * Allocate next available slot and fill it out
1572 psfileact
= &(*psactsp
)->psfa_act_acts
[(*psactsp
)->psfa_act_count
++];
1574 psfileact
->psfaa_type
= PSFA_FCHDIR
;
1575 psfileact
->psfaa_filedes
= filedes
;
1581 posix_spawnattr_setcpumonitor_default(posix_spawnattr_t
* __restrict attr
)
1583 return posix_spawnattr_setcpumonitor(attr
, PROC_POLICY_CPUMON_DEFAULTS
, 0);
1587 posix_spawnattr_setcpumonitor(posix_spawnattr_t
* __restrict attr
,
1588 uint64_t percent
, uint64_t interval
)
1590 _posix_spawnattr_t psattr
;
1592 if (attr
== NULL
|| *attr
== NULL
) {
1596 psattr
= *(_posix_spawnattr_t
*)attr
;
1598 psattr
->psa_cpumonitor_percent
= percent
;
1599 psattr
->psa_cpumonitor_interval
= interval
;
1605 posix_spawnattr_getcpumonitor(posix_spawnattr_t
* __restrict attr
,
1606 uint64_t *percent
, uint64_t *interval
)
1608 _posix_spawnattr_t psattr
;
1610 if (attr
== NULL
|| *attr
== NULL
) {
1614 psattr
= *(_posix_spawnattr_t
*)attr
;
1616 *percent
= psattr
->psa_cpumonitor_percent
;
1617 *interval
= psattr
->psa_cpumonitor_interval
;
1622 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
1624 * posix_spawnattr_setjetsam
1626 * Description: Set jetsam attributes for the spawn attribute object
1627 * referred to by 'attr'.
1629 * Parameters: flags The flags value to set
1630 * priority Relative jetsam priority
1631 * memlimit Value in megabytes; a memory footprint
1632 * above this level may result in termination.
1633 * Implies both active and inactive limits.
1635 * Returns: 0 Success
1637 * Note: to be deprecated (not available on desktop)
1641 posix_spawnattr_setjetsam(posix_spawnattr_t
* __restrict attr
,
1642 short flags
, int priority
, int memlimit
)
1644 short flags_ext
= flags
;
1646 if (flags
& POSIX_SPAWN_JETSAM_MEMLIMIT_FATAL
) {
1647 flags_ext
|= POSIX_SPAWN_JETSAM_MEMLIMIT_ACTIVE_FATAL
;
1648 flags_ext
|= POSIX_SPAWN_JETSAM_MEMLIMIT_INACTIVE_FATAL
;
1650 flags_ext
&= ~POSIX_SPAWN_JETSAM_MEMLIMIT_ACTIVE_FATAL
;
1651 flags_ext
&= ~POSIX_SPAWN_JETSAM_MEMLIMIT_INACTIVE_FATAL
;
1654 return posix_spawnattr_setjetsam_ext(attr
, flags_ext
, priority
, memlimit
, memlimit
);
1656 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1659 * posix_spawnattr_setjetsam_ext
1661 * Description: Set jetsam attributes for the spawn attribute object
1662 * referred to by 'attr'.
1664 * Parameters: flags The flags value to set
1665 * priority Relative jetsam priority
1666 * memlimit_active Value in megabytes; memory footprint
1667 * above this level while process is
1668 * active may result in termination.
1669 * memlimit_inactive Value in megabytes; memory footprint
1670 * above this level while process is
1671 * inactive may result in termination.
1673 * Returns: 0 Success
1676 posix_spawnattr_setjetsam_ext(posix_spawnattr_t
* __restrict attr
,
1677 short flags
, int priority
, int memlimit_active
, int memlimit_inactive
)
1679 _posix_spawnattr_t psattr
;
1681 if (attr
== NULL
|| *attr
== NULL
) {
1685 psattr
= *(_posix_spawnattr_t
*)attr
;
1687 psattr
->psa_jetsam_flags
= flags
;
1688 psattr
->psa_jetsam_flags
|= POSIX_SPAWN_JETSAM_SET
;
1689 psattr
->psa_priority
= priority
;
1690 psattr
->psa_memlimit_active
= memlimit_active
;
1691 psattr
->psa_memlimit_inactive
= memlimit_inactive
;
1697 posix_spawnattr_set_threadlimit_ext(posix_spawnattr_t
* __restrict attr
,
1700 _posix_spawnattr_t psattr
;
1702 if (attr
== NULL
|| *attr
== NULL
) {
1706 psattr
= *(_posix_spawnattr_t
*)attr
;
1708 psattr
->psa_thread_limit
= thread_limit
;
1715 * posix_spawnattr_set_importancewatch_port_np
1717 * Description: Mark ports referred to by these rights
1718 * to boost the new task instead of their current task
1719 * for the spawn attribute object referred to by 'attr'.
1720 * Ports must be valid at posix_spawn time. They will NOT be
1721 * consumed by the kernel, so they must be deallocated after the spawn returns.
1722 * (If you are SETEXEC-ing, they are cleaned up by the exec operation).
1724 * The maximum number of watch ports allowed is defined by POSIX_SPAWN_IMPORTANCE_PORT_COUNT.
1726 * Parameters: count Number of ports in portarray
1727 * portarray Array of rights
1729 * Returns: 0 Success
1730 * EINVAL Bad port count
1731 * ENOMEM Insufficient memory exists to add to
1732 * the spawn port actions object.
1735 posix_spawnattr_set_importancewatch_port_np(posix_spawnattr_t
* __restrict attr
,
1736 int count
, mach_port_t portarray
[])
1740 if (count
< 0 || count
> POSIX_SPAWN_IMPORTANCE_PORT_COUNT
) {
1744 for (i
= 0; i
< count
; i
++) {
1745 _ps_port_action_t action
= {
1746 .port_type
= PSPA_IMP_WATCHPORTS
,
1747 .new_port
= portarray
[i
],
1749 err
= posix_spawn_appendportaction_np(attr
, &action
);
1758 posix_spawnattr_set_registered_ports_np(posix_spawnattr_t
* __restrict attr
,
1759 mach_port_t portarray
[], uint32_t count
)
1763 if (count
> TASK_PORT_REGISTER_MAX
) {
1767 for (uint32_t i
= 0; i
< count
; i
++) {
1768 _ps_port_action_t action
= {
1769 .port_type
= PSPA_REGISTERED_PORTS
,
1770 .new_port
= portarray
[i
],
1772 err
= posix_spawn_appendportaction_np(attr
, &action
);
1782 _ps_mac_policy_extension_t
*
1783 posix_spawnattr_macpolicyinfo_lookup(_posix_spawn_mac_policy_extensions_t psmx
, const char *policyname
)
1791 for (i
= 0; i
< psmx
->psmx_count
; i
++) {
1792 _ps_mac_policy_extension_t
*extension
= &psmx
->psmx_extensions
[i
];
1793 if (strcmp(extension
->policyname
, policyname
) == 0) {
1801 posix_spawnattr_getmacpolicyinfo_np(const posix_spawnattr_t
* __restrict attr
,
1802 const char *policyname
, void **datap
, size_t *datalenp
)
1804 _posix_spawnattr_t psattr
;
1805 _ps_mac_policy_extension_t
*extension
;
1807 if (attr
== NULL
|| *attr
== NULL
|| policyname
== NULL
|| datap
== NULL
) {
1811 psattr
= *(_posix_spawnattr_t
*)attr
;
1812 extension
= posix_spawnattr_macpolicyinfo_lookup(psattr
->psa_mac_extensions
, policyname
);
1813 if (extension
== NULL
) {
1816 *datap
= (void *)(uintptr_t)extension
->data
;
1817 if (datalenp
!= NULL
) {
1818 *datalenp
= (size_t)extension
->datalen
;
1824 posix_spawnattr_setmacpolicyinfo_np(posix_spawnattr_t
* __restrict attr
,
1825 const char *policyname
, void *data
, size_t datalen
)
1827 _posix_spawnattr_t psattr
;
1828 _posix_spawn_mac_policy_extensions_t psmx
;
1829 _ps_mac_policy_extension_t
*extension
;
1831 if (attr
== NULL
|| *attr
== NULL
|| policyname
== NULL
) {
1835 psattr
= *(_posix_spawnattr_t
*)attr
;
1836 psmx
= psattr
->psa_mac_extensions
;
1837 extension
= posix_spawnattr_macpolicyinfo_lookup(psattr
->psa_mac_extensions
, policyname
);
1838 if (extension
!= NULL
) {
1839 extension
->data
= (uintptr_t)data
;
1840 extension
->datalen
= datalen
;
1842 } else if (psmx
== NULL
) {
1843 psmx
= psattr
->psa_mac_extensions
= malloc(PS_MAC_EXTENSIONS_SIZE(PS_MAC_EXTENSIONS_INIT_COUNT
));
1847 psmx
->psmx_alloc
= PS_MAC_EXTENSIONS_INIT_COUNT
;
1848 psmx
->psmx_count
= 0;
1849 } else if (psmx
->psmx_count
== psmx
->psmx_alloc
) {
1851 if (os_mul_overflow(psmx
->psmx_alloc
, 2, &newnum
)) {
1854 size_t extsize
= PS_MAC_EXTENSIONS_SIZE(newnum
);
1858 psmx
= psattr
->psa_mac_extensions
= reallocf(psmx
, extsize
);
1862 psmx
->psmx_alloc
= newnum
;
1864 extension
= &psmx
->psmx_extensions
[psmx
->psmx_count
];
1865 strlcpy(extension
->policyname
, policyname
, sizeof(extension
->policyname
));
1866 extension
->data
= (uintptr_t)data
;
1867 extension
->datalen
= datalen
;
1868 psmx
->psmx_count
+= 1;
1873 * posix_spawn_destroymacpolicy_info_np
1874 * Description: cleanup the macpolicy struct in posix_spawnattr_t attr
1877 posix_spawn_destroymacpolicy_info_np(posix_spawnattr_t
*attr
)
1879 _posix_spawnattr_t psattr
;
1880 _posix_spawn_mac_policy_extensions_t psmx
;
1882 if (attr
== NULL
|| *attr
== NULL
) {
1886 psattr
= *(_posix_spawnattr_t
*)attr
;
1887 psmx
= psattr
->psa_mac_extensions
;
1892 psattr
->psa_mac_extensions
= NULL
;
1898 posix_spawnattr_setcoalition_np(const posix_spawnattr_t
* __restrict attr
,
1899 uint64_t coalitionid
, int type
, int role
)
1901 _posix_spawnattr_t psattr
;
1902 struct _posix_spawn_coalition_info
*coal_info
;
1904 if (attr
== NULL
|| *attr
== NULL
) {
1907 if (type
< 0 || type
> COALITION_TYPE_MAX
) {
1911 psattr
= *(_posix_spawnattr_t
*)attr
;
1913 coal_info
= psattr
->psa_coalition_info
;
1915 coal_info
= (struct _posix_spawn_coalition_info
*)malloc(sizeof(*coal_info
));
1919 memset(coal_info
, 0, sizeof(*coal_info
));
1920 psattr
->psa_coalition_info
= coal_info
;
1923 coal_info
->psci_info
[type
].psci_id
= coalitionid
;
1924 coal_info
->psci_info
[type
].psci_role
= role
;
1931 posix_spawnattr_set_qos_clamp_np(const posix_spawnattr_t
* __restrict attr
, uint64_t qos_clamp
)
1933 _posix_spawnattr_t psattr
;
1935 if (attr
== NULL
|| *attr
== NULL
) {
1939 if (qos_clamp
>= POSIX_SPAWN_PROC_CLAMP_LAST
) {
1943 psattr
= *(_posix_spawnattr_t
*)attr
;
1944 psattr
->psa_qos_clamp
= qos_clamp
;
1950 posix_spawnattr_get_qos_clamp_np(const posix_spawnattr_t
* __restrict attr
, uint64_t * __restrict qos_clampp
)
1952 _posix_spawnattr_t psattr
;
1954 if (attr
== NULL
|| *attr
== NULL
) {
1958 psattr
= *(_posix_spawnattr_t
*)attr
;
1959 *qos_clampp
= psattr
->psa_qos_clamp
;
1965 posix_spawnattr_set_darwin_role_np(const posix_spawnattr_t
* __restrict attr
, uint64_t darwin_role
)
1967 _posix_spawnattr_t psattr
;
1969 if (attr
== NULL
|| *attr
== NULL
) {
1973 psattr
= *(_posix_spawnattr_t
*)attr
;
1974 psattr
->psa_darwin_role
= darwin_role
;
1980 posix_spawnattr_get_darwin_role_np(const posix_spawnattr_t
* __restrict attr
, uint64_t * __restrict darwin_rolep
)
1982 _posix_spawnattr_t psattr
;
1984 if (attr
== NULL
|| *attr
== NULL
) {
1988 psattr
= *(_posix_spawnattr_t
*)attr
;
1989 *darwin_rolep
= psattr
->psa_darwin_role
;
1996 posix_spawnattr_set_persona_np(const posix_spawnattr_t
* __restrict attr
, uid_t persona_id
, uint32_t flags
)
1998 _posix_spawnattr_t psattr
;
1999 struct _posix_spawn_persona_info
*persona
;
2001 if (attr
== NULL
|| *attr
== NULL
) {
2005 if (flags
& ~POSIX_SPAWN_PERSONA_ALL_FLAGS
) {
2009 psattr
= *(_posix_spawnattr_t
*)attr
;
2011 persona
= psattr
->psa_persona_info
;
2013 persona
= (struct _posix_spawn_persona_info
*)malloc(sizeof(*persona
));
2017 persona
->pspi_uid
= 0;
2018 persona
->pspi_gid
= 0;
2019 persona
->pspi_ngroups
= 0;
2020 persona
->pspi_groups
[0] = 0;
2021 persona
->pspi_gmuid
= 0;
2023 psattr
->psa_persona_info
= persona
;
2026 persona
->pspi_id
= persona_id
;
2027 persona
->pspi_flags
= flags
;
2033 posix_spawnattr_set_persona_uid_np(const posix_spawnattr_t
* __restrict attr
, uid_t uid
)
2035 _posix_spawnattr_t psattr
;
2036 struct _posix_spawn_persona_info
*persona
;
2038 if (attr
== NULL
|| *attr
== NULL
) {
2042 psattr
= *(_posix_spawnattr_t
*)attr
;
2043 persona
= psattr
->psa_persona_info
;
2048 if (!(persona
->pspi_flags
& (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE
| POSIX_SPAWN_PERSONA_FLAGS_VERIFY
))) {
2052 persona
->pspi_uid
= uid
;
2054 persona
->pspi_flags
|= POSIX_SPAWN_PERSONA_UID
;
2060 posix_spawnattr_set_persona_gid_np(const posix_spawnattr_t
* __restrict attr
, gid_t gid
)
2062 _posix_spawnattr_t psattr
;
2063 struct _posix_spawn_persona_info
*persona
;
2065 if (attr
== NULL
|| *attr
== NULL
) {
2069 psattr
= *(_posix_spawnattr_t
*)attr
;
2070 persona
= psattr
->psa_persona_info
;
2075 if (!(persona
->pspi_flags
& (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE
| POSIX_SPAWN_PERSONA_FLAGS_VERIFY
))) {
2079 persona
->pspi_gid
= gid
;
2081 persona
->pspi_flags
|= POSIX_SPAWN_PERSONA_GID
;
2087 posix_spawnattr_set_persona_groups_np(const posix_spawnattr_t
* __restrict attr
, int ngroups
, gid_t
*gidarray
, uid_t gmuid
)
2089 _posix_spawnattr_t psattr
;
2090 struct _posix_spawn_persona_info
*persona
;
2092 if (attr
== NULL
|| *attr
== NULL
) {
2096 if (gidarray
== NULL
) {
2100 if (ngroups
> NGROUPS
|| ngroups
< 0) {
2104 psattr
= *(_posix_spawnattr_t
*)attr
;
2105 persona
= psattr
->psa_persona_info
;
2110 if (!(persona
->pspi_flags
& (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE
| POSIX_SPAWN_PERSONA_FLAGS_VERIFY
))) {
2114 persona
->pspi_ngroups
= ngroups
;
2115 for (int i
= 0; i
< ngroups
; i
++) {
2116 persona
->pspi_groups
[i
] = gidarray
[i
];
2119 persona
->pspi_gmuid
= gmuid
;
2121 persona
->pspi_flags
|= POSIX_SPAWN_PERSONA_GROUPS
;
2127 posix_spawnattr_set_max_addr_np(const posix_spawnattr_t
* __restrict attr
, uint64_t max_addr
)
2129 _posix_spawnattr_t psattr
;
2131 if (attr
== NULL
|| *attr
== NULL
) {
2135 psattr
= *(_posix_spawnattr_t
*)attr
;
2136 psattr
->psa_max_addr
= max_addr
;
2141 static struct _posix_spawn_posix_cred_info
*
2142 _posix_spawnattr_get_posix_creds_info(_posix_spawnattr_t psattr
)
2144 struct _posix_spawn_posix_cred_info
*pspci
= psattr
->psa_posix_cred_info
;
2146 if (pspci
== NULL
) {
2147 pspci
= malloc(sizeof(struct _posix_spawn_posix_cred_info
));
2148 if (pspci
!= NULL
) {
2149 pspci
->pspci_flags
= 0;
2150 pspci
->pspci_uid
= 0;
2151 pspci
->pspci_gid
= 0;
2152 pspci
->pspci_ngroups
= 0;
2153 pspci
->pspci_groups
[0] = 0;
2154 pspci
->pspci_gmuid
= 0;
2155 pspci
->pspci_login
[0] = '\0';
2156 psattr
->psa_posix_cred_info
= pspci
;
2163 posix_spawnattr_set_uid_np(const posix_spawnattr_t
*attr
, uid_t uid
)
2165 struct _posix_spawn_posix_cred_info
*pspci
;
2167 if (attr
== NULL
|| *attr
== NULL
) {
2171 pspci
= _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t
*)attr
);
2172 if (pspci
== NULL
) {
2176 pspci
->pspci_uid
= uid
;
2178 pspci
->pspci_flags
|= POSIX_SPAWN_POSIX_CRED_UID
;
2184 posix_spawnattr_set_gid_np(const posix_spawnattr_t
*attr
, gid_t gid
)
2186 struct _posix_spawn_posix_cred_info
*pspci
;
2188 if (attr
== NULL
|| *attr
== NULL
) {
2192 pspci
= _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t
*)attr
);
2193 if (pspci
== NULL
) {
2197 pspci
->pspci_gid
= gid
;
2199 pspci
->pspci_flags
|= POSIX_SPAWN_POSIX_CRED_GID
;
2205 posix_spawnattr_set_groups_np(const posix_spawnattr_t
*attr
,
2206 int ngroups
, gid_t
*gidarray
, uid_t gmuid
)
2208 struct _posix_spawn_posix_cred_info
*pspci
;
2210 if (attr
== NULL
|| *attr
== NULL
) {
2214 if (gidarray
== NULL
) {
2218 if (ngroups
> NGROUPS
|| ngroups
< 0) {
2222 pspci
= _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t
*)attr
);
2223 if (pspci
== NULL
) {
2227 pspci
->pspci_ngroups
= ngroups
;
2228 for (int i
= 0; i
< ngroups
; i
++) {
2229 pspci
->pspci_groups
[i
] = gidarray
[i
];
2232 pspci
->pspci_gmuid
= gmuid
;
2234 pspci
->pspci_flags
|= POSIX_SPAWN_POSIX_CRED_GROUPS
;
2240 posix_spawnattr_set_login_np(const posix_spawnattr_t
*attr
, const char *login
)
2242 struct _posix_spawn_posix_cred_info
*pspci
;
2244 if (attr
== NULL
|| *attr
== NULL
) {
2248 if (strlen(login
) > MAXLOGNAME
) {
2252 pspci
= _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t
*)attr
);
2253 if (pspci
== NULL
) {
2257 strlcpy(pspci
->pspci_login
, login
, sizeof(pspci
->pspci_login
));
2259 pspci
->pspci_flags
|= POSIX_SPAWN_POSIX_CRED_LOGIN
;
2265 * posix_spawnattr_set_jetsam_ttr_np
2267 * Description: Pass data regarding recent relaunch behavior when jetsammed for the process.
2268 * The recent history is effectively converted into a histogram and the highest
2269 * frequency bucket defines the "type" of the process. The type is passed along
2270 * to the jetsam code as part of psa_jetsam_flags.
2272 * Parameters: count Number of entries in the ttrs_millis array
2273 * ttrs_millis Array of raw data for relaunch behavior
2275 * Returns: 0 Success
2276 * EINVAL Bad attr pointer or empty data array
2279 posix_spawnattr_set_jetsam_ttr_np(const posix_spawnattr_t
* __restrict attr
, uint32_t count
, uint32_t *ttrs_millis
)
2281 _posix_spawnattr_t psattr
;
2284 * Define the bucketizing policy which would be used to generate the histogram. These
2285 * values are based on looking at data from various Avg. Joanna runs.
2287 static const uint32_t relaunch_buckets_msecs
[POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS
] = {
2292 static const uint32_t relaunch_jetsam_flags
[POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS
] = {
2293 POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_HIGH
,
2294 POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_MED
,
2295 POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_LOW
2298 /* Make sure the attr pointer is valid */
2299 if (attr
== NULL
|| *attr
== NULL
) {
2303 /* Make sure the count of entries is non-zero */
2308 psattr
= *(_posix_spawnattr_t
*)attr
;
2310 /* Generate a histogram based on the relaunch data while maintaining highest frequency bucket info */
2311 int relaunch_histogram
[POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS
] = {0};
2312 int max_frequency
= -1;
2313 int highest_frequency_bucket
= -1;
2315 for (uint32_t i
= 0; i
< count
; i
++) {
2316 /* For each data point passed in via launchd, find the bucket it lands in */
2317 for (uint32_t bucket
= 0; bucket
< POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS
; bucket
++) {
2318 if (ttrs_millis
[i
] <= relaunch_buckets_msecs
[bucket
]) {
2319 relaunch_histogram
[bucket
]++;
2321 /* Check if the bucket is the highest frequency bucket now */
2322 if (relaunch_histogram
[bucket
] > max_frequency
) {
2323 max_frequency
= relaunch_histogram
[bucket
];
2324 highest_frequency_bucket
= bucket
;
2330 psattr
->psa_jetsam_flags
|= relaunch_jetsam_flags
[highest_frequency_bucket
];
2337 * Description: Create a new process from the process image corresponding to
2338 * the supplied 'path' argument.
2340 * Parameters: pid Pointer to pid_t to receive the
2341 * PID of the spawned process, if
2342 * successful and 'pid' != NULL
2343 * path Path of image file to spawn
2344 * file_actions spawn file actions object which
2345 * describes file actions to be
2346 * performed during the spawn
2347 * attrp spawn attributes object which
2348 * describes attributes to be
2349 * applied during the spawn
2350 * argv argument vector array; NULL
2352 * envp environment vector array; NULL
2355 * Returns: 0 Success
2356 * !0 An errno value indicating the
2357 * cause of the failure to spawn
2359 * Notes: Unlike other system calls, the return value of this system
2360 * call is expected to either be a 0 or an errno, rather than a
2361 * 0 or a -1, with the 'errno' variable being set.
2363 extern int __posix_spawn(pid_t
* __restrict
, const char * __restrict
,
2364 struct _posix_spawn_args_desc
*,
2365 char *const argv
[__restrict
], char *const envp
[__restrict
]);
2368 posix_spawn(pid_t
* __restrict pid
, const char * __restrict path
,
2369 const posix_spawn_file_actions_t
*file_actions
,
2370 const posix_spawnattr_t
* __restrict attrp
,
2371 char *const argv
[__restrict
], char *const envp
[__restrict
])
2373 int saveerrno
= errno
;
2376 * Only do extra work if we have file actions or attributes to push
2377 * down. We use a descriptor to push this information down, since we
2378 * want to have size information, which will let us (1) preallocate a
2379 * single chunk of memory for the copyin(), and (2) allow us to do a
2380 * single copyin() per attributes or file actions as a monlithic block.
2382 * Note: A future implementation may attempt to do the same
2383 * thing for the argv/envp data, which could potentially
2384 * result in a performance improvement due to increased
2385 * kernel efficiency, even though it would mean copying
2386 * the data in user space.
2388 if ((file_actions
!= NULL
&& (*file_actions
!= NULL
) && (*(_posix_spawn_file_actions_t
*)file_actions
)->psfa_act_count
> 0) || attrp
!= NULL
) {
2389 struct _posix_spawn_args_desc ad
;
2391 memset(&ad
, 0, sizeof(ad
));
2392 if (attrp
!= NULL
&& *attrp
!= NULL
) {
2393 _posix_spawnattr_t psattr
= *(_posix_spawnattr_t
*)attrp
;
2394 ad
.attr_size
= sizeof(struct _posix_spawnattr
);
2397 if (psattr
->psa_ports
!= NULL
) {
2398 size_t psact_size
= PS_PORT_ACTIONS_SIZE(psattr
->psa_ports
->pspa_count
);
2399 if (psact_size
== 0 && psattr
->psa_ports
->pspa_count
!= 0) {
2404 ad
.port_actions
= psattr
->psa_ports
;
2405 ad
.port_actions_size
= psact_size
;
2407 if (psattr
->psa_mac_extensions
!= NULL
) {
2408 size_t macext_size
= PS_MAC_EXTENSIONS_SIZE(psattr
->psa_mac_extensions
->psmx_count
);
2409 if (macext_size
== 0 && psattr
->psa_mac_extensions
->psmx_count
!= 0) {
2414 ad
.mac_extensions
= psattr
->psa_mac_extensions
;
2415 ad
.mac_extensions_size
= macext_size
;
2417 if (psattr
->psa_coalition_info
!= NULL
) {
2418 ad
.coal_info_size
= sizeof(struct _posix_spawn_coalition_info
);
2419 ad
.coal_info
= psattr
->psa_coalition_info
;
2421 if (psattr
->psa_persona_info
!= NULL
) {
2422 ad
.persona_info_size
= sizeof(struct _posix_spawn_persona_info
);
2423 ad
.persona_info
= psattr
->psa_persona_info
;
2425 if (psattr
->psa_posix_cred_info
!= NULL
) {
2426 ad
.posix_cred_info_size
= sizeof(struct _posix_spawn_posix_cred_info
);
2427 ad
.posix_cred_info
= psattr
->psa_posix_cred_info
;
2430 if (file_actions
!= NULL
&& *file_actions
!= NULL
) {
2431 _posix_spawn_file_actions_t psactsp
=
2432 *(_posix_spawn_file_actions_t
*)file_actions
;
2434 if (psactsp
->psfa_act_count
> 0) {
2435 size_t fa_size
= PSF_ACTIONS_SIZE(psactsp
->psfa_act_count
);
2436 if (fa_size
== 0 && psactsp
->psfa_act_count
!= 0) {
2441 ad
.file_actions_size
= fa_size
;
2442 ad
.file_actions
= psactsp
;
2446 ret
= __posix_spawn(pid
, path
, &ad
, argv
, envp
);
2448 ret
= __posix_spawn(pid
, path
, NULL
, argv
, envp
);