diff --git a/newlib/ChangeLog b/newlib/ChangeLog index cb3d05dac..c0e4037b2 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,12 @@ +2013-10-01 Petr Hosek + + * configure.host: Disable new posix_spawn function for all + users of posix dir except Cygwin. + * libc/posix/Makefile.am: Add support for new posix_spawn function. + * libc/posix/Makefile.in: Regenerate. + * libc/posix/posix_spawn.c: New file. + * libc/include/spawn.h: Ditto. + 2013-09-13 Joey Ye * libc/stdlib/nano-mallocr.c (nano_allopt): Typo fixed to ... diff --git a/newlib/configure.host b/newlib/configure.host index e7047f060..f4a80bbc6 100644 --- a/newlib/configure.host +++ b/newlib/configure.host @@ -458,6 +458,7 @@ case "${host}" in newlib_cflags="${newlib_cflags} -D_I386MACH_ALLOW_HW_INTERRUPTS" newlib_cflags="${newlib_cflags} -DHAVE_FCNTL" newlib_cflags="${newlib_cflags} -DHAVE_GETOPT" + newlib_cflags="${newlib_cflags} -D_NO_POSIX_SPAWN" # --- Required when building a shared library ------------------------ newlib_cflags="${newlib_cflags} -fPIC -D_I386MACH_NEED_SOTYPE_FUNCTION" # --- The three lines below are optional ------------------------------ @@ -568,7 +569,7 @@ case "${host}" in newlib_cflags="${newlib_cflags} -D_COMPILING_NEWLIB" newlib_cflags="${newlib_cflags} -DMALLOC_PROVIDED -DEXIT_PROVIDED -DSIGNAL_PROVIDED -DREENTRANT_SYSCALLS_PROVIDED -DHAVE_NANOSLEEP -DHAVE_BLKSIZE -DHAVE_FCNTL -DHAVE_ASSERT_FUNC" # turn off unsupported items in posix directory - newlib_cflags="${newlib_cflags} -D_NO_GETLOGIN -D_NO_GETPWENT -D_NO_GETUT -D_NO_GETPASS -D_NO_SIGSET -D_NO_WORDEXP -D_NO_POPEN" + newlib_cflags="${newlib_cflags} -D_NO_GETLOGIN -D_NO_GETPWENT -D_NO_GETUT -D_NO_GETPASS -D_NO_SIGSET -D_NO_WORDEXP -D_NO_POPEN -D_NO_POSIX_SPAWN" ;; # VxWorks supplies its own version of malloc, and the newlib one # doesn't work because VxWorks does not have sbrk. @@ -746,7 +747,7 @@ case "${host}" in newlib_cflags="${newlib_cflags} -mrelocatable-lib -mno-eabi -mstrict-align -DMISSING_SYSCALL_NAMES" ;; powerpcle-*-pe) - newlib_cflags="${newlib_cflags} -DHAVE_OPENDIR -DHAVE_RENAME -DHAVE_FCNTL" + newlib_cflags="${newlib_cflags} -DHAVE_OPENDIR -DHAVE_RENAME -DHAVE_FCNTL -D_NO_POSIX_SPAWN" syscall_dir=syscalls ;; sh*-*-*) diff --git a/newlib/libc/include/spawn.h b/newlib/libc/include/spawn.h new file mode 100644 index 000000000..55867b598 --- /dev/null +++ b/newlib/libc/include/spawn.h @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 2008 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SPAWN_H_ +#define _SPAWN_H_ + +#include <_ansi.h> +#include +#include +#include +#define __need_sigset_t +#include + +struct sched_param; + +typedef struct __posix_spawnattr *posix_spawnattr_t; +typedef struct __posix_spawn_file_actions *posix_spawn_file_actions_t; + +#define POSIX_SPAWN_RESETIDS 0x01 +#define POSIX_SPAWN_SETPGROUP 0x02 +#define POSIX_SPAWN_SETSCHEDPARAM 0x04 +#define POSIX_SPAWN_SETSCHEDULER 0x08 +#define POSIX_SPAWN_SETSIGDEF 0x10 +#define POSIX_SPAWN_SETSIGMASK 0x20 + +_BEGIN_STD_C +/* + * Spawn routines + * + * XXX both arrays should be __restrict, but this does not work when GCC + * is invoked with -std=c99. + */ +int _EXFUN(posix_spawn, (pid_t * __restrict, const char * __restrict, + const posix_spawn_file_actions_t *, const posix_spawnattr_t * __restrict, + char * const [], char * const []) +); +int _EXFUN(posix_spawnp, (pid_t * __restrict, const char * __restrict, + const posix_spawn_file_actions_t *, const posix_spawnattr_t * __restrict, + char * const [], char * const []) +); + +/* + * File descriptor actions + */ +int _EXFUN(posix_spawn_file_actions_init, (posix_spawn_file_actions_t *)); +int _EXFUN(posix_spawn_file_action_destroy, (posix_spawn_file_actions_t *)); + +int _EXFUN(posix_spawn_file_actions_addopen, + (posix_spawn_file_actions_t * __restrict, int, const char * __restrict, int, mode_t) +); +int _EXFUN(posix_spawn_file_actions_adddup2, + (posix_spawn_file_actions_t *, int, int) +); +int _EXFUN(posix_spawn_file_actions_addclose, + (posix_spawn_file_actions_t *, int) +); + +/* + * Spawn attributes + */ +int _EXFUN(posix_spawnattr_init, (posix_spawnattr_t *)); +int _EXFUN(posix_spawnattr_destroy, (posix_spawnattr_t *)); + +int _EXFUN(posix_spawnattr_getflags, + (const posix_spawnattr_t * __restrict, short * __restrict) +); +int _EXFUN(posix_spawnattr_getpgroup, + (const posix_spawnattr_t * __restrict, pid_t * __restrict)); +int _EXFUN(posix_spawnattr_getschedparam, + (const posix_spawnattr_t * __restrict, struct sched_param * __restrict) +); +int _EXFUN(posix_spawnattr_getschedpolicy, + (const posix_spawnattr_t * __restrict, int * __restrict) +); +int _EXFUN(posix_spawnattr_getsigdefault, + (const posix_spawnattr_t * __restrict, sigset_t * __restrict) +); +int _EXFUN(posix_spawnattr_getsigmask, + (const posix_spawnattr_t * __restrict, sigset_t * __restrict) +); + +int _EXFUN(posix_spawnattr_setflags, (posix_spawnattr_t *, short)); +int _EXFUN(posix_spawnattr_setpgroup, (posix_spawnattr_t *, pid_t)); +int _EXFUN(posix_spawnattr_setschedparam, + (posix_spawnattr_t * __restrict, const struct sched_param * __restrict) +); +int _EXFUN(posix_spawnattr_setschedpolicy, (posix_spawnattr_t *, int)); +int _EXFUN(posix_spawnattr_setsigdefault, + (posix_spawnattr_t * __restrict, const sigset_t * __restrict) +); +int _EXFUN(posix_spawnattr_setsigmask, + (posix_spawnattr_t * __restrict, const sigset_t * __restrict) +); +_END_STD_C + +#endif /* !_SPAWN_H_ */ diff --git a/newlib/libc/posix/Makefile.am b/newlib/libc/posix/Makefile.am index fa20dd725..aca993e04 100644 --- a/newlib/libc/posix/Makefile.am +++ b/newlib/libc/posix/Makefile.am @@ -20,7 +20,7 @@ ELIX_3_SOURCES = \ execve.c execvp.c wordexp.c wordfree.c ELIX_4_SOURCES = \ - popen.c + popen.c posix_spawn.c if ELIX_LEVEL_1 ELIX_SOURCES = diff --git a/newlib/libc/posix/Makefile.in b/newlib/libc/posix/Makefile.in index 09a0b3811..81ba81511 100644 --- a/newlib/libc/posix/Makefile.in +++ b/newlib/libc/posix/Makefile.in @@ -87,7 +87,7 @@ am__objects_3 = lib_a-execl.$(OBJEXT) lib_a-execle.$(OBJEXT) \ lib_a-execlp.$(OBJEXT) lib_a-execv.$(OBJEXT) \ lib_a-execve.$(OBJEXT) lib_a-execvp.$(OBJEXT) \ lib_a-wordexp.$(OBJEXT) lib_a-wordfree.$(OBJEXT) -am__objects_4 = lib_a-popen.$(OBJEXT) +am__objects_4 = lib_a-popen.$(OBJEXT) lib_a-posix_spawn.$(OBJEXT) @ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@am__objects_5 = $(am__objects_2) \ @ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ $(am__objects_3) \ @ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ $(am__objects_4) @@ -107,7 +107,7 @@ am__objects_6 = closedir.lo collate.lo collcmp.lo creat.lo fnmatch.lo \ am__objects_7 = scandir.lo seekdir.lo am__objects_8 = execl.lo execle.lo execlp.lo execv.lo execve.lo \ execvp.lo wordexp.lo wordfree.lo -am__objects_9 = popen.lo +am__objects_9 = popen.lo posix_spawn.lo @ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@am__objects_10 = $(am__objects_7) \ @ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ $(am__objects_8) \ @ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ $(am__objects_9) @@ -305,7 +305,7 @@ ELIX_3_SOURCES = \ execve.c execvp.c wordexp.c wordfree.c ELIX_4_SOURCES = \ - popen.c + popen.c posix_spawn.c @ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ELIX_SOURCES = $(ELIX_2_SOURCES) $(ELIX_3_SOURCES) $(ELIX_4_SOURCES) @ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_TRUE@ELIX_SOURCES = $(ELIX_2_SOURCES) $(ELIX_3_SOURCES) @@ -576,6 +576,12 @@ lib_a-popen.o: popen.c lib_a-popen.obj: popen.c $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-popen.obj `if test -f 'popen.c'; then $(CYGPATH_W) 'popen.c'; else $(CYGPATH_W) '$(srcdir)/popen.c'; fi` +lib_a-posix_spawn.o: posix_spawn.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-posix_spawn.o `test -f 'posix_spawn.c' || echo '$(srcdir)/'`posix_spawn.c + +lib_a-posix_spawn.obj: posix_spawn.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-posix_spawn.obj `if test -f 'posix_spawn.c'; then $(CYGPATH_W) 'posix_spawn.c'; else $(CYGPATH_W) '$(srcdir)/posix_spawn.c'; fi` + mostlyclean-libtool: -rm -f *.lo diff --git a/newlib/libc/posix/posix_spawn.c b/newlib/libc/posix/posix_spawn.c new file mode 100644 index 000000000..14d5b8090 --- /dev/null +++ b/newlib/libc/posix/posix_spawn.c @@ -0,0 +1,579 @@ +/*- + * Copyright (c) 2008 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* +FUNCTION +<>, <>---spawn a process + +INDEX + posix_spawn +INDEX + posix_spawnp + +ANSI_SYNOPSIS + #include + + int posix_spawn(pid_t *<[pid]>, const char *<[path]>, + const posix_spawn_file_actions_t *<[file_actions]>, + const posix_spawnattr_t *<[attrp]>, + char *const <[argv]>, char *const <[envp]>); + int posix_spawnp(pid_t *<[pid]>, const char *<[file]>, + const posix_spawn_file_actions_t *<[file_actions]>, + const posix_spawnattr_t *<[attrp]>, + char *const <[argv]>, char *const <[envp]>); + +DESCRIPTION +Use <> and <> to create a new child process +from the specified process image file. <> is the argument count +and <> is an array of argument strings passed to the new program. +<> is an array of stings, which are passed as environment to the +new program. + +The <> argument to <> identifies the new process +image file to execute. The <> argument to <> is +used to construct a pathname that identifies the new process image +file by duplicating the actions of the shell in searching for an +executable file if the specified filename does not contain a `<>' +character. The <> is sought in the colon-separated list of +directory pathnames specified in the <> environment variable. + +The file descriptors remain open across <> and +<> except for those marked as close-on-exec. The open +file descriptors in the child process can be modified by the spawn file +actions object pointed to by <>. + +The spawn attributes object type pointed to by <> argument +may contain any of the attributes defined in <>. + +RETURNS +<> and <> return the process ID of the newly +spawned child process in the variable pointed by a non-NULL <<*<[pid]>>> +argument and zero as the function return value upon successful +completion. Otherwise, <> and <> return an +error number as the function return value to indicate the error; the +value stored into the variable pointed to by a non-NULL <<*<[pid]>>> +argument is unspecified. + +PORTABILITY +POSIX.1-2008 requires <> and <>. + +Supporting OS subroutines required: <<_close>>, <<_dup2>>, <<_fcntl>>, +<<_execve>>, <<_execvpe>>, <<_exit>>, <<_open>>, <<_sigaction>>, +<<_sigprocmask>>, <<_waitpid>>, <>, +<>, <>, <>, <>, <>. +*/ + +#ifndef _NO_POSIX_SPAWN + +#include + +#include "namespace.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +/* Only deal with a pointer to environ, to work around subtle bugs with shared + libraries and/or small data systems where the user declares his own + 'environ'. */ +static char ***p_environ = &environ; + +struct __posix_spawnattr { + short sa_flags; + pid_t sa_pgroup; + struct sched_param sa_schedparam; + int sa_schedpolicy; + sigset_t sa_sigdefault; + sigset_t sa_sigmask; +}; + +struct __posix_spawn_file_actions { + STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list; +}; + +typedef struct __posix_spawn_file_actions_entry { + STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list; + enum { FAE_OPEN, FAE_DUP2, FAE_CLOSE } fae_action; + + int fae_fildes; + union { + struct { + char *path; +#define fae_path fae_data.open.path + int oflag; +#define fae_oflag fae_data.open.oflag + mode_t mode; +#define fae_mode fae_data.open.mode + } open; + struct { + int newfildes; +#define fae_newfildes fae_data.dup2.newfildes + } dup2; + } fae_data; +} posix_spawn_file_actions_entry_t; + +/* + * Spawn routines + */ + +static int +process_spawnattr(_CONST posix_spawnattr_t sa) +{ + struct sigaction sigact = { .sa_flags = 0, .sa_handler = SIG_DFL }; + int i; + + /* + * POSIX doesn't really describe in which order everything + * should be set. We'll just set them in the order in which they + * are mentioned. + */ + + /* Set process group */ + if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) { + if (setpgid(0, sa->sa_pgroup) != 0) + return (errno); + } + + /* Set scheduler policy */ + if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) { + if (sched_setscheduler(0, sa->sa_schedpolicy, + &sa->sa_schedparam) != 0) + return (errno); + } else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) { + if (sched_setparam(0, &sa->sa_schedparam) != 0) + return (errno); + } + + /* Reset user ID's */ + if (sa->sa_flags & POSIX_SPAWN_RESETIDS) { + if (setegid(getgid()) != 0) + return (errno); + if (seteuid(getuid()) != 0) + return (errno); + } + + /* Set signal masks/defaults */ + if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) { + _sigprocmask(SIG_SETMASK, &sa->sa_sigmask, NULL); + } + + if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) { + for (i = 1; i < NSIG; i++) { + if (sigismember(&sa->sa_sigdefault, i)) + if (_sigaction(i, &sigact, NULL) != 0) + return (errno); + } + } + + return (0); +} + +static int +process_file_actions_entry(posix_spawn_file_actions_entry_t *fae) +{ + int fd; + + switch (fae->fae_action) { + case FAE_OPEN: + /* Perform an open(), make it use the right fd */ + fd = _open(fae->fae_path, fae->fae_oflag, fae->fae_mode); + if (fd < 0) + return (errno); + if (fd != fae->fae_fildes) { + if (_dup2(fd, fae->fae_fildes) == -1) + return (errno); + if (_close(fd) != 0) { + if (errno == EBADF) + return (EBADF); + } + } +#ifdef HAVE_FCNTL + if (_fcntl(fae->fae_fildes, F_SETFD, 0) == -1) + return (errno); +#endif /* HAVE_FCNTL */ + break; + case FAE_DUP2: + /* Perform a dup2() */ + if (_dup2(fae->fae_fildes, fae->fae_newfildes) == -1) + return (errno); +#ifdef HAVE_FCNTL + if (_fcntl(fae->fae_newfildes, F_SETFD, 0) == -1) + return (errno); +#endif /* HAVE_FCNTL */ + break; + case FAE_CLOSE: + /* Perform a close(), do not fail if already closed */ + (void)_close(fae->fae_fildes); + break; + } + return (0); +} + +static int +process_file_actions(_CONST posix_spawn_file_actions_t fa) +{ + posix_spawn_file_actions_entry_t *fae; + int error; + + /* Replay all file descriptor modifications */ + STAILQ_FOREACH(fae, &fa->fa_list, fae_list) { + error = process_file_actions_entry(fae); + if (error) + return (error); + } + return (0); +} + +static int +do_posix_spawn(pid_t *pid, _CONST char *path, + _CONST posix_spawn_file_actions_t *fa, + _CONST posix_spawnattr_t *sa, + char * _CONST argv[], char * _CONST envp[], int use_env_path) +{ + pid_t p; + volatile int error = 0; + + p = vfork(); + switch (p) { + case -1: + return (errno); + case 0: + if (sa != NULL) { + error = process_spawnattr(*sa); + if (error) + _exit(127); + } + if (fa != NULL) { + error = process_file_actions(*fa); + if (error) + _exit(127); + } + if (use_env_path) + _execvpe(path, argv, envp != NULL ? envp : *p_environ); + else + _execve(path, argv, envp != NULL ? envp : *p_environ); + error = errno; + _exit(127); + default: + if (error != 0) + _waitpid(p, NULL, WNOHANG); + else if (pid != NULL) + *pid = p; + return (error); + } +} + +int +_DEFUN(posix_spawn, (pid, path, fa, sa, argv, envp), + pid_t *pid _AND + _CONST char *path _AND + _CONST posix_spawn_file_actions_t *fa _AND + _CONST posix_spawnattr_t *sa _AND + char * _CONST argv[] _AND + char * _CONST envp[]) +{ + return do_posix_spawn(pid, path, fa, sa, argv, envp, 0); +} + +int +_DEFUN(posix_spawnp, (pid, path, fa, sa, argv, envp), + pid_t *pid _AND + _CONST char *path _AND + _CONST posix_spawn_file_actions_t *fa _AND + _CONST posix_spawnattr_t *sa _AND + char * _CONST argv[] _AND + char * _CONST envp[]) +{ + return do_posix_spawn(pid, path, fa, sa, argv, envp, 1); +} + +/* + * File descriptor actions + */ + +int +_DEFUN(posix_spawn_file_actions_init, (ret), + posix_spawn_file_actions_t *ret) +{ + posix_spawn_file_actions_t fa; + + fa = malloc(sizeof(struct __posix_spawn_file_actions)); + if (fa == NULL) + return (-1); + + STAILQ_INIT(&fa->fa_list); + *ret = fa; + return (0); +} + +int +_DEFUN(posix_spawn_file_action_destroy, (fa), + posix_spawn_file_actions_t *fa) +{ + posix_spawn_file_actions_entry_t *fae; + + while ((fae = STAILQ_FIRST(&(*fa)->fa_list)) != NULL) { + /* Remove file action entry from the queue */ + STAILQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list); + + /* Deallocate file action entry */ + if (fae->fae_action == FAE_OPEN) + free(fae->fae_path); + free(fae); + } + + free(*fa); + return (0); +} + +int +_DEFUN(posix_spawn_file_actions_addopen, (fa, fildes, path, oflag, mode), + posix_spawn_file_actions_t * __restrict fa _AND + int fildes _AND + _CONST char * __restrict path _AND + int oflag _AND + mode_t mode) +{ + posix_spawn_file_actions_entry_t *fae; + int error; + + if (fildes < 0) + return (EBADF); + + /* Allocate object */ + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + /* Set values and store in queue */ + fae->fae_action = FAE_OPEN; + fae->fae_path = strdup(path); + if (fae->fae_path == NULL) { + error = errno; + free(fae); + return (error); + } + fae->fae_fildes = fildes; + fae->fae_oflag = oflag; + fae->fae_mode = mode; + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +int +_DEFUN(posix_spawn_file_actions_adddup2, (fa, fildes, newfildes), + posix_spawn_file_actions_t *fa _AND + int fildes _AND + int newfildes) +{ + posix_spawn_file_actions_entry_t *fae; + + if (fildes < 0 || newfildes < 0) + return (EBADF); + + /* Allocate object */ + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + /* Set values and store in queue */ + fae->fae_action = FAE_DUP2; + fae->fae_fildes = fildes; + fae->fae_newfildes = newfildes; + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +int +_DEFUN(posix_spawn_file_actions_addclose, (fa, fildes), + posix_spawn_file_actions_t *fa _AND + int fildes) +{ + posix_spawn_file_actions_entry_t *fae; + + if (fildes < 0) + return (EBADF); + + /* Allocate object */ + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + /* Set values and store in queue */ + fae->fae_action = FAE_CLOSE; + fae->fae_fildes = fildes; + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +/* + * Spawn attributes + */ + +int +_DEFUN(posix_spawnattr_init, (ret), + posix_spawnattr_t *ret) +{ + posix_spawnattr_t sa; + + sa = calloc(1, sizeof(struct __posix_spawnattr)); + if (sa == NULL) + return (errno); + + /* Set defaults as specified by POSIX, cleared above */ + *ret = sa; + return (0); +} + +int +_DEFUN(posix_spawnattr_destroy, (sa), + posix_spawnattr_t *sa) +{ + free(*sa); + return (0); +} + +int +_DEFUN(posix_spawnattr_getflags, (sa, flags), + _CONST posix_spawnattr_t * __restrict sa _AND + short * __restrict flags) +{ + *flags = (*sa)->sa_flags; + return (0); +} + +int +_DEFUN(posix_spawnattr_getpgroup, (sa, pgroup), + _CONST posix_spawnattr_t * __restrict sa _AND + pid_t * __restrict pgroup) +{ + *pgroup = (*sa)->sa_pgroup; + return (0); +} + +int +_DEFUN(posix_spawnattr_getschedparam, (sa, schedparam), + _CONST posix_spawnattr_t * __restrict sa _AND + struct sched_param * __restrict schedparam) +{ + *schedparam = (*sa)->sa_schedparam; + return (0); +} + +int +_DEFUN(posix_spawnattr_getschedpolicy, (sa, schedpolicy), + _CONST posix_spawnattr_t * __restrict sa _AND + int * __restrict schedpolicy) +{ + *schedpolicy = (*sa)->sa_schedpolicy; + return (0); +} + +int +_DEFUN(posix_spawnattr_getsigdefault, (sa, sigdefault), + _CONST posix_spawnattr_t * __restrict sa _AND + sigset_t * __restrict sigdefault) +{ + *sigdefault = (*sa)->sa_sigdefault; + return (0); +} + +int +_DEFUN(posix_spawnattr_getsigmask, (sa, sigmask), + _CONST posix_spawnattr_t * __restrict sa _AND + sigset_t * __restrict sigmask) +{ + *sigmask = (*sa)->sa_sigmask; + return (0); +} + +int +_DEFUN(posix_spawnattr_setflags, (sa, flags), + posix_spawnattr_t *sa _AND + short flags) +{ + (*sa)->sa_flags = flags; + return (0); +} + +int +_DEFUN(posix_spawnattr_setpgroup, (sa, pgroup), + posix_spawnattr_t *sa _AND + pid_t pgroup) +{ + (*sa)->sa_pgroup = pgroup; + return (0); +} + +int +_DEFUN(posix_spawnattr_setschedparam, (sa, schedparam), + posix_spawnattr_t * __restrict sa _AND + _CONST struct sched_param * __restrict schedparam) +{ + (*sa)->sa_schedparam = *schedparam; + return (0); +} + +int +_DEFUN(posix_spawnattr_setschedpolicy, (sa, schedpolicy), + posix_spawnattr_t *sa _AND + int schedpolicy) +{ + (*sa)->sa_schedpolicy = schedpolicy; + return (0); +} + +int +_DEFUN(posix_spawnattr_setsigdefault, (sa, sigdefault), + posix_spawnattr_t * __restrict sa _AND + _CONST sigset_t * __restrict sigdefault) +{ + (*sa)->sa_sigdefault = *sigdefault; + return (0); +} + +int +_DEFUN(posix_spawnattr_setsigmask, (sa, sigmask), + posix_spawnattr_t * __restrict sa _AND + _CONST sigset_t * __restrict sigmask) +{ + (*sa)->sa_sigmask = *sigmask; + return (0); +} + +#endif /* !_NO_POSIX_SPAWN */