1 --- popen.c.orig 2009-12-02 15:21:37.000000000 -0800
2 +++ popen.c 2009-12-02 15:36:51.000000000 -0800
7 +#ifdef VARIANT_DARWINEXTSN
8 +#define _DARWIN_UNLIMITED_STREAMS
9 +#endif /* VARIANT_DARWINEXTSN */
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95";
13 #endif /* LIBC_SCCS and not lint */
14 @@ -40,7 +44,8 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/pop
15 #include <sys/param.h>
16 #include <sys/queue.h>
19 +#include <sys/socket.h>
20 +#include <wchar.h> /* fwide() */
24 @@ -49,18 +54,39 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/pop
29 #include "un-namespace.h"
30 #include "libc_private.h"
32 -extern char **environ;
33 +#include <crt_externs.h>
34 +#define environ (*_NSGetEnviron())
36 +/* Our queue.h doesn't have SLIST_REMOVE_AFTER in it yet
37 + * <rdar://problem/7431558> API: Add SLIST_REMOVE_AFTER to sys/queue.h (from FreeBSD)
39 +#ifndef SLIST_REMOVE_AFTER
40 +#define SLIST_REMOVE_AFTER(elm, field) do { \
41 + SLIST_NEXT(elm, field) = \
42 + SLIST_NEXT(SLIST_NEXT(elm, field), field); \
46 +/* 3516149 - store file descriptor and use that to close to prevent blocking */
48 SLIST_ENTRY(pid) next;
53 -static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
54 -static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
55 +#define pidlist __popen_pidlist
56 +#define pidlist_mutex __popen_pidlist_mutex
57 +#ifndef BUILDING_VARIANT
58 +__private_extern__ SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
59 +__private_extern__ pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
60 +#else /* BUILDING_VARIANT */
61 +extern SLIST_HEAD(, pid) pidlist;
62 +extern pthread_mutex_t pidlist_mutex;
63 +#endif /* !BUILDING_VARIANT */
65 #define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&pidlist_mutex)
66 #define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&pidlist_mutex)
67 @@ -71,84 +97,108 @@ popen(command, type)
71 - int pdes[2], pid, twoway;
72 + int pdes[2], pid, twoway, other;
75 + posix_spawn_file_actions_t file_actions;
79 - * Lite2 introduced two-way popen() pipes using _socketpair().
80 - * FreeBSD's pipe() is bidirectional, so we use that.
82 - if (strchr(type, '+')) {
87 + if (strcmp(type, "r+") == 0) {
90 + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pdes) < 0)
94 - if ((*type != 'r' && *type != 'w') || type[1])
95 + if ((*type != 'r' && *type != 'w') || type[1]) {
102 - if (pipe(pdes) < 0)
105 - if ((cur = malloc(sizeof(struct pid))) == NULL) {
106 + /* fdopen can now fail */
107 + if (*type == 'r') {
108 + iop = fdopen(pdes[0], type);
111 + iop = fdopen(pdes[1], type);
115 (void)_close(pdes[0]);
116 (void)_close(pdes[1]);
120 + if ((cur = malloc(sizeof(struct pid))) == NULL) {
122 + (void)_close(other);
126 + if ((err = posix_spawn_file_actions_init(&file_actions)) != 0) {
128 + (void)_close(other);
133 + if (*type == 'r') {
135 + * The dup2() to STDIN_FILENO is repeated to avoid
136 + * writing to pdes[1], which might corrupt the
137 + * parent's copy. This isn't good enough in
138 + * general, since the _exit() is no return, so
139 + * the compiler is free to corrupt all the local
142 + (void)posix_spawn_file_actions_addclose(&file_actions, pdes[0]);
143 + if (pdes[1] != STDOUT_FILENO) {
144 + (void)posix_spawn_file_actions_adddup2(&file_actions, pdes[1], STDOUT_FILENO);
145 + (void)posix_spawn_file_actions_addclose(&file_actions, pdes[1]);
147 + (void)posix_spawn_file_actions_adddup2(&file_actions, STDOUT_FILENO, STDIN_FILENO);
148 + } else if (twoway && (pdes[1] != STDIN_FILENO))
149 + (void)posix_spawn_file_actions_adddup2(&file_actions, pdes[1], STDIN_FILENO);
151 + if (pdes[0] != STDIN_FILENO) {
152 + (void)posix_spawn_file_actions_adddup2(&file_actions, pdes[0], STDIN_FILENO);
153 + (void)posix_spawn_file_actions_addclose(&file_actions, pdes[0]);
155 + (void)posix_spawn_file_actions_addclose(&file_actions, pdes[1]);
157 + SLIST_FOREACH(p, &pidlist, next)
158 + (void)posix_spawn_file_actions_addclose(&file_actions, p->fd);
162 argv[2] = (char *)command;
166 - switch (pid = vfork()) {
167 - case -1: /* Error. */
169 - (void)_close(pdes[0]);
170 - (void)_close(pdes[1]);
171 + err = posix_spawn(&pid, _PATH_BSHELL, &file_actions, NULL, argv, environ);
172 + posix_spawn_file_actions_destroy(&file_actions);
174 + if (err == ENOMEM || err == EAGAIN) { /* as if fork failed */
176 + (void)_close(other);
181 - case 0: /* Child. */
182 - if (*type == 'r') {
184 - * The _dup2() to STDIN_FILENO is repeated to avoid
185 - * writing to pdes[1], which might corrupt the
186 - * parent's copy. This isn't good enough in
187 - * general, since the _exit() is no return, so
188 - * the compiler is free to corrupt all the local
191 - (void)_close(pdes[0]);
192 - if (pdes[1] != STDOUT_FILENO) {
193 - (void)_dup2(pdes[1], STDOUT_FILENO);
194 - (void)_close(pdes[1]);
196 - (void)_dup2(STDOUT_FILENO, STDIN_FILENO);
197 - } else if (twoway && (pdes[1] != STDIN_FILENO))
198 - (void)_dup2(pdes[1], STDIN_FILENO);
200 - if (pdes[0] != STDIN_FILENO) {
201 - (void)_dup2(pdes[0], STDIN_FILENO);
202 - (void)_close(pdes[0]);
204 - (void)_close(pdes[1]);
206 - SLIST_FOREACH(p, &pidlist, next)
207 - (void)_close(fileno(p->fp));
208 - _execve(_PATH_BSHELL, argv, environ);
211 + } else if (err != 0) { /* couldn't exec the shell */
216 - /* Parent; assume fdopen can't fail. */
218 - iop = fdopen(pdes[0], type);
220 (void)_close(pdes[1]);
222 - iop = fdopen(pdes[1], type);
224 (void)_close(pdes[0]);
227 @@ -158,10 +208,11 @@ popen(command, type)
229 SLIST_INSERT_HEAD(&pidlist, cur, next);
232 + fwide(iop, -1); /* byte stream */
236 +#ifndef BUILDING_VARIANT
239 * Pclose returns -1 if stream is not associated with a `popened' command,
240 @@ -196,6 +247,10 @@ pclose(iop)
244 + if (cur->pid < 0) {
246 + return W_EXITCODE(127, 0);
249 pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0);
250 } while (pid == -1 && errno == EINTR);
251 @@ -204,3 +259,4 @@ pclose(iop)
253 return (pid == -1 ? -1 : pstat);
255 +#endif /* !BUILDING_VARIANT */