]> git.saurik.com Git - apple/libc.git/blame - sys/posix_spawn.c
Libc-498.1.5.tar.gz
[apple/libc.git] / sys / posix_spawn.c
CommitLineData
224c7076
A
1/*
2 * Copyright (c) 2006 Apple Computer, 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#include <sys/types.h> /* for user_size_t */
29#include <spawn.h>
30#include <sys/spawn_internal.h>
31#include <stdlib.h>
32#include <errno.h>
33#include <limits.h> /* for OPEN_MAX, PATH_MAX */
34#include <stddef.h> /* for offsetof() */
35#include <string.h> /* for strlcpy() */
36#include <paths.h> /* for _PATH_DEFPATH */
37#include <sys/stat.h> /* for struct stat */
38#include <mach/port.h>
39#include <mach/exception_types.h>
40
41
42/*
43 * posix_spawnattr_init
44 *
45 * Description: Initialize a spawn attributes object attr with default values
46 *
47 * Parameters: attr The spawn attributes object to be
48 * initialized
49 *
50 * Returns: 0 Success
51 * ENOMEM Insufficient memory exists to
52 * initialize the spawn attributes object.
53 *
54 * Note: As an implementation detail, the externally visibily type
55 * posix_spawnattr_t is defined to be a void *, and initialization
56 * involves allocation of a memory object. Subsequent changes to
57 * the spawn attributes may result in reallocation under the
58 * covers.
59 *
60 * Reinitialization of an already initialized spawn attributes
61 * object will result in memory being leaked. Because spawn
62 * attributes are not required to be used in conjunction with a
63 * static initializer, there is no way to distinguish a spawn
64 * attribute with stack garbage from one that's been initialized.
65 * This is arguably an API design error.
66 */
67int
68posix_spawnattr_init(posix_spawnattr_t *attr)
69{
70 _posix_spawnattr_t *psattrp = (_posix_spawnattr_t *)attr;
71 int err = 0;
72
73 if ((*psattrp = (_posix_spawnattr_t)malloc(sizeof(struct _posix_spawnattr))) == NULL) {
74 err = ENOMEM;
75 } else {
76
77 /*
78 * The default value of this attribute shall be as if no
79 * flags were set
80 */
81 (*psattrp)->psa_flags = 0;
82
83 /*
84 * The default value of this attribute shall be an empty
85 * signal set
86 */
87 (*psattrp)->psa_sigdefault = 0;
88
89 /* The default value of this attribute is unspecified */
90 (*psattrp)->psa_sigmask = 0;
91
92 /* The default value of this attribute shall be zero */
93 (*psattrp)->psa_pgroup = 0; /* doesn't matter */
94
95 /* Default is no binary preferences, i.e. use normal grading */
96 memset((*psattrp)->psa_binprefs, 0,
97 sizeof((*psattrp)->psa_binprefs));
98
99 /* Default is no port actions to take */
100 (*psattrp)->psa_ports = NULL;
101 }
102
103 return (err);
104}
105
106
107/*
108 * posix_spawnattr_destroy
109 *
110 * Description: Destroy a spawn attributes object that was previously
111 * initialized via posix_spawnattr_init() by freeing any
112 * memory associated with it and setting it to an invalid value.
113 *
114 * Parameters: attr The spawn attributes object to be
115 * destroyed.
116 *
117 * Returns: 0 Success
118 *
119 * Notes: The destroyed spawn attribute results in the void * pointer
120 * being set to NULL; subsequent use without reinitialization
121 * will result in explicit program failure (rather than merely
122 * "undefined behaviour").
123 *
124 * NOTIMP: Allowed failures (checking NOT required):
125 * EINVAL The value specified by attr is invalid.
126 */
127int
128posix_spawnattr_destroy(posix_spawnattr_t *attr)
129{
130 _posix_spawnattr_t psattr;
131
132 if (attr == NULL || *attr == NULL)
133 return EINVAL;
134
135 psattr = *(_posix_spawnattr_t *)attr;
136 posix_spawn_destroyportactions_np(attr);
137
138 free(psattr);
139 *attr = NULL;
140
141 return (0);
142}
143
144
145/*
146 * posix_spawnattr_setflags
147 *
148 * Description: Set the spawn flags attribute for the spawn attribute object
149 * referred to by 'attr'.
150 *
151 * Parameters: attr The spawn attributes object whose flags
152 * are to be set
153 * flags The flags value to set
154 *
155 * Returns: 0 Success
156 *
157 * NOTIMP: Allowed failures (checking NOT required):
158 * EINVAL The value specified by attr is invalid.
159 * EINVAL The value of the attribute being set is not valid.
160 */
161int
162posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
163{
164 _posix_spawnattr_t psattr;
165
166 if (attr == NULL || *attr == NULL)
167 return EINVAL;
168
169 psattr = *(_posix_spawnattr_t *)attr;
170 psattr->psa_flags = flags;
171
172 return (0);
173}
174
175
176/*
177 * posix_spawnattr_getflags
178 *
179 * Description: Retrieve the spawn attributes flag for the spawn attributes
180 * object referenced by 'attr' and place them in the memory
181 * location referenced by 'flagsp'
182 *
183 * Parameters: attr The spawn attributes object whose flags
184 * are to be retrieved
185 * flagsp A pointer to a short value to receive
186 * the flags
187 *
188 * Returns: 0 Success
189 *
190 * Implicit Returns:
191 * *flagps (modified) The flags value from the spawn
192 * attributes object
193 *
194 * NOTIMP: Allowed failures (checking NOT required):
195 * EINVAL The value specified by attr is invalid.
196 * EINVAL The value of the attribute being set is not valid.
197 */
198int
199posix_spawnattr_getflags(const posix_spawnattr_t * __restrict attr,
200 short * __restrict flagsp)
201{
202 _posix_spawnattr_t psattr;
203
204 if (attr == NULL || *attr == NULL)
205 return EINVAL;
206
207 psattr = *(_posix_spawnattr_t *)attr;
208 *flagsp = psattr->psa_flags;
209
210 return (0);
211}
212
213
214/*
215 * posix_spawnattr_getsigdefault
216 *
217 * Description: Retrieve the set of signals to be set to default according to
218 * the spawn attribute value referenced by 'attr' and place the
219 * result into the memory containing the sigset_t referenced by
220 * 'sigdefault'
221 *
222 * Parameters: attr The spawn attributes object whose
223 * signal set for default signals is to
224 * be retrieved
225 * sigdefault A pointer to the sigset_t to receive
226 * the signal set
227 *
228 * Returns: 0 Success
229 *
230 * Implicit Returns:
231 * *sigdefault (modified) The signal set of signals to default
232 * from the spawn attributes object
233 */
234int
235posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict attr,
236 sigset_t * __restrict sigdefault)
237{
238 _posix_spawnattr_t psattr;
239
240 if (attr == NULL || *attr == NULL)
241 return EINVAL;
242
243 psattr = *(_posix_spawnattr_t *)attr;
244 *sigdefault = psattr->psa_sigdefault;
245
246 return (0);
247}
248
249
250/*
251 * posix_spawnattr_getpgroup
252 *
253 * Description: Obtain the value of the spawn process group attribute from the
254 * spawn attributes object referenced by 'attr' and place the
255 * results in the memory location referenced by 'pgroup'
256 *
257 * Parameters: attr The spawn attributes object whose
258 * process group information is to be
259 * retrieved
260 * pgroup A pointer to the pid_t to receive the
261 * process group
262 *
263 * Returns: 0 Success
264 *
265 * Implicit Returns:
266 * *pgroup (modified) The process group information from the
267 * spawn attributes object
268 */
269int
270posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict attr,
271 pid_t * __restrict pgroup)
272{
273 _posix_spawnattr_t psattr;
274
275 if (attr == NULL || *attr == NULL)
276 return EINVAL;
277
278 psattr = *(_posix_spawnattr_t *)attr;
279 *pgroup = psattr->psa_pgroup;
280
281 return (0);
282}
283
284
285/*
286 * posix_spawnattr_getsigmask
287 *
288 * Description: Obtain the value of the spawn signal mask attribute from the
289 * spawn attributes object referenced by 'attr' and place the
290 * result into the memory containing the sigset_t referenced by
291 * 'sigmask'
292 *
293 * Parameters: attr The spawn attributes object whose
294 * signal set for masked signals is to
295 * be retrieved
296 * sigmask A pointer to the sigset_t to receive
297 * the signal set
298 *
299 * Returns: 0 Success
300 *
301 * Implicit Returns:
302 * *sigmask (modified) The signal set of signals to mask
303 * from the spawn attributes object
304 */
305int
306posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict attr,
307 sigset_t * __restrict sigmask)
308{
309 _posix_spawnattr_t psattr;
310
311 if (attr == NULL || *attr == NULL)
312 return EINVAL;
313
314 psattr = *(_posix_spawnattr_t *)attr;
315 *sigmask = psattr->psa_sigmask;
316
317 return (0);
318}
319
320/*
321 * posix_spawnattr_getbinpref_np
322 *
323 * Description: Obtain the value of the spawn binary preferences attribute from
324 * the spawn attributes object referenced by 'attr' and place the
325 * result into the memory referenced by 'pref'.
326 *
327 * Parameters: attr The spawn attributes object whose
328 * binary preferences are to be retrieved
329 * count The size of the cpu_type_t array
330 * pref An array of cpu types
331 * ocount The actual number copied
332 *
333 * Returns: 0 No binary preferences found
334 * > 0 The number of cpu types (less than
335 * count) copied over from 'attr'.
336 *
337 * Implicit Returns:
338 * *pref (modified) The binary preferences array
339 * from the spawn attributes object
340 */
341int
342posix_spawnattr_getbinpref_np(const posix_spawnattr_t * __restrict attr,
343 size_t count, cpu_type_t *pref, size_t * __restrict ocount)
344{
345 _posix_spawnattr_t psattr;
346 int i = 0;
347
348 if (attr == NULL || *attr == NULL)
349 return EINVAL;
350
351 psattr = *(_posix_spawnattr_t *)attr;
352 for (i = 0; i < count && i < 4; i++) {
353 pref[i] = psattr->psa_binprefs[i];
354 }
355
356 if (ocount)
357 *ocount = i;
358 return 0;
359}
360/*
361 * posix_spawnattr_setsigdefault
362 *
363 * Description: Set the set of signals to be set to default for the spawn
364 * attribute value referenced by 'attr' from the memory
365 * containing the sigset_t referenced by 'sigdefault'
366 *
367 * Parameters: attr The spawn attributes object whose
368 * signal set for default signals is to
369 * be set
370 * sigdefault A pointer to the sigset_t from which to
371 * obtain the signal set
372 *
373 * Returns: 0 Success
374 */
375int
376posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict attr,
377 const sigset_t * __restrict sigdefault)
378{
379 _posix_spawnattr_t psattr;
380
381 if (attr == NULL || *attr == NULL)
382 return EINVAL;
383
384 psattr = *(_posix_spawnattr_t *)attr;
385 psattr->psa_sigdefault = *sigdefault;
386
387 return (0);
388}
389
390
391/*
392 * posix_spawnattr_setpgroup
393 *
394 * Description: Set the value of the spawn process group attribute for the
395 * spawn attributes object referenced by 'attr' from the value
396 * of 'pgroup'
397 *
398 * Parameters: attr The spawn attributes object for which
399 * the process group information is to be
400 * set
401 * pgroup The process group to set
402 *
403 * Returns: 0 Success
404 */
405int
406posix_spawnattr_setpgroup(posix_spawnattr_t * attr, pid_t pgroup)
407{
408 _posix_spawnattr_t psattr;
409
410 if (attr == NULL || *attr == NULL)
411 return EINVAL;
412
413 psattr = *(_posix_spawnattr_t *)attr;
414 psattr->psa_pgroup = pgroup;
415
416 return (0);
417}
418
419
420/*
421 * posix_spawnattr_setsigmask
422 *
423 * Description: Set the set of signals to be masked for the spawn attribute
424 * value referenced by 'attr' from the memory containing the
425 * sigset_t referenced by 'sigmask'
426 *
427 * Parameters: attr The spawn attributes object whose
428 * signal set for masked signals is to
429 * be set
430 * sigmask A pointer to the sigset_t from which to
431 * obtain the signal set
432 *
433 * Returns: 0 Success
434 */
435int
436posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict attr,
437 const sigset_t * __restrict sigmask)
438{
439 _posix_spawnattr_t psattr;
440
441 if (attr == NULL || *attr == NULL)
442 return EINVAL;
443
444 psattr = *(_posix_spawnattr_t *)attr;
445 psattr->psa_sigmask = *sigmask;
446
447 return (0);
448}
449
450
451/*
452 * posix_spawnattr_setbinpref_np
453 *
454 * Description: Set the universal binary preferences for the spawn attribute
455 * value referenced by 'attr' from the memory containing the
456 * cpu_type_t array referenced by 'pref', size of 'count'
457 *
458 * Parameters: attr The spawn attributes object whose
459 * binary preferences are to be set
460 * count Size of the array pointed to by 'pref'
461 * pref cpu_type_t array of binary preferences
462 * ocount The actual number copied
463 *
464 * Returns: 0 No preferences copied
465 * > 0 Number of preferences copied
466 *
467 * Note: The posix_spawnattr_t currently only holds four cpu_type_t's.
468 * If the caller provides more preferences than this limit, they
469 * will be ignored, as reflected in the return value.
470 */
471int
472posix_spawnattr_setbinpref_np(posix_spawnattr_t * __restrict attr,
473 size_t count, cpu_type_t *pref, size_t * __restrict ocount)
474{
475 _posix_spawnattr_t psattr;
476 int i = 0;
477
478 if (attr == NULL || *attr == NULL)
479 return EINVAL;
480
481 psattr = *(_posix_spawnattr_t *)attr;
482 for (i = 0; i < count && i < 4; i++) {
483 psattr->psa_binprefs[i] = pref[i];
484 }
485
486 /* return number of binprefs copied over */
487 if (ocount)
488 *ocount = i;
489 return 0;
490}
491
492/*
493 * posix_spawn_createportactions_np
494 * Description: create a new posix_spawn_port_actions struct and link
495 * it into the posix_spawnattr.
496 */
497int
498posix_spawn_createportactions_np(posix_spawnattr_t *attr)
499{
500 _posix_spawnattr_t psattr;
501 _posix_spawn_port_actions_t acts;
502
503 if (attr == NULL || *attr == NULL)
504 return EINVAL;
505
506 psattr = *(_posix_spawnattr_t *)attr;
507 acts = (_posix_spawn_port_actions_t)malloc(PS_PORT_ACTIONS_SIZE(2));
508 if (acts == NULL)
509 return ENOMEM;
510
511 acts->pspa_alloc = 2;
512 acts->pspa_count = 0;
513
514 psattr->psa_ports = acts;
515 return 0;
516}
517
518/*
519 * posix_spawn_growportactions_np
520 * Description: Enlarge the size of portactions if necessary
521 */
522int
523posix_spawn_growportactions_np(posix_spawnattr_t *attr)
524{
525 _posix_spawnattr_t psattr;
526 _posix_spawn_port_actions_t acts;
527 int newnum;
528
529 if (attr == NULL || *attr == NULL)
530 return EINVAL;
531
532 psattr = *(_posix_spawnattr_t *)attr;
533 acts = psattr->psa_ports;
534 if (acts == NULL)
535 return EINVAL;
536
537 /* Double number of port actions allocated for */
538 newnum = 2 * acts->pspa_alloc;
539 acts = realloc(acts, PS_PORT_ACTIONS_SIZE(newnum));
540 if (acts == NULL)
541 return ENOMEM;
542
543 acts->pspa_alloc = newnum;
544 return 0;
545}
546
547/*
548 * posix_spawn_destroyportactions_np
549 * Description: clean up portactions struct in posix_spawnattr_t attr
550 */
551int
552posix_spawn_destroyportactions_np(posix_spawnattr_t *attr)
553{
554 _posix_spawnattr_t psattr;
555 _posix_spawn_port_actions_t acts;
556
557 if (attr == NULL || *attr == NULL)
558 return EINVAL;
559
560 psattr = *(_posix_spawnattr_t *)attr;
561 acts = psattr->psa_ports;
562 if (acts == NULL)
563 return EINVAL;
564
565 free(acts);
566 return 0;
567}
568
569
570/*
571 * posix_spawnattr_setspecialport_np
572 *
573 * Description: Set a new value for a mach special port in the spawned task.
574 *
575 * Parameters: attr The spawn attributes object for the
576 * new process
577 * new_port The new value for the special port
578 * which The particular port to be set
579 * (see task_set_special_port for details)
580 *
581 * Returns: 0 Success
582 * ENOMEM Couldn't allocate memory
583 */
584int
585posix_spawnattr_setspecialport_np(
586 posix_spawnattr_t *attr,
587 mach_port_t new_port,
588 int which)
589{
590 _posix_spawnattr_t psattr;
591 int err = 0;
592 _ps_port_action_t *action;
593 _posix_spawn_port_actions_t ports;
594
595 if (attr == NULL || *attr == NULL)
596 return EINVAL;
597
598 psattr = *(_posix_spawnattr_t *)attr;
599 ports = psattr->psa_ports;
600 /* Have any port actions been created yet? */
601 if (ports == NULL) {
602 err = posix_spawn_createportactions_np(attr);
603 if (err)
604 return err;
605 ports = psattr->psa_ports;
606 }
607
608 /* Is there enough room? */
609 if (ports->pspa_alloc == ports->pspa_count) {
610 err = posix_spawn_growportactions_np(attr);
611 if (err)
612 return err;
613 }
614
615 /* Add this action to next spot in array */
616 action = &ports->pspa_actions[ports->pspa_count];
617 action->port_type = PSPA_SPECIAL;
618 action->new_port = new_port;
619 action->which = which;
620
621 ports->pspa_count++;
622 return err;
623}
624
625/*
626 * posix_spawnattr_setexceptionports_np
627 *
628 * Description: Set a new port for a set of exception ports in the spawned task.
629 *
630 * Parameters: attr The spawn attributes object for the
631 * new process
632 * mask A bitfield indicating which exceptions
633 * to associate the port with
634 * new_port The new value for the exception port
635 * behavior The default behavior for the port
636 * flavor The default flavor for the port
637 * (see task_set_exception_ports)
638 *
639 * Returns: 0 Success
640 */
641int
642posix_spawnattr_setexceptionports_np(
643 posix_spawnattr_t *attr,
644 exception_mask_t mask,
645 mach_port_t new_port,
646 exception_behavior_t behavior,
647 thread_state_flavor_t flavor)
648{
649 _posix_spawnattr_t psattr;
650 int err = 0;
651 _ps_port_action_t *action;
652 _posix_spawn_port_actions_t ports;
653
654 if (attr == NULL || *attr == NULL)
655 return EINVAL;
656
657 psattr = *(_posix_spawnattr_t *)attr;
658 ports = psattr->psa_ports;
659 /* Have any port actions been created yet? */
660 if (ports == NULL) {
661 err = posix_spawn_createportactions_np(attr);
662 if (err)
663 return err;
664 ports = psattr->psa_ports;
665 }
666
667 /* Is there enough room? */
668 if (ports->pspa_alloc == ports->pspa_count) {
669 err = posix_spawn_growportactions_np(attr);
670 if (err)
671 return err;
672 }
673
674 /* Add this action to next spot in array */
675 action = &ports->pspa_actions[ports->pspa_count];
676 action->port_type = PSPA_EXCEPTION;
677 action->mask = mask;
678 action->new_port = new_port;
679 action->behavior = behavior;
680 action->flavor = flavor;
681
682 ports->pspa_count++;
683 return err;
684}
685
686
687/*
688 * posix_spawn_file_actions_init
689 *
690 * Description: Initialize a spawn file actions object attr with default values
691 *
692 * Parameters: file_actions The spawn file actions object to be
693 * initialized
694 *
695 * Returns: 0 Success
696 * ENOMEM Insufficient memory exists to
697 * initialize the spawn file actions
698 * object.
699 *
700 * Note: As an implementation detail, the externally visibily type
701 * posix_spawn_file_actions_t is defined to be a void *, and
702 * initialization involves allocation of a memory object.
703 * Subsequent changes to the spawn file actions may result in
704 * reallocation under the covers.
705 *
706 * Reinitialization of an already initialized spawn file actions
707 * object will result in memory being leaked. Because spawn
708 * file actions are not required to be used in conjunction with a
709 * static initializer, there is no way to distinguish a spawn
710 * file actions with stack garbage from one that's been
711 * initialized. This is arguably an API design error.
712 */
713int
714posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions)
715{
716 _posix_spawn_file_actions_t *psactsp = (_posix_spawn_file_actions_t *)file_actions;
717 int err = 0;
718
719 if ((*psactsp = (_posix_spawn_file_actions_t)malloc(PSF_ACTIONS_SIZE(PSF_ACTIONS_INIT_COUNT))) == NULL) {
720 err = ENOMEM;
721 } else {
722 (*psactsp)->psfa_act_alloc = PSF_ACTIONS_INIT_COUNT;
723 (*psactsp)->psfa_act_count = 0;
724 }
725
726 return (err);
727}
728
729
730/*
731 * posix_spawn_file_actions_destroy
732 *
733 * Description: Destroy a spawn file actions object that was previously
734 * initialized via posix_spawn_file_actions_init() by freeing any
735 * memory associated with it and setting it to an invalid value.
736 *
737 * Parameters: attr The spawn file actions object to be
738 * destroyed.
739 *
740 * Returns: 0 Success
741 *
742 * Notes: The destroyed spawn file actions results in the void * pointer
743 * being set to NULL; subsequent use without reinitialization
744 * will result in explicit program failure (rather than merely
745 * "undefined behaviour").
746 *
747 * NOTIMP: Allowed failures (checking NOT required):
748 * EINVAL The value specified by file_actions is invalid.
749 */
750int
751posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions)
752{
753 _posix_spawn_file_actions_t psacts;
754
755 if (file_actions == NULL || *file_actions == NULL)
756 return EINVAL;
757
758 psacts = *(_posix_spawn_file_actions_t *)file_actions;
759 free(psacts);
760 *file_actions = NULL;
761
762 return (0);
763}
764
765
766/*
767 * _posix_spawn_file_actions_grow
768 *
769 * Description: Grow the available list of file actions associated with the
770 * pointer to the structure provided; replace the contents of the
771 * pointer as a side effect.
772 *
773 * Parameters: psactsp Pointer to _posix_spawn_file_actions_t
774 * to grow
775 *
776 * Returns: 0 Success
777 * ENOMEM Insufficient memory for operation
778 *
779 * Notes: This code is common to all posix_spawn_file_actions_*()
780 * functions, since we use a naieve data structure implementation
781 * at present. Future optimization will likely change this.
782 */
783static int
784_posix_spawn_file_actions_grow(_posix_spawn_file_actions_t *psactsp)
785{
786 int new_alloc = (*psactsp)->psfa_act_alloc * 2;
787 _posix_spawn_file_actions_t new_psacts;
788
789 /*
790 * XXX may want to impose an administrative limit here; POSIX does
791 * XXX not provide for an administrative error return in this case,
792 * XXX so it's probably acceptable to just fail catastrophically
793 * XXX instead of implementing one.
794 */
795 if ((new_psacts = (_posix_spawn_file_actions_t)realloc((*psactsp), PSF_ACTIONS_SIZE(new_alloc))) == NULL) {
796 return (ENOMEM);
797 }
798 new_psacts->psfa_act_alloc = new_alloc;
799 *psactsp = new_psacts;
800
801 return (0);
802}
803
804
805/*
806 * posix_spawn_file_actions_addopen
807 *
808 * Description: Add an open action to the object referenced by 'file_actions'
809 * that will cause the file named by 'path' to be attempted to be
810 * opened with flags 'oflag' and mode 'mode', and, if successful,
811 * return as descriptor 'filedes' to the spawned process.
812 *
813 * Parameters: file_actions File action object to add open to
814 * filedes fd that open is to use
815 * path path to file to open
816 * oflag open file flags
817 * mode open file mode
818 *
819 * Returns: 0 Success
820 * EBADF The value specified by fildes is
821 * negative or greater than or equal to
822 * {OPEN_MAX}.
823 * ENOMEM Insufficient memory exists to add to
824 * the spawn file actions object.
825 *
826 * NOTIMP: Allowed failures (checking NOT required):
827 * EINVAL The value specified by file_actions is invalid.
828 */
829int
830posix_spawn_file_actions_addopen(
831 posix_spawn_file_actions_t * __restrict file_actions,
832 int filedes, const char * __restrict path, int oflag,
833 mode_t mode)
834{
835 _posix_spawn_file_actions_t *psactsp;
836 _psfa_action_t *psfileact;
837
838 if (file_actions == NULL || *file_actions == NULL)
839 return EINVAL;
840
841 psactsp = (_posix_spawn_file_actions_t *)file_actions;
842 /* Range check; required by POSIX */
843 if (filedes < 0 || filedes >= OPEN_MAX)
844 return (EBADF);
845
846 /* If we do not have enough slots, grow the structure */
847 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
848 /* need to grow file actions structure */
849 if (_posix_spawn_file_actions_grow(psactsp))
850 return (ENOMEM);
851 }
852
853 /*
854 * Allocate next available slot and fill it out
855 */
856 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
857
858 psfileact->psfaa_type = PSFA_OPEN;
859 psfileact->psfaa_filedes = filedes;
860 psfileact->psfaa_openargs.psfao_oflag = oflag;
861 psfileact->psfaa_openargs.psfao_mode = mode;
862 strlcpy(psfileact->psfaa_openargs.psfao_path, path, PATH_MAX);
863
864 return (0);
865}
866
867
868/*
869 * posix_spawn_file_actions_addclose
870 *
871 * Description: Add a close action to the object referenced by 'file_actions'
872 * that will cause the file referenced by 'filedes' to be
873 * attempted to be closed in the spawned process.
874 *
875 * Parameters: file_actions File action object to add open to
876 * filedes fd to close
877 *
878 * Returns: 0 Success
879 * EBADF The value specified by fildes is
880 * negative or greater than or equal to
881 * {OPEN_MAX}.
882 * ENOMEM Insufficient memory exists to add to
883 * the spawn file actions object.
884 *
885 * NOTIMP: Allowed failures (checking NOT required):
886 * EINVAL The value specified by file_actions is invalid.
887 */
888int
889posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions,
890 int filedes)
891{
892 _posix_spawn_file_actions_t *psactsp;
893 _psfa_action_t *psfileact;
894
895 if (file_actions == NULL || *file_actions == NULL)
896 return EINVAL;
897
898 psactsp = (_posix_spawn_file_actions_t *)file_actions;
899 /* Range check; required by POSIX */
900 if (filedes < 0 || filedes >= OPEN_MAX)
901 return (EBADF);
902
903 /* If we do not have enough slots, grow the structure */
904 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
905 /* need to grow file actions structure */
906 if (_posix_spawn_file_actions_grow(psactsp))
907 return (ENOMEM);
908 }
909
910 /*
911 * Allocate next available slot and fill it out
912 */
913 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
914
915 psfileact->psfaa_type = PSFA_CLOSE;
916 psfileact->psfaa_filedes = filedes;
917
918 return (0);
919}
920
921
922/*
923 * posix_spawn_file_actions_adddup2
924 *
925 * Description: Add a dpu2 action to the object referenced by 'file_actions'
926 * that will cause the file referenced by 'filedes' to be
927 * attempted to be dup2'ed to the descriptor 'newfiledes' in the
928 * spawned process.
929 *
930 * Parameters: file_actions File action object to add open to
931 * filedes fd to dup2
932 * newfiledes fd to dup2 it to
933 *
934 * Returns: 0 Success
935 * EBADF The value specified by either fildes
936 * or by newfiledes is negative or greater
937 * than or equal to {OPEN_MAX}.
938 * ENOMEM Insufficient memory exists to add to
939 * the spawn file actions object.
940 *
941 * NOTIMP: Allowed failures (checking NOT required):
942 * EINVAL The value specified by file_actions is invalid.
943 */
944int
945posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions,
946 int filedes, int newfiledes)
947{
948 _posix_spawn_file_actions_t *psactsp;
949 _psfa_action_t *psfileact;
950
951 if (file_actions == NULL || *file_actions == NULL)
952 return EINVAL;
953
954 psactsp = (_posix_spawn_file_actions_t *)file_actions;
955 /* Range check; required by POSIX */
956 if (filedes < 0 || filedes >= OPEN_MAX ||
957 newfiledes < 0 || newfiledes >= OPEN_MAX)
958 return (EBADF);
959
960 /* If we do not have enough slots, grow the structure */
961 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
962 /* need to grow file actions structure */
963 if (_posix_spawn_file_actions_grow(psactsp))
964 return (ENOMEM);
965 }
966
967 /*
968 * Allocate next available slot and fill it out
969 */
970 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
971
972 psfileact->psfaa_type = PSFA_DUP2;
973 psfileact->psfaa_filedes = filedes;
974 psfileact->psfaa_openargs.psfao_oflag = newfiledes;
975
976 return (0);
977}
978
979
980/*
981 * posix_spawnp
982 *
983 * Description: Create a new process from the process image corresponding to
984 * the supplied 'file' argument and the parent processes path
985 * environment.
986 *
987 * Parameters: pid Pointer to pid_t to receive the
988 * PID of the spawned process, if
989 * successful and 'pid' != NULL
990 * file Name of image file to spawn
991 * file_actions spawn file actions object which
992 * describes file actions to be
993 * performed during the spawn
994 * attrp spawn attributes object which
995 * describes attributes to be
996 * applied during the spawn
997 * argv argument vector array; NULL
998 * terminated
999 * envp environment vector array; NULL
1000 * terminated
1001 *
1002 * Returns: 0 Success
1003 * !0 An errno value indicating the
1004 * cause of the failure to spawn
1005 *
1006 * Notes: Much of this function is derived from code from execvP() from
1007 * exec.c in libc; this common code should be factored out at
1008 * some point to prevent code duplication or desynchronization vs.
1009 * bug fixes applied to one set of code but not the other.
1010 */
1011int
1012posix_spawnp(pid_t * __restrict pid, const char * __restrict file,
1013 const posix_spawn_file_actions_t *file_actions,
1014 const posix_spawnattr_t * __restrict attrp,
1015 char *const argv[ __restrict], char *const envp[ __restrict])
1016{
1017 const char *env_path;
1018 char *bp;
1019 char *cur;
1020 char *p;
1021 char **memp;
1022 int lp;
1023 int ln;
1024 int cnt;
1025 int err = 0;
1026 int eacces = 0;
1027 struct stat sb;
1028 char path_buf[PATH_MAX];
1029
1030 if ((env_path = getenv("PATH")) == NULL)
1031 env_path = _PATH_DEFPATH;
1032
1033 /* If it's an absolute or relative path name, it's easy. */
1034 if (index(file, '/')) {
1035 bp = (char *)file;
1036 cur = NULL;
1037 goto retry;
1038 }
1039 bp = path_buf;
1040
1041 /* If it's an empty path name, fail in the usual POSIX way. */
1042 if (*file == '\0')
1043 return (ENOENT);
1044
1045 if ((cur = alloca(strlen(env_path) + 1)) == NULL)
1046 return ENOMEM;
1047 strcpy(cur, env_path);
1048 while ((p = strsep(&cur, ":")) != NULL) {
1049 /*
1050 * It's a SHELL path -- double, leading and trailing colons
1051 * mean the current directory.
1052 */
1053 if (*p == '\0') {
1054 p = ".";
1055 lp = 1;
1056 } else {
1057 lp = strlen(p);
1058 }
1059 ln = strlen(file);
1060
1061 /*
1062 * If the path is too long complain. This is a possible
1063 * security issue; given a way to make the path too long
1064 * the user may spawn the wrong program.
1065 */
1066 if (lp + ln + 2 > sizeof(path_buf)) {
1067 err = ENAMETOOLONG;
1068 goto done;
1069 }
1070 bcopy(p, path_buf, lp);
1071 path_buf[lp] = '/';
1072 bcopy(file, path_buf + lp + 1, ln);
1073 path_buf[lp + ln + 1] = '\0';
1074
1075retry: err = posix_spawn(pid, bp, file_actions, attrp, argv, envp);
1076 switch (err) {
1077 case E2BIG:
1078 case ENOMEM:
1079 case ETXTBSY:
1080 goto done;
1081 case ELOOP:
1082 case ENAMETOOLONG:
1083 case ENOENT:
1084 case ENOTDIR:
1085 break;
1086 case ENOEXEC:
1087 for (cnt = 0; argv[cnt]; ++cnt)
1088 ;
1089 memp = alloca((cnt + 2) * sizeof(char *));
1090 if (memp == NULL) {
1091 /* errno = ENOMEM; XXX override ENOEXEC? */
1092 goto done;
1093 }
1094 memp[0] = "sh";
1095 memp[1] = bp;
1096 bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
1097 err = posix_spawn(pid, _PATH_BSHELL, file_actions, attrp, memp, envp);
1098 goto done;
1099 default:
1100 /*
1101 * EACCES may be for an inaccessible directory or
1102 * a non-executable file. Call stat() to decide
1103 * which. This also handles ambiguities for EFAULT
1104 * and EIO, and undocumented errors like ESTALE.
1105 * We hope that the race for a stat() is unimportant.
1106 */
1107 if (stat(bp, &sb) != 0)
1108 break;
1109 if (err == EACCES) {
1110 eacces = 1;
1111 continue;
1112 }
1113 goto done;
1114 }
1115 }
1116 if (eacces)
1117 err = EACCES;
1118 else
1119 err = ENOENT;
1120done:
1121 return (err);
1122}
1123
1124
1125/*
1126 * posix_spawn
1127 *
1128 * Description: Create a new process from the process image corresponding to
1129 * the supplied 'path' argument.
1130 *
1131 * Parameters: pid Pointer to pid_t to receive the
1132 * PID of the spawned process, if
1133 * successful and 'pid' != NULL
1134 * path Path of image file to spawn
1135 * file_actions spawn file actions object which
1136 * describes file actions to be
1137 * performed during the spawn
1138 * attrp spawn attributes object which
1139 * describes attributes to be
1140 * applied during the spawn
1141 * argv argument vector array; NULL
1142 * terminated
1143 * envp environment vector array; NULL
1144 * terminated
1145 *
1146 * Returns: 0 Success
1147 * !0 An errno value indicating the
1148 * cause of the failure to spawn
1149 *
1150 * Notes: Unlike other system calls, the return value of this system
1151 * call is expected to either be a 0 or an errno, rather than a
1152 * 0 or a -1, with the 'errno' variable being set.
1153 */
1154extern int __posix_spawn(pid_t * __restrict, const char * __restrict,
1155 struct _posix_spawn_args_desc *,
1156 char *const argv[ __restrict], char *const envp[ __restrict]);
1157
1158int
1159posix_spawn(pid_t * __restrict pid, const char * __restrict path,
1160 const posix_spawn_file_actions_t *file_actions,
1161 const posix_spawnattr_t * __restrict attrp,
1162 char *const argv[ __restrict], char *const envp[ __restrict])
1163{
1164 int saveerrno = errno;
1165 int ret;
1166 /*
1167 * Only do extra work if we have file actions or attributes to push
1168 * down. We use a descriptor to push this information down, since we
1169 * want to have size information, which will let us (1) preallocate a
1170 * single chunk of memory for the copyin(), and (2) allow us to do a
1171 * single copyin() per attributes or file actions as a monlithic block.
1172 *
1173 * Note: A future implementation may attempt to do the same
1174 * thing for the argv/envp data, which could potentially
1175 * result in a performance improvement due to increased
1176 * kernel efficiency, even though it would mean copying
1177 * the data in user space.
1178 */
1179 if ((file_actions != NULL && (*file_actions != NULL) && (*(_posix_spawn_file_actions_t *)file_actions)->psfa_act_count > 0) || attrp != NULL) {
1180 struct _posix_spawn_args_desc ad;
1181
1182 memset(&ad, 0, sizeof(ad));
1183 if (attrp != NULL && *attrp != NULL) {
1184 _posix_spawnattr_t psattr = *(_posix_spawnattr_t *)attrp;
1185 ad.attr_size = sizeof(struct _posix_spawnattr);
1186 ad.attrp = psattr;
1187
1188 if (psattr->psa_ports != NULL) {
1189 ad.port_actions = psattr->psa_ports;
1190 ad.port_actions_size = PS_PORT_ACTIONS_SIZE(
1191 ad.port_actions->pspa_count);
1192 }
1193 }
1194 if (file_actions != NULL && *file_actions != NULL) {
1195 _posix_spawn_file_actions_t psactsp =
1196 *(_posix_spawn_file_actions_t *)file_actions;
1197
1198 if (psactsp->psfa_act_count > 0) {
1199 ad.file_actions_size = PSF_ACTIONS_SIZE(psactsp->psfa_act_count);
1200 ad.file_actions = psactsp;
1201 }
1202 }
1203
1204 ret = __posix_spawn(pid, path, &ad, argv, envp);
1205 } else
1206 ret = __posix_spawn(pid, path, NULL, argv, envp);
1207
1208 if (ret < 0)
1209 ret = errno;
1210 errno = saveerrno;
1211 return ret;
1212}
1213