source: trunk/libs/newlib/src/newlib/libc/posix/posix_spawn.c @ 444

Last change on this file since 444 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 13.0 KB
Line 
1/*-
2 * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28FUNCTION
29<<posix_spawn>>, <<posix_spawnp>>---spawn a process
30
31INDEX
32        posix_spawn
33INDEX
34        posix_spawnp
35
36SYNOPSIS
37        #include <spawn.h>
38
39        int posix_spawn(pid_t *<[pid]>, const char *<[path]>,
40                        const posix_spawn_file_actions_t *<[file_actions]>,
41                        const posix_spawnattr_t *<[attrp]>,
42                        char *const <[argv]>, char *const <[envp]>);
43        int posix_spawnp(pid_t *<[pid]>, const char *<[file]>,
44                        const posix_spawn_file_actions_t *<[file_actions]>,
45                        const posix_spawnattr_t *<[attrp]>,
46                        char *const <[argv]>, char *const <[envp]>);
47
48DESCRIPTION
49Use <<posix_spawn>> and <<posix_spawnp>> to create a new child process
50from the specified process image file. <<argc>> is the argument count
51and <<argv>> is an array of argument strings passed to the new program.
52<<envp>> is an array of stings, which are passed as environment to the
53new program.
54
55The <<path>> argument to <<posix_spawn>> identifies the new process
56image file to execute. The <<file>> argument to <<posix_spawnp>> is
57used to construct a pathname that identifies the new process image
58file by duplicating the actions of the shell in searching for an
59executable file if the specified filename does not contain a `<</>>'
60character. The <<file>> is sought in the colon-separated list of
61directory pathnames specified in the <<PATH>> environment variable.
62
63The file descriptors remain open across <<posix_spawn>> and
64<<posix_spawnp>> except for those marked as close-on-exec. The open
65file descriptors in the child process can be modified by the spawn file
66actions object pointed to by <<file_actions>>.
67
68The spawn attributes object type pointed to by <<attrp>> argument
69may contain any of the attributes defined in <<spawn.h>>.
70
71RETURNS
72<<posix_spawn>> and <<posix_spawnp>> return the process ID of the newly
73spawned child process in the variable pointed by a non-NULL <<*<[pid]>>>
74argument and zero as the function return value upon successful
75completion. Otherwise, <<posix_spawn>> and <<posix_spawnp>> return an
76error number as the function return value to indicate the error; the
77value stored into the variable pointed to by a non-NULL <<*<[pid]>>>
78argument is unspecified.
79
80PORTABILITY
81POSIX.1-2008 requires <<posix_spawn>> and <<posix_spawnp>>.
82
83Supporting OS subroutines required: <<_close>>, <<dup2>>, <<_fcntl>>,
84<<_execve>>, <<execvpe>>, <<_exit>>, <<_open>>, <<sigaction>>,
85<<sigprocmask>>, <<waitpid>>, <<sched_setscheduler>>,
86<<sched_setparam>>, <<setegid>>, <<seteuid>>, <<setpgid>>, <<vfork>>.
87*/
88
89#ifndef _NO_POSIX_SPAWN
90
91#include <sys/cdefs.h>
92
93#include <sys/signal.h>
94#include <sys/queue.h>
95#include <sys/wait.h>
96
97#include <errno.h>
98#include <fcntl.h>
99#include <sched.h>
100#include <spawn.h>
101#include <signal.h>
102#include <stdlib.h>
103#include <string.h>
104#include <unistd.h>
105
106/* Only deal with a pointer to environ, to work around subtle bugs with shared
107   libraries and/or small data systems where the user declares his own
108   'environ'.  */
109static char ***p_environ = &environ;
110
111struct __posix_spawnattr {
112        short                   sa_flags;
113        pid_t                   sa_pgroup;
114        struct sched_param      sa_schedparam;
115        int                     sa_schedpolicy;
116        sigset_t                sa_sigdefault;
117        sigset_t                sa_sigmask;
118};
119
120struct __posix_spawn_file_actions {
121        STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list;
122};
123
124typedef struct __posix_spawn_file_actions_entry {
125        STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list;
126        enum { FAE_OPEN, FAE_DUP2, FAE_CLOSE } fae_action;
127
128        int fae_fildes;
129        union {
130                struct {
131                        char *path;
132#define fae_path        fae_data.open.path
133                        int oflag;
134#define fae_oflag       fae_data.open.oflag
135                        mode_t mode;
136#define fae_mode        fae_data.open.mode
137                } open;
138                struct {
139                        int newfildes;
140#define fae_newfildes   fae_data.dup2.newfildes
141                } dup2;
142        } fae_data;
143} posix_spawn_file_actions_entry_t;
144
145/*
146 * Spawn routines
147 */
148
149static int
150process_spawnattr(const posix_spawnattr_t sa)
151{
152        struct sigaction sigact = { .sa_flags = 0, .sa_handler = SIG_DFL };
153        int i;
154
155        /*
156         * POSIX doesn't really describe in which order everything
157         * should be set. We'll just set them in the order in which they
158         * are mentioned.
159         */
160
161        /* Set process group */
162        if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) {
163                if (setpgid(0, sa->sa_pgroup) != 0)
164                        return (errno);
165        }
166
167        /* Set scheduler policy */
168        if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) {
169                if (sched_setscheduler(0, sa->sa_schedpolicy,
170                    &sa->sa_schedparam) != 0)
171                        return (errno);
172        } else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) {
173                if (sched_setparam(0, &sa->sa_schedparam) != 0)
174                        return (errno);
175        }
176
177        /* Reset user ID's */
178        if (sa->sa_flags & POSIX_SPAWN_RESETIDS) {
179                if (setegid(getgid()) != 0)
180                        return (errno);
181                if (seteuid(getuid()) != 0)
182                        return (errno);
183        }
184
185        /* Set signal masks/defaults */
186        if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) {
187                sigprocmask(SIG_SETMASK, &sa->sa_sigmask, NULL);
188        }
189
190        if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) {
191                for (i = 1; i < NSIG; i++) {
192                        if (sigismember(&sa->sa_sigdefault, i))
193                                if (sigaction(i, &sigact, NULL) != 0)
194                                        return (errno);
195                }
196        }
197
198        return (0);
199}
200
201static int
202process_file_actions_entry(posix_spawn_file_actions_entry_t *fae)
203{
204        int fd;
205
206        switch (fae->fae_action) {
207        case FAE_OPEN:
208                /* Perform an open(), make it use the right fd */
209                fd = _open(fae->fae_path, fae->fae_oflag, fae->fae_mode);
210                if (fd < 0)
211                        return (errno);
212                if (fd != fae->fae_fildes) {
213                        if (dup2(fd, fae->fae_fildes) == -1)
214                                return (errno);
215                        if (_close(fd) != 0) {
216                                if (errno == EBADF)
217                                        return (EBADF);
218                        }
219                }
220#ifdef HAVE_FCNTL
221                if (_fcntl(fae->fae_fildes, F_SETFD, 0) == -1)
222                        return (errno);
223#endif /* HAVE_FCNTL */
224                break;
225        case FAE_DUP2:
226                /* Perform a dup2() */
227                if (dup2(fae->fae_fildes, fae->fae_newfildes) == -1)
228                        return (errno);
229#ifdef HAVE_FCNTL
230                if (_fcntl(fae->fae_newfildes, F_SETFD, 0) == -1)
231                        return (errno);
232#endif /* HAVE_FCNTL */
233                break;
234        case FAE_CLOSE:
235                /* Perform a close(), do not fail if already closed */
236                (void)_close(fae->fae_fildes);
237                break;
238        }
239        return (0);
240}
241
242static int
243process_file_actions(const posix_spawn_file_actions_t fa)
244{
245        posix_spawn_file_actions_entry_t *fae;
246        int error;
247
248        /* Replay all file descriptor modifications */
249        STAILQ_FOREACH(fae, &fa->fa_list, fae_list) {
250                error = process_file_actions_entry(fae);
251                if (error)
252                        return (error);
253        }
254        return (0);
255}
256
257static int
258do_posix_spawn(pid_t *pid, const char *path,
259        const posix_spawn_file_actions_t *fa,
260        const posix_spawnattr_t *sa,
261        char * const argv[], char * const envp[], int use_env_path)
262{
263        pid_t p;
264        volatile int error = 0;
265
266        p = vfork();
267        switch (p) {
268        case -1:
269                return (errno);
270        case 0:
271                if (sa != NULL) {
272                        error = process_spawnattr(*sa);
273                        if (error)
274                                _exit(127);
275                }
276                if (fa != NULL) {
277                        error = process_file_actions(*fa);
278                        if (error)
279                                _exit(127);
280                }
281                if (use_env_path)
282                        execvpe(path, argv, envp != NULL ? envp : *p_environ);
283                else
284                        _execve(path, argv, envp != NULL ? envp : *p_environ);
285                error = errno;
286                _exit(127);
287        default:
288                if (error != 0)
289                        waitpid(p, NULL, WNOHANG);
290                else if (pid != NULL)
291                        *pid = p;
292                return (error);
293        }
294}
295
296int
297posix_spawn (pid_t *pid,
298        const char *path,
299        const posix_spawn_file_actions_t *fa,
300        const posix_spawnattr_t *sa,
301        char * const argv[],
302        char * const envp[])
303{
304        return do_posix_spawn(pid, path, fa, sa, argv, envp, 0);
305}
306
307int
308posix_spawnp (pid_t *pid,
309        const char *path,
310        const posix_spawn_file_actions_t *fa,
311        const posix_spawnattr_t *sa,
312        char * const argv[],
313        char * const envp[])
314{
315        return do_posix_spawn(pid, path, fa, sa, argv, envp, 1);
316}
317
318/*
319 * File descriptor actions
320 */
321
322int
323posix_spawn_file_actions_init (posix_spawn_file_actions_t *ret)
324{
325        posix_spawn_file_actions_t fa;
326
327        fa = malloc(sizeof(struct __posix_spawn_file_actions));
328        if (fa == NULL)
329                return (-1);
330
331        STAILQ_INIT(&fa->fa_list);
332        *ret = fa;
333        return (0);
334}
335
336int
337posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *fa)
338{
339        posix_spawn_file_actions_entry_t *fae;
340
341        while ((fae = STAILQ_FIRST(&(*fa)->fa_list)) != NULL) {
342                /* Remove file action entry from the queue */
343                STAILQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list);
344
345                /* Deallocate file action entry */
346                if (fae->fae_action == FAE_OPEN)
347                        free(fae->fae_path);
348                free(fae);
349        }
350
351        free(*fa);
352        return (0);
353}
354
355int
356posix_spawn_file_actions_addopen (posix_spawn_file_actions_t * __restrict fa,
357        int fildes,
358        const char * __restrict path,
359        int oflag,
360        mode_t mode)
361{
362        posix_spawn_file_actions_entry_t *fae;
363        int error;
364
365        if (fildes < 0)
366                return (EBADF);
367
368        /* Allocate object */
369        fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
370        if (fae == NULL)
371                return (errno);
372
373        /* Set values and store in queue */
374        fae->fae_action = FAE_OPEN;
375        fae->fae_path = strdup(path);
376        if (fae->fae_path == NULL) {
377                error = errno;
378                free(fae);
379                return (error);
380        }
381        fae->fae_fildes = fildes;
382        fae->fae_oflag = oflag;
383        fae->fae_mode = mode;
384
385        STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
386        return (0);
387}
388
389int
390posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *fa,
391        int fildes,
392        int newfildes)
393{
394        posix_spawn_file_actions_entry_t *fae;
395
396        if (fildes < 0 || newfildes < 0)
397                return (EBADF);
398
399        /* Allocate object */
400        fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
401        if (fae == NULL)
402                return (errno);
403
404        /* Set values and store in queue */
405        fae->fae_action = FAE_DUP2;
406        fae->fae_fildes = fildes;
407        fae->fae_newfildes = newfildes;
408
409        STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
410        return (0);
411}
412
413int
414posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *fa,
415        int fildes)
416{
417        posix_spawn_file_actions_entry_t *fae;
418
419        if (fildes < 0)
420                return (EBADF);
421
422        /* Allocate object */
423        fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
424        if (fae == NULL)
425                return (errno);
426
427        /* Set values and store in queue */
428        fae->fae_action = FAE_CLOSE;
429        fae->fae_fildes = fildes;
430
431        STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
432        return (0);
433}
434
435/*
436 * Spawn attributes
437 */
438
439int
440posix_spawnattr_init (posix_spawnattr_t *ret)
441{
442        posix_spawnattr_t sa;
443
444        sa = calloc(1, sizeof(struct __posix_spawnattr));
445        if (sa == NULL)
446                return (errno);
447
448        /* Set defaults as specified by POSIX, cleared above */
449        *ret = sa;
450        return (0);
451}
452
453int
454posix_spawnattr_destroy (posix_spawnattr_t *sa)
455{
456        free(*sa);
457        return (0);
458}
459
460int
461posix_spawnattr_getflags (const posix_spawnattr_t * __restrict sa,
462        short * __restrict flags)
463{
464        *flags = (*sa)->sa_flags;
465        return (0);
466}
467
468int
469posix_spawnattr_getpgroup (const posix_spawnattr_t * __restrict sa,
470        pid_t * __restrict pgroup)
471{
472        *pgroup = (*sa)->sa_pgroup;
473        return (0);
474}
475
476int
477posix_spawnattr_getschedparam (const posix_spawnattr_t * __restrict sa,
478        struct sched_param * __restrict schedparam)
479{
480        *schedparam = (*sa)->sa_schedparam;
481        return (0);
482}
483
484int
485posix_spawnattr_getschedpolicy (const posix_spawnattr_t * __restrict sa,
486        int * __restrict schedpolicy)
487{
488        *schedpolicy = (*sa)->sa_schedpolicy;
489        return (0);
490}
491
492int
493posix_spawnattr_getsigdefault (const posix_spawnattr_t * __restrict sa,
494        sigset_t * __restrict sigdefault)
495{
496        *sigdefault = (*sa)->sa_sigdefault;
497        return (0);
498}
499
500int
501posix_spawnattr_getsigmask (const posix_spawnattr_t * __restrict sa,
502        sigset_t * __restrict sigmask)
503{
504        *sigmask = (*sa)->sa_sigmask;
505        return (0);
506}
507
508int
509posix_spawnattr_setflags (posix_spawnattr_t *sa,
510        short flags)
511{
512        (*sa)->sa_flags = flags;
513        return (0);
514}
515
516int
517posix_spawnattr_setpgroup (posix_spawnattr_t *sa,
518        pid_t pgroup)
519{
520        (*sa)->sa_pgroup = pgroup;
521        return (0);
522}
523
524int
525posix_spawnattr_setschedparam (posix_spawnattr_t * __restrict sa,
526        const struct sched_param * __restrict schedparam)
527{
528        (*sa)->sa_schedparam = *schedparam;
529        return (0);
530}
531
532int
533posix_spawnattr_setschedpolicy (posix_spawnattr_t *sa,
534        int schedpolicy)
535{
536        (*sa)->sa_schedpolicy = schedpolicy;
537        return (0);
538}
539
540int
541posix_spawnattr_setsigdefault (posix_spawnattr_t * __restrict sa,
542        const sigset_t * __restrict sigdefault)
543{
544        (*sa)->sa_sigdefault = *sigdefault;
545        return (0);
546}
547
548int
549posix_spawnattr_setsigmask (posix_spawnattr_t * __restrict sa,
550        const sigset_t * __restrict sigmask)
551{
552        (*sa)->sa_sigmask = *sigmask;
553        return (0);
554}
555
556#endif  /* !_NO_POSIX_SPAWN */
Note: See TracBrowser for help on using the repository browser.