+++ /dev/null
---- popen.c.orig 2009-12-02 15:21:37.000000000 -0800
-+++ popen.c 2009-12-02 15:36:51.000000000 -0800
-@@ -30,6 +30,10 @@
- * SUCH DAMAGE.
- */
-
-+#ifdef VARIANT_DARWINEXTSN
-+#define _DARWIN_UNLIMITED_STREAMS
-+#endif /* VARIANT_DARWINEXTSN */
-+
- #if defined(LIBC_SCCS) && !defined(lint)
- static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95";
- #endif /* LIBC_SCCS and not lint */
-@@ -40,7 +44,8 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/pop
- #include <sys/param.h>
- #include <sys/queue.h>
- #include <sys/wait.h>
--
-+#include <sys/socket.h>
-+#include <wchar.h> /* fwide() */
- #include <signal.h>
- #include <errno.h>
- #include <unistd.h>
-@@ -49,18 +54,39 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/pop
- #include <string.h>
- #include <paths.h>
- #include <pthread.h>
-+#include <spawn.h>
- #include "un-namespace.h"
- #include "libc_private.h"
-
--extern char **environ;
-+#include <crt_externs.h>
-+#define environ (*_NSGetEnviron())
-+
-+/* Our queue.h doesn't have SLIST_REMOVE_AFTER in it yet
-+ * <rdar://problem/7431558> API: Add SLIST_REMOVE_AFTER to sys/queue.h (from FreeBSD)
-+ */
-+#ifndef SLIST_REMOVE_AFTER
-+#define SLIST_REMOVE_AFTER(elm, field) do { \
-+ SLIST_NEXT(elm, field) = \
-+ SLIST_NEXT(SLIST_NEXT(elm, field), field); \
-+} while (0)
-+#endif
-
-+/* 3516149 - store file descriptor and use that to close to prevent blocking */
- struct pid {
- SLIST_ENTRY(pid) next;
- FILE *fp;
-+ int fd;
- pid_t pid;
- };
--static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
--static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
-+#define pidlist __popen_pidlist
-+#define pidlist_mutex __popen_pidlist_mutex
-+#ifndef BUILDING_VARIANT
-+__private_extern__ SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
-+__private_extern__ pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
-+#else /* BUILDING_VARIANT */
-+extern SLIST_HEAD(, pid) pidlist;
-+extern pthread_mutex_t pidlist_mutex;
-+#endif /* !BUILDING_VARIANT */
-
- #define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&pidlist_mutex)
- #define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&pidlist_mutex)
-@@ -71,84 +97,108 @@ popen(command, type)
- {
- struct pid *cur;
- FILE *iop;
-- int pdes[2], pid, twoway;
-+ int pdes[2], pid, twoway, other;
- char *argv[4];
- struct pid *p;
-+ posix_spawn_file_actions_t file_actions;
-+ int err;
-
-- /*
-- * Lite2 introduced two-way popen() pipes using _socketpair().
-- * FreeBSD's pipe() is bidirectional, so we use that.
-- */
-- if (strchr(type, '+')) {
-+ if (type == NULL) {
-+ errno = EINVAL;
-+ return (NULL);
-+ }
-+ if (strcmp(type, "r+") == 0) {
- twoway = 1;
- type = "r+";
-+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pdes) < 0)
-+ return (NULL);
- } else {
- twoway = 0;
-- if ((*type != 'r' && *type != 'w') || type[1])
-+ if ((*type != 'r' && *type != 'w') || type[1]) {
-+ errno = EINVAL;
-+ return (NULL);
-+ }
-+ if (pipe(pdes) < 0)
- return (NULL);
- }
-- if (pipe(pdes) < 0)
-- return (NULL);
-
-- if ((cur = malloc(sizeof(struct pid))) == NULL) {
-+ /* fdopen can now fail */
-+ if (*type == 'r') {
-+ iop = fdopen(pdes[0], type);
-+ other = pdes[1];
-+ } else {
-+ iop = fdopen(pdes[1], type);
-+ other = pdes[0];
-+ }
-+ if (iop == NULL) {
- (void)_close(pdes[0]);
- (void)_close(pdes[1]);
- return (NULL);
- }
-
-+ if ((cur = malloc(sizeof(struct pid))) == NULL) {
-+ (void)fclose(iop);
-+ (void)_close(other);
-+ return (NULL);
-+ }
-+
-+ if ((err = posix_spawn_file_actions_init(&file_actions)) != 0) {
-+ (void)fclose(iop);
-+ (void)_close(other);
-+ free(cur);
-+ errno = err;
-+ return (NULL);
-+ }
-+ if (*type == 'r') {
-+ /*
-+ * The dup2() to STDIN_FILENO is repeated to avoid
-+ * writing to pdes[1], which might corrupt the
-+ * parent's copy. This isn't good enough in
-+ * general, since the _exit() is no return, so
-+ * the compiler is free to corrupt all the local
-+ * variables.
-+ */
-+ (void)posix_spawn_file_actions_addclose(&file_actions, pdes[0]);
-+ if (pdes[1] != STDOUT_FILENO) {
-+ (void)posix_spawn_file_actions_adddup2(&file_actions, pdes[1], STDOUT_FILENO);
-+ (void)posix_spawn_file_actions_addclose(&file_actions, pdes[1]);
-+ if (twoway)
-+ (void)posix_spawn_file_actions_adddup2(&file_actions, STDOUT_FILENO, STDIN_FILENO);
-+ } else if (twoway && (pdes[1] != STDIN_FILENO))
-+ (void)posix_spawn_file_actions_adddup2(&file_actions, pdes[1], STDIN_FILENO);
-+ } else {
-+ if (pdes[0] != STDIN_FILENO) {
-+ (void)posix_spawn_file_actions_adddup2(&file_actions, pdes[0], STDIN_FILENO);
-+ (void)posix_spawn_file_actions_addclose(&file_actions, pdes[0]);
-+ }
-+ (void)posix_spawn_file_actions_addclose(&file_actions, pdes[1]);
-+ }
-+ SLIST_FOREACH(p, &pidlist, next)
-+ (void)posix_spawn_file_actions_addclose(&file_actions, p->fd);
-+
- argv[0] = "sh";
- argv[1] = "-c";
- argv[2] = (char *)command;
- argv[3] = NULL;
-
-- THREAD_LOCK();
-- switch (pid = vfork()) {
-- case -1: /* Error. */
-- THREAD_UNLOCK();
-- (void)_close(pdes[0]);
-- (void)_close(pdes[1]);
-+ err = posix_spawn(&pid, _PATH_BSHELL, &file_actions, NULL, argv, environ);
-+ posix_spawn_file_actions_destroy(&file_actions);
-+
-+ if (err == ENOMEM || err == EAGAIN) { /* as if fork failed */
-+ (void)fclose(iop);
-+ (void)_close(other);
- free(cur);
-+ errno = err;
- return (NULL);
-- /* NOTREACHED */
-- case 0: /* Child. */
-- if (*type == 'r') {
-- /*
-- * The _dup2() to STDIN_FILENO is repeated to avoid
-- * writing to pdes[1], which might corrupt the
-- * parent's copy. This isn't good enough in
-- * general, since the _exit() is no return, so
-- * the compiler is free to corrupt all the local
-- * variables.
-- */
-- (void)_close(pdes[0]);
-- if (pdes[1] != STDOUT_FILENO) {
-- (void)_dup2(pdes[1], STDOUT_FILENO);
-- (void)_close(pdes[1]);
-- if (twoway)
-- (void)_dup2(STDOUT_FILENO, STDIN_FILENO);
-- } else if (twoway && (pdes[1] != STDIN_FILENO))
-- (void)_dup2(pdes[1], STDIN_FILENO);
-- } else {
-- if (pdes[0] != STDIN_FILENO) {
-- (void)_dup2(pdes[0], STDIN_FILENO);
-- (void)_close(pdes[0]);
-- }
-- (void)_close(pdes[1]);
-- }
-- SLIST_FOREACH(p, &pidlist, next)
-- (void)_close(fileno(p->fp));
-- _execve(_PATH_BSHELL, argv, environ);
-- _exit(127);
-- /* NOTREACHED */
-+ } else if (err != 0) { /* couldn't exec the shell */
-+ pid = -1;
- }
-- THREAD_UNLOCK();
-
-- /* Parent; assume fdopen can't fail. */
- if (*type == 'r') {
-- iop = fdopen(pdes[0], type);
-+ cur->fd = pdes[0];
- (void)_close(pdes[1]);
- } else {
-- iop = fdopen(pdes[1], type);
-+ cur->fd = pdes[1];
- (void)_close(pdes[0]);
- }
-
-@@ -158,10 +208,11 @@ popen(command, type)
- THREAD_LOCK();
- SLIST_INSERT_HEAD(&pidlist, cur, next);
- THREAD_UNLOCK();
--
-+ fwide(iop, -1); /* byte stream */
- return (iop);
- }
-
-+#ifndef BUILDING_VARIANT
- /*
- * pclose --
- * Pclose returns -1 if stream is not associated with a `popened' command,
-@@ -196,6 +247,10 @@ pclose(iop)
-
- (void)fclose(iop);
-
-+ if (cur->pid < 0) {
-+ free(cur);
-+ return W_EXITCODE(127, 0);
-+ }
- do {
- pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0);
- } while (pid == -1 && errno == EINTR);
-@@ -204,3 +259,4 @@ pclose(iop)
-
- return (pid == -1 ? -1 : pstat);
- }
-+#endif /* !BUILDING_VARIANT */