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