Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Johnston <jjohnstn@redhat.com>2013-10-01 22:08:46 +0400
committerJeff Johnston <jjohnstn@redhat.com>2013-10-01 22:08:46 +0400
commitc7c1a1ca1b33d73541326629bfe8fa48480c890b (patch)
tree3d607d0e503e156bb26b98c1d29df177659f070d /newlib/libc/posix
parent05a8ad9f727dcf74c06863a19167c5593a8580a2 (diff)
2013-10-01 Petr Hosek <phosek@chromium.org>
* 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.
Diffstat (limited to 'newlib/libc/posix')
-rw-r--r--newlib/libc/posix/Makefile.am2
-rw-r--r--newlib/libc/posix/Makefile.in12
-rw-r--r--newlib/libc/posix/posix_spawn.c579
3 files changed, 589 insertions, 4 deletions
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 <ed@FreeBSD.org>
+ * 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
+<<posix_spawn>>, <<posix_spawnp>>---spawn a process
+
+INDEX
+ posix_spawn
+INDEX
+ posix_spawnp
+
+ANSI_SYNOPSIS
+ #include <spawn.h>
+
+ 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 <<posix_spawn>> and <<posix_spawnp>> to create a new child process
+from the specified process image file. <<argc>> is the argument count
+and <<argv>> is an array of argument strings passed to the new program.
+<<envp>> is an array of stings, which are passed as environment to the
+new program.
+
+The <<path>> argument to <<posix_spawn>> identifies the new process
+image file to execute. The <<file>> argument to <<posix_spawnp>> 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 <<file>> is sought in the colon-separated list of
+directory pathnames specified in the <<PATH>> environment variable.
+
+The file descriptors remain open across <<posix_spawn>> and
+<<posix_spawnp>> 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 <<file_actions>>.
+
+The spawn attributes object type pointed to by <<attrp>> argument
+may contain any of the attributes defined in <<spawn.h>>.
+
+RETURNS
+<<posix_spawn>> and <<posix_spawnp>> 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, <<posix_spawn>> and <<posix_spawnp>> 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 <<posix_spawn>> and <<posix_spawnp>>.
+
+Supporting OS subroutines required: <<_close>>, <<_dup2>>, <<_fcntl>>,
+<<_execve>>, <<_execvpe>>, <<_exit>>, <<_open>>, <<_sigaction>>,
+<<_sigprocmask>>, <<_waitpid>>, <<sched_setscheduler>>,
+<<sched_setparam>>, <<setegid>>, <<seteuid>>, <<setpgid>>, <<vfork>>.
+*/
+
+#ifndef _NO_POSIX_SPAWN
+
+#include <sys/cdefs.h>
+
+#include "namespace.h"
+#include <sys/signal.h>
+#include <sys/queue.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <spawn.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#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 */