aboutsummaryrefslogtreecommitdiffstats
path: root/main/libc0.9.32/0001-librt-add-posix_spawn-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'main/libc0.9.32/0001-librt-add-posix_spawn-support.patch')
-rw-r--r--main/libc0.9.32/0001-librt-add-posix_spawn-support.patch853
1 files changed, 853 insertions, 0 deletions
diff --git a/main/libc0.9.32/0001-librt-add-posix_spawn-support.patch b/main/libc0.9.32/0001-librt-add-posix_spawn-support.patch
new file mode 100644
index 0000000000..29725529ce
--- /dev/null
+++ b/main/libc0.9.32/0001-librt-add-posix_spawn-support.patch
@@ -0,0 +1,853 @@
+From 0dcf66744f533e160232072bd03273ca1c448879 Mon Sep 17 00:00:00 2001
+From: Ismael Luceno <ismael.luceno@gmail.com>
+Date: Mon, 5 Mar 2012 06:43:49 -0200
+Subject: [PATCH] librt: add posix_spawn support
+
+Signed-off-by: Ismael Luceno <ismael.luceno@gmail.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+---
+ Makefile.in | 1 +
+ include/spawn.h | 266 +++++++++++++++++++++++++++++++++++++++++
+ librt/Makefile.in | 8 ++
+ librt/spawn.c | 259 +++++++++++++++++++++++++++++++++++++++
+ librt/spawn_faction_addclose.c | 51 ++++++++
+ librt/spawn_faction_adddup2.c | 52 ++++++++
+ librt/spawn_faction_addopen.c | 55 +++++++++
+ librt/spawn_faction_init.c | 42 +++++++
+ librt/spawn_int.h | 26 ++++
+ 9 files changed, 760 insertions(+)
+ create mode 100644 include/spawn.h
+ create mode 100644 librt/spawn.c
+ create mode 100644 librt/spawn_faction_addclose.c
+ create mode 100644 librt/spawn_faction_adddup2.c
+ create mode 100644 librt/spawn_faction_addopen.c
+ create mode 100644 librt/spawn_faction_init.c
+ create mode 100644 librt/spawn_int.h
+
+diff --git a/Makefile.in b/Makefile.in
+index d0ac6c0..82a2eff 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -290,6 +290,7 @@ HEADERS_RM-$(UCLIBC_SUPPORT_AI_ADDRCONFIG) += ifaddrs.h
+ HEADERS_RM-$(UCLIBC_SV4_DEPRECATED) += ustat.h sys/ustat.h bits/ustat.h
+ HEADERS_RM-$(UCLIBC_SUSV3_LEGACY) += sys/timeb.h regexp.h
+ HEADERS_RM-$(UCLIBC_SUSV4_LEGACY) += utime.h ucontext.h
++HEADERS_RM-$(UCLIBC_HAS_ADVANCED_REALTIME) += spawn.h
+
+ ifneq ($(findstring install,$(MAKECMDGOALS)),)
+ $(addprefix $(PREFIX)$(DEVEL_PREFIX),include $(MULTILIB_DIR)):
+diff --git a/include/spawn.h b/include/spawn.h
+new file mode 100644
+index 0000000..8b07bb8
+--- /dev/null
++++ b/include/spawn.h
+@@ -0,0 +1,266 @@
++/* Definitions for POSIX spawn interface.
++ Copyright (C) 2000,2003,2004,2009,2011,2012 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#ifndef _SPAWN_H
++#define _SPAWN_H 1
++
++#include <errno.h>
++#include <string.h>
++#include <stdlib.h>
++
++#include <features.h>
++#include <sched.h>
++#define __need_sigset_t
++#include <signal.h>
++#include <sys/types.h>
++
++
++/* Data structure to contain attributes for thread creation. */
++typedef struct {
++ short int __flags;
++ pid_t __pgrp;
++ sigset_t __sd;
++ sigset_t __ss;
++ struct sched_param __sp;
++ int __policy;
++ int __pad[16];
++} posix_spawnattr_t;
++
++
++/* Data structure to contain information about the actions to be
++ performed in the new process with respect to file descriptors. */
++typedef struct {
++ int __allocated;
++ int __used;
++ struct __spawn_action *__actions;
++ int __pad[16];
++} posix_spawn_file_actions_t;
++
++
++/* Flags to be set in the `posix_spawnattr_t'. */
++#define POSIX_SPAWN_RESETIDS 0x01
++#define POSIX_SPAWN_SETPGROUP 0x02
++#define POSIX_SPAWN_SETSIGDEF 0x04
++#define POSIX_SPAWN_SETSIGMASK 0x08
++#define POSIX_SPAWN_SETSCHEDPARAM 0x10
++#define POSIX_SPAWN_SETSCHEDULER 0x20
++#define POSIX_SPAWN_USEVFORK 0x40 /* GNU extension */
++
++
++#define __POSIX_SPAWN_MASK (POSIX_SPAWN_RESETIDS \
++ | POSIX_SPAWN_SETPGROUP \
++ | POSIX_SPAWN_SETSIGDEF \
++ | POSIX_SPAWN_SETSIGMASK \
++ | POSIX_SPAWN_SETSCHEDPARAM \
++ | POSIX_SPAWN_SETSCHEDULER \
++ | POSIX_SPAWN_USEVFORK)
++
++__BEGIN_DECLS
++
++/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
++ Before running the process perform the actions described in FILE-ACTIONS.
++
++ This function is a possible cancellation point and therefore not
++ marked with __THROW. */
++int posix_spawn(pid_t * restrict pid, const char * restrict path,
++ const posix_spawn_file_actions_t * restrict file_actions,
++ const posix_spawnattr_t * restrict attrp,
++ char * const argv[restrict],
++ char * const envp[restrict]);
++
++/* Similar to `posix_spawn' but search for FILE in the PATH.
++
++ This function is a possible cancellation point and therefore not
++ marked with __THROW. */
++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[]);
++
++/* Initialize data structure with attributes for `spawn' to default values. */
++inline static int
++posix_spawnattr_init(posix_spawnattr_t *attr)
++{
++ memset(attr, 0, sizeof(*attr));
++ return 0;
++}
++
++/* Free resources associated with ATTR. */
++inline static int
++posix_spawnattr_destroy(posix_spawnattr_t *attr)
++{
++ return 0;
++}
++
++/* Store signal mask for signals with default handling from ATTR in
++ SIGDEFAULT. */
++inline static int
++posix_spawnattr_getsigdefault(const posix_spawnattr_t *attr,
++ sigset_t *sigdefault)
++{
++ memcpy(sigdefault, &attr->__sd, sizeof(sigset_t));
++ return 0;
++}
++
++
++/* Set signal mask for signals with default handling in ATTR to SIGDEFAULT. */
++inline static int
++posix_spawnattr_setsigdefault(posix_spawnattr_t *attr,
++ const sigset_t *sigdefault)
++{
++ memcpy(&attr->__sd, sigdefault, sizeof(sigset_t));
++ return 0;
++}
++
++/* Store signal mask for the new process from ATTR in SIGMASK. */
++inline static int
++posix_spawnattr_getsigmask(const posix_spawnattr_t *attr,
++ sigset_t *sigmask)
++{
++ memcpy(sigmask, &attr->__ss, sizeof(sigset_t));
++ return 0;
++}
++
++
++/* Set signal mask for the new process in ATTR to SIGMASK. */
++inline static int
++posix_spawnattr_setsigmask(posix_spawnattr_t *attr,
++ const sigset_t *sigmask)
++{
++ memcpy(&attr->__ss, sigmask, sizeof(sigset_t));
++ return 0;
++}
++
++/* Get flag word from the attribute structure. */
++inline static int
++posix_spawnattr_getflags(const posix_spawnattr_t *attr, short int *flags)
++{
++ *flags = attr->__flags;
++ return 0;
++}
++
++/* Store flags in the attribute structure. */
++inline static int
++posix_spawnattr_setflags(posix_spawnattr_t *attr, short int flags)
++{
++ /* Check no invalid bits are set. */
++ if (flags & ~__POSIX_SPAWN_MASK)
++ return EINVAL;
++
++ attr->__flags = flags;
++ return 0;
++}
++
++/* Get process group ID from the attribute structure. */
++inline static int
++posix_spawnattr_getpgroup(const posix_spawnattr_t *attr, pid_t *pgroup)
++{
++ *pgroup = attr->__pgrp;
++ return 0;
++}
++
++/* Store process group ID in the attribute structure. */
++inline static int
++posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup)
++{
++ attr->__pgrp = pgroup;
++ return 0;
++}
++
++/* Get scheduling policy from the attribute structure. */
++inline static int
++posix_spawnattr_getschedpolicy(const posix_spawnattr_t *attr,
++ int *schedpolicy)
++{
++ *schedpolicy = attr->__policy;
++ return 0;
++}
++
++/* Store scheduling policy in the attribute structure. */
++inline static int
++posix_spawnattr_setschedpolicy(posix_spawnattr_t *attr, int schedpolicy)
++{
++ switch (schedpolicy) {
++ case SCHED_OTHER:
++ case SCHED_FIFO:
++ case SCHED_RR:
++ break;
++ default:
++ return EINVAL;
++ }
++
++ attr->__policy = schedpolicy;
++ return 0;
++}
++
++/* Get scheduling parameters from the attribute structure. */
++static inline int
++posix_spawnattr_getschedparam(const posix_spawnattr_t *attr,
++ struct sched_param *schedparam)
++{
++ memcpy(schedparam, &attr->__sp, sizeof(attr->__sp));
++ return 0;
++}
++
++/* Store scheduling parameters in the attribute structure. */
++static inline int
++posix_spawnattr_setschedparam(posix_spawnattr_t *attr,
++ const struct sched_param *schedparam)
++{
++ attr->__sp = *schedparam;
++ return 0;
++}
++
++/* Initialize data structure for file attribute for `spawn' call. */
++inline static int
++posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions)
++{
++ memset(file_actions, 0, sizeof(*file_actions));
++ return 0;
++}
++
++/* Free resources associated with FILE-ACTIONS. */
++inline static int
++posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions)
++{
++ free(file_actions->__actions);
++ return 0;
++}
++
++/* Add an action to FILE-ACTIONS which tells the implementation to call
++ `open' for the given file during the `spawn' call. */
++int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * restrict
++ file_actions, int fd,
++ const char * restrict path,
++ int oflag, mode_t mode)
++ __THROW;
++
++/* Add an action to FILE-ACTIONS which tells the implementation to call
++ `close' for the given file descriptor during the `spawn' call. */
++int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions,
++ int fd)
++ __THROW;
++
++/* Add an action to FILE-ACTIONS which tells the implementation to call
++ `dup2' for the given file descriptors during the `spawn' call. */
++int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions,
++ int fd, int newfd) __THROW;
++
++__END_DECLS
++
++#endif /* spawn.h */
+diff --git a/librt/Makefile.in b/librt/Makefile.in
+index 909afd8..857efb5 100644
+--- a/librt/Makefile.in
++++ b/librt/Makefile.in
+@@ -33,6 +33,14 @@ else
+ librt_filter_SRC += clock_nanosleep.c clock_getcpuclockid.c clock_gettime.c
+ librt_SSRC :=
+ endif
++
++librt_filter_SRC += $(if $(UCLIBC_HAS_ADVANCED_REALTIME),, \
++ spawn.c \
++ spawn_faction_addclose.c \
++ spawn_faction_adddup2.c \
++ spawn_faction_addopen.c \
++ spawn_faction_init.c)
++
+ librt_SRC := $(filter-out $(librt_filter_SRC),$(librt_SRC))
+
+ librt_OBJ := $(patsubst %.c,$(librt_OUT)/%.o,$(librt_SRC))
+diff --git a/librt/spawn.c b/librt/spawn.c
+new file mode 100644
+index 0000000..b5935a1
+--- /dev/null
++++ b/librt/spawn.c
+@@ -0,0 +1,259 @@
++/* Copyright (C) 2000, 2011 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <errno.h>
++#include <alloca.h>
++#include <unistd.h>
++#include <signal.h>
++#include <stdbool.h>
++#include <fcntl.h>
++
++#include <sys/resource.h>
++#include <not-cancel.h>
++
++#include <spawn.h>
++#include "spawn_int.h"
++
++/* The Unix standard contains a long explanation of the way to signal
++ an error after the fork() was successful. Since no new wait status
++ was wanted there is no way to signal an error using one of the
++ available methods. The committee chose to signal an error by a
++ normal program exit with the exit code 127. */
++#define SPAWN_ERROR 127
++
++/* Execute file actions.
++ * Returns true on error.
++ */
++inline static bool execute_file_actions(const posix_spawn_file_actions_t *fa)
++{
++ struct rlimit64 fdlimit;
++ bool have_fdlimit = false;
++
++ for (int cnt = 0; cnt < fa->__used; ++cnt) {
++ struct __spawn_action *action = &fa->__actions[cnt];
++
++ switch (action->tag) {
++ case spawn_do_close:
++ if (close_not_cancel(action->action.close_action.fd) != 0) {
++ if (!have_fdlimit) {
++ getrlimit64(RLIMIT_NOFILE, &fdlimit);
++ have_fdlimit = true;
++ }
++
++ /* Only signal errors for file descriptors out of range. */
++ if (0 > action->action.close_action.fd
++ || action->action.close_action.fd >= fdlimit.rlim_cur)
++ /* Signal the error. */
++ return true;
++ }
++ break;
++
++ case spawn_do_open:;
++ int new_fd = open_not_cancel(action->action.open_action.path,
++ action->action.open_action.oflag
++ | O_LARGEFILE,
++ action->action.open_action.mode);
++
++ if (new_fd == -1)
++ return true;
++
++ /* Make sure the desired file descriptor is used. */
++ if (new_fd != action->action.open_action.fd) {
++ if (dup2(new_fd, action->action.open_action.fd)
++ != action->action.open_action.fd)
++ return true;
++
++ if (close_not_cancel(new_fd) != 0)
++ return true;
++ }
++ break;
++
++ case spawn_do_dup2:
++ if (dup2(action->action.dup2_action.fd,
++ action->action.dup2_action.newfd)
++ != action->action.dup2_action.newfd)
++ return true;
++ break;
++ }
++ }
++
++ return false;
++}
++
++#define DANGEROUS (POSIX_SPAWN_SETSIGMASK \
++ | POSIX_SPAWN_SETSIGDEF \
++ | POSIX_SPAWN_SETSCHEDPARAM \
++ | POSIX_SPAWN_SETSCHEDULER \
++ | POSIX_SPAWN_SETPGROUP \
++ | POSIX_SPAWN_RESETIDS)
++inline static bool is_vfork_safe(short int flags)
++{
++ return ((flags & POSIX_SPAWN_USEVFORK) || !(flags & DANGEROUS));
++}
++
++
++/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
++ Before running the process perform the actions described in FILE-ACTIONS. */
++static int
++__spawni(pid_t *pid, const char *file,
++ const posix_spawn_file_actions_t *fa,
++ const posix_spawnattr_t *attrp, char *const argv[],
++ char *const envp[], const char *path)
++{
++ short int flags = attrp ? attrp->__flags : 0;
++
++ pid_t new_pid;
++ if (is_vfork_safe(flags) && !fa)
++ new_pid = vfork();
++ else
++ new_pid = fork();
++
++ if (new_pid) {
++ if (new_pid < 0)
++ return errno;
++
++ if (pid)
++ *pid = new_pid;
++
++ return 0;
++ }
++
++ if (flags & POSIX_SPAWN_SETSIGMASK) {
++ if (sigprocmask(SIG_SETMASK, &attrp->__ss, NULL) != 0)
++ goto error;
++ }
++
++ if (flags & POSIX_SPAWN_SETSIGDEF) {
++ /* We have to iterate over all signals. This could possibly be
++ done better but it requires system specific solutions since
++ the sigset_t data type can be very different on different
++ architectures. */
++ struct sigaction sa;
++
++ memset(&sa, 0, sizeof(sa));
++ sa.sa_handler = SIG_DFL;
++
++ for (int sig = 1; sig <= _NSIG; ++sig) {
++ if (sigismember(&attrp->__sd, sig)) {
++ if (sigaction(sig, &sa, NULL) != 0)
++ goto error;
++ }
++ }
++ }
++
++ if (flags & POSIX_SPAWN_SETSCHEDULER) {
++ if (sched_setscheduler(0, attrp->__policy, &attrp->__sp) == -1)
++ goto error;
++ } else if (flags & POSIX_SPAWN_SETSCHEDPARAM) {
++ if (sched_setparam(0, &attrp->__sp) == -1)
++ goto error;
++ }
++
++ if (flags & POSIX_SPAWN_SETPGROUP) {
++ if (setpgid(0, attrp->__pgrp) != 0)
++ goto error;
++ }
++
++ if (flags & POSIX_SPAWN_RESETIDS) {
++ if (seteuid(getuid()) || setegid(getgid()))
++ goto error;
++ }
++
++ if (fa && execute_file_actions(fa))
++ goto error;
++
++ if (!path || strchr(file, '/')) {
++ execve(file, argv, envp);
++ goto error;
++ }
++
++
++ char *name;
++ {
++ size_t filelen = strlen(file) + 1;
++ size_t pathlen = strlen(path) + 1;
++ name = alloca(pathlen + filelen);
++
++ /* Copy the file name at the top. */
++ name = (char *) memcpy(name + pathlen, file, filelen);
++
++ /* And add the slash. */
++ *--name = '/';
++ }
++
++ char *p;
++ do {
++ char *startp;
++ p = strchrnul(path, ':');
++
++ /* Two adjacent colons, or a colon at the beginning or the end
++ of `PATH' means to search the current directory. */
++ if (p == path)
++ startp = name + 1;
++ else
++ startp = (char *) memcpy(name - (p - path), path, p - path);
++
++ execve(startp, argv, envp);
++
++ switch (errno) {
++ case EACCES:
++ case ENOENT:
++ case ESTALE:
++ case ENOTDIR:
++ /* Those errors indicate the file is missing or not
++ executable by us, in which case we want to just try
++ the next path directory. */
++ break;
++ default:
++ /* Some other error means we found an executable file,
++ but something went wrong executing it; return the
++ error to our caller. */
++ goto error;
++ }
++
++ path = p;
++ } while (*p++ != '\0');
++
++error:
++ _exit(SPAWN_ERROR);
++}
++
++/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
++ Before running the process perform the actions described in FILE-ACTIONS. */
++int posix_spawn (pid_t *pid, const char *path,
++ const posix_spawn_file_actions_t *fa,
++ const posix_spawnattr_t *attrp, char *const argv[],
++ char *const envp[])
++{
++ return __spawni(pid, path, fa, attrp, argv, envp, NULL);
++}
++
++/* Spawn a new process executing FILE with the attributes describes in *ATTRP.
++ Before running the process perform the actions described in FILE-ACTIONS. */
++int
++posix_spawnp(pid_t *pid, const char *file,
++ const posix_spawn_file_actions_t *fa,
++ const posix_spawnattr_t *attrp, char *const argv[],
++ char *const envp[])
++{
++ const char *path = getenv("PATH");
++
++ if (!path)
++ path = ":/bin:/usr/bin";
++
++ return __spawni(pid, file, fa, attrp, argv, envp, path);
++}
+diff --git a/librt/spawn_faction_addclose.c b/librt/spawn_faction_addclose.c
+new file mode 100644
+index 0000000..b418f96
+--- /dev/null
++++ b/librt/spawn_faction_addclose.c
+@@ -0,0 +1,51 @@
++/* Copyright (C) 2000 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <errno.h>
++#include <spawn.h>
++#include <unistd.h>
++
++#include "spawn_int.h"
++
++/* Add an action to FILE-ACTIONS which tells the implementation to call
++ `close' for the given file descriptor during the `spawn' call. */
++int
++posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions,
++ int fd)
++{
++ int maxfd = sysconf(_SC_OPEN_MAX);
++ struct __spawn_action *rec;
++
++ /* Test for the validity of the file descriptor. */
++ if (fd < 0 || fd >= maxfd)
++ return EBADF;
++
++ /* Allocate more memory if needed. */
++ if (file_actions->__used == file_actions->__allocated
++ && __posix_spawn_file_actions_realloc(file_actions) != 0)
++ /* This can only mean we ran out of memory. */
++ return ENOMEM;
++
++ /* Add the new value. */
++ rec = &file_actions->__actions[file_actions->__used];
++ rec->tag = spawn_do_close;
++ rec->action.open_action.fd = fd;
++
++ /* Account for the new entry. */
++ ++file_actions->__used;
++ return 0;
++}
+diff --git a/librt/spawn_faction_adddup2.c b/librt/spawn_faction_adddup2.c
+new file mode 100644
+index 0000000..6d73313
+--- /dev/null
++++ b/librt/spawn_faction_adddup2.c
+@@ -0,0 +1,52 @@
++/* Copyright (C) 2000 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <errno.h>
++#include <spawn.h>
++#include <unistd.h>
++
++#include "spawn_int.h"
++
++/* Add an action to FILE-ACTIONS which tells the implementation to call
++ `dup2' for the given file descriptors during the `spawn' call. */
++int
++posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions,
++ int fd, int newfd)
++{
++ int maxfd = sysconf(_SC_OPEN_MAX);
++ struct __spawn_action *rec;
++
++ /* Test for the validity of the file descriptor. */
++ if (fd < 0 || newfd < 0 || fd >= maxfd || newfd >= maxfd)
++ return EBADF;
++
++ /* Allocate more memory if needed. */
++ if (file_actions->__used == file_actions->__allocated
++ && __posix_spawn_file_actions_realloc (file_actions) != 0)
++ /* This can only mean we ran out of memory. */
++ return ENOMEM;
++
++ /* Add the new value. */
++ rec = &file_actions->__actions[file_actions->__used];
++ rec->tag = spawn_do_dup2;
++ rec->action.dup2_action.fd = fd;
++ rec->action.dup2_action.newfd = newfd;
++
++ /* Account for the new entry. */
++ ++file_actions->__used;
++ return 0;
++}
+diff --git a/librt/spawn_faction_addopen.c b/librt/spawn_faction_addopen.c
+new file mode 100644
+index 0000000..285ca71
+--- /dev/null
++++ b/librt/spawn_faction_addopen.c
+@@ -0,0 +1,55 @@
++/* Copyright (C) 2000 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <errno.h>
++#include <spawn.h>
++#include <unistd.h>
++
++#include "spawn_int.h"
++
++/* Add an action to FILE-ACTIONS which tells the implementation to call
++ `open' for the given file during the `spawn' call. */
++int
++posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *file_actions,
++ int fd, const char *path, int oflag,
++ mode_t mode)
++{
++ int maxfd = sysconf(_SC_OPEN_MAX);
++ struct __spawn_action *rec;
++
++ /* Test for the validity of the file descriptor. */
++ if (fd < 0 || fd >= maxfd)
++ return EBADF;
++
++ /* Allocate more memory if needed. */
++ if (file_actions->__used == file_actions->__allocated
++ && __posix_spawn_file_actions_realloc (file_actions) != 0)
++ /* This can only mean we ran out of memory. */
++ return ENOMEM;
++
++ /* Add the new value. */
++ rec = &file_actions->__actions[file_actions->__used];
++ rec->tag = spawn_do_open;
++ rec->action.open_action.fd = fd;
++ rec->action.open_action.path = path;
++ rec->action.open_action.oflag = oflag;
++ rec->action.open_action.mode = mode;
++
++ /* Account for the new entry. */
++ ++file_actions->__used;
++ return 0;
++}
+diff --git a/librt/spawn_faction_init.c b/librt/spawn_faction_init.c
+new file mode 100644
+index 0000000..fb398a5
+--- /dev/null
++++ b/librt/spawn_faction_init.c
+@@ -0,0 +1,42 @@
++/* Copyright (C) 2000 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <errno.h>
++#include <spawn.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include "spawn_int.h"
++
++
++/* Function used to increase the size of the allocated array. This
++ function is called from the `add'-functions. */
++int
++__posix_spawn_file_actions_realloc(posix_spawn_file_actions_t *file_actions)
++{
++ int newalloc = file_actions->__allocated + 8;
++ void *newmem = realloc(file_actions->__actions,
++ newalloc * sizeof(struct __spawn_action));
++
++ if (newmem == NULL)
++ /* Not enough memory. */
++ return ENOMEM;
++
++ file_actions->__actions = (struct __spawn_action *)newmem;
++ file_actions->__allocated = newalloc;
++ return 0;
++}
+diff --git a/librt/spawn_int.h b/librt/spawn_int.h
+new file mode 100644
+index 0000000..89c88db
+--- /dev/null
++++ b/librt/spawn_int.h
+@@ -0,0 +1,26 @@
++/* Data structure to contain the action information. */
++struct __spawn_action {
++ enum {
++ spawn_do_close,
++ spawn_do_dup2,
++ spawn_do_open
++ } tag;
++
++ union {
++ struct {
++ int fd;
++ } close_action;
++ struct {
++ int fd;
++ int newfd;
++ } dup2_action;
++ struct {
++ int fd;
++ const char *path;
++ int oflag;
++ mode_t mode;
++ } open_action;
++ } action;
++};
++
++int __posix_spawn_file_actions_realloc(posix_spawn_file_actions_t *fa);
+--
+1.8.4
+