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