changeset 1615:dad40f8a408d

Add some stuff John Spencer needed so sabotage can bootstrap itself.
author Rob Landley <rob@landley.net>
date Thu, 11 Jul 2013 00:54:32 -0500
parents ee6db9e5cce3
children 5636dc006f09
files sources/baseconfig-busybox sources/patches/uClibc-posix_spawn.patch
diffstat 2 files changed, 835 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/sources/baseconfig-busybox	Thu Jul 11 00:29:06 2013 -0500
+++ b/sources/baseconfig-busybox	Thu Jul 11 00:54:32 2013 -0500
@@ -135,6 +135,11 @@
 CONFIG_LSPCI=y
 CONFIG_PING=y
 
+CONFIG_SHA512SUM=y
+CONFIG_FDISK=y
+CONFIG_FEATURE_FDISK_WRITABLE=y
+CONFIG_FEATURE_FDISK_ADVANCED=y
+
 # Stuff in toybox
 
 CONFIG_CAT=y
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sources/patches/uClibc-posix_spawn.patch	Thu Jul 11 00:54:32 2013 -0500
@@ -0,0 +1,830 @@
+Sabotage needs posix_spawn to bootstrap musl.
+
+Upstream, uClibc added posix_spawn and did it horribly. It's a straight copy
+from glibc, checked in before 0.9.33.2 released but not _in_ 0.9.33.2. Commit
+a969b3f3c08e removed the "we have this" indicator from the headers, but
+then commit 0dcf66744f53 didn't add it back...
+
+
+diff -ruN uClibc/include/spawn.h uClibc.bak/include/spawn.h
+--- uClibc/include/spawn.h	1969-12-31 18:00:00.000000000 -0600
++++ uClibc.bak/include/spawn.h	2013-07-11 00:04:24.024324269 -0500
+@@ -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 -ruN uClibc/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h uClibc.bak/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
+--- uClibc/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h	2012-05-15 02:20:09.000000000 -0500
++++ uClibc.bak/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h	2013-07-10 21:49:10.087986094 -0500
+@@ -149,10 +149,8 @@
+ /* We support spinlocks.  */
+ #define _POSIX_SPIN_LOCKS	200809L
+ 
+-#if 0 /* no support in uClibc (yet) */
+ /* The `spawn' function family is supported.  */
+ #define _POSIX_SPAWN	200809L
+-#endif
+ 
+ /* We have POSIX timers.  */
+ #define _POSIX_TIMERS	200809L
+diff -ruN uClibc/librt/Makefile.in uClibc.bak/librt/Makefile.in
+--- uClibc/librt/Makefile.in	2012-05-15 02:20:09.000000000 -0500
++++ uClibc.bak/librt/Makefile.in	2013-07-10 21:48:33.191984555 -0500
+@@ -33,6 +33,14 @@
+ 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 -ruN uClibc/librt/spawn.c uClibc.bak/librt/spawn.c
+--- uClibc/librt/spawn.c	1969-12-31 18:00:00.000000000 -0600
++++ uClibc.bak/librt/spawn.c	2013-07-10 21:48:33.191984555 -0500
+@@ -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 -ruN uClibc/librt/spawn_faction_addclose.c uClibc.bak/librt/spawn_faction_addclose.c
+--- uClibc/librt/spawn_faction_addclose.c	1969-12-31 18:00:00.000000000 -0600
++++ uClibc.bak/librt/spawn_faction_addclose.c	2013-07-10 21:48:33.191984555 -0500
+@@ -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 -ruN uClibc/librt/spawn_faction_adddup2.c uClibc.bak/librt/spawn_faction_adddup2.c
+--- uClibc/librt/spawn_faction_adddup2.c	1969-12-31 18:00:00.000000000 -0600
++++ uClibc.bak/librt/spawn_faction_adddup2.c	2013-07-10 21:48:33.219984556 -0500
+@@ -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 -ruN uClibc/librt/spawn_faction_addopen.c uClibc.bak/librt/spawn_faction_addopen.c
+--- uClibc/librt/spawn_faction_addopen.c	1969-12-31 18:00:00.000000000 -0600
++++ uClibc.bak/librt/spawn_faction_addopen.c	2013-07-10 21:48:33.219984556 -0500
+@@ -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 -ruN uClibc/librt/spawn_faction_init.c uClibc.bak/librt/spawn_faction_init.c
+--- uClibc/librt/spawn_faction_init.c	1969-12-31 18:00:00.000000000 -0600
++++ uClibc.bak/librt/spawn_faction_init.c	2013-07-10 21:48:33.219984556 -0500
+@@ -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 -ruN uClibc/librt/spawn_int.h uClibc.bak/librt/spawn_int.h
+--- uClibc/librt/spawn_int.h	1969-12-31 18:00:00.000000000 -0600
++++ uClibc.bak/librt/spawn_int.h	2013-07-10 21:48:33.219984556 -0500
+@@ -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);
+diff -ruN uClibc/Makefile.in uClibc.bak/Makefile.in
+--- uClibc/Makefile.in	2013-07-11 00:46:58.388430731 -0500
++++ uClibc.bak/Makefile.in	2013-07-10 21:48:33.187984555 -0500
+@@ -293,6 +293,7 @@
+ 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)):