Loading...
--- Libc/Libc-391/gen/FreeBSD/popen.c.patch
+++ Libc/Libc-763.12/gen/FreeBSD/popen.c.patch
@@ -1,72 +1,255 @@
---- popen.c.orig Mon May 24 23:50:41 2004
-+++ popen.c Tue May 25 00:09:39 2004
-@@ -43,6 +43,7 @@
- #include "namespace.h"
+--- 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>
-@@ -55,11 +56,14 @@
+ #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 */
- static struct pid {
- struct pid *next;
+ struct pid {
+ SLIST_ENTRY(pid) next;
FILE *fp;
+ int fd;
pid_t pid;
- } *pidlist;
- static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
-@@ -77,20 +81,18 @@
+ };
+-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 (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])
++ if ((*type != 'r' && *type != 'w') || type[1]) {
++ errno = EINVAL;
++ return (NULL);
++ }
++ if (pipe(pdes) < 0)
return (NULL);
-+ if (pipe(pdes) < 0)
-+ return (NULL);
}
- if (pipe(pdes) < 0)
- return (NULL);
- if ((cur = malloc(sizeof(struct pid))) == 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]);
-@@ -138,7 +140,7 @@
- (void)_close(pdes[1]);
- }
- for (p = pidlist; p; p = p->next) {
+ (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));
-+ (void)_close(p->fd);
- }
- _execve(_PATH_BSHELL, argv, environ);
- _exit(127);
-@@ -149,9 +151,11 @@
- /* Parent; assume fdopen can't fail. */
+- _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);
+- iop = fdopen(pdes[0], type);
+ cur->fd = pdes[0];
(void)_close(pdes[1]);
} else {
- iop = fdopen(pdes[1], type);
+- 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 */