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