]> git.saurik.com Git - apple/libc.git/blame - gen/FreeBSD/popen.c.patch
Libc-763.13.tar.gz
[apple/libc.git] / gen / FreeBSD / popen.c.patch
CommitLineData
1f2f436a
A
1--- popen.c.orig 2009-12-02 15:21:37.000000000 -0800
2+++ popen.c 2009-12-02 15:36:51.000000000 -0800
3@@ -30,6 +30,10 @@
34e8f829
A
4 * SUCH DAMAGE.
5 */
6
7+#ifdef VARIANT_DARWINEXTSN
8+#define _DARWIN_UNLIMITED_STREAMS
9+#endif /* VARIANT_DARWINEXTSN */
10+
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 */
1f2f436a 14@@ -40,7 +44,8 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/pop
59e0d9fe 15 #include <sys/param.h>
1f2f436a 16 #include <sys/queue.h>
59e0d9fe 17 #include <sys/wait.h>
224c7076 18-
59e0d9fe 19+#include <sys/socket.h>
224c7076 20+#include <wchar.h> /* fwide() */
59e0d9fe
A
21 #include <signal.h>
22 #include <errno.h>
224c7076 23 #include <unistd.h>
1f2f436a 24@@ -49,18 +54,39 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/pop
34e8f829
A
25 #include <string.h>
26 #include <paths.h>
27 #include <pthread.h>
28+#include <spawn.h>
9385eb3d
A
29 #include "un-namespace.h"
30 #include "libc_private.h"
31
32-extern char **environ;
33+#include <crt_externs.h>
34+#define environ (*_NSGetEnviron())
1f2f436a
A
35+
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)
38+ */
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); \
43+} while (0)
44+#endif
9385eb3d 45
59e0d9fe 46+/* 3516149 - store file descriptor and use that to close to prevent blocking */
1f2f436a
A
47 struct pid {
48 SLIST_ENTRY(pid) next;
59e0d9fe
A
49 FILE *fp;
50+ int fd;
51 pid_t pid;
1f2f436a
A
52 };
53-static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
34e8f829 54-static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
34e8f829
A
55+#define pidlist __popen_pidlist
56+#define pidlist_mutex __popen_pidlist_mutex
57+#ifndef BUILDING_VARIANT
1f2f436a 58+__private_extern__ SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
34e8f829
A
59+__private_extern__ pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
60+#else /* BUILDING_VARIANT */
1f2f436a 61+extern SLIST_HEAD(, pid) pidlist;
34e8f829
A
62+extern pthread_mutex_t pidlist_mutex;
63+#endif /* !BUILDING_VARIANT */
64
65 #define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&pidlist_mutex)
66 #define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&pidlist_mutex)
1f2f436a 67@@ -71,84 +97,108 @@ popen(command, type)
34e8f829
A
68 {
69 struct pid *cur;
70 FILE *iop;
71- int pdes[2], pid, twoway;
72+ int pdes[2], pid, twoway, other;
59e0d9fe
A
73 char *argv[4];
74 struct pid *p;
34e8f829
A
75+ posix_spawn_file_actions_t file_actions;
76+ int err;
59e0d9fe
A
77
78- /*
79- * Lite2 introduced two-way popen() pipes using _socketpair().
80- * FreeBSD's pipe() is bidirectional, so we use that.
81- */
224c7076
A
82- if (strchr(type, '+')) {
83+ if (type == NULL) {
84+ errno = EINVAL;
85+ return (NULL);
86+ }
87+ if (strcmp(type, "r+") == 0) {
59e0d9fe
A
88 twoway = 1;
89 type = "r+";
90+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pdes) < 0)
91+ return (NULL);
92 } else {
93 twoway = 0;
224c7076
A
94- if ((*type != 'r' && *type != 'w') || type[1])
95+ if ((*type != 'r' && *type != 'w') || type[1]) {
96+ errno = EINVAL;
34e8f829
A
97+ return (NULL);
98+ }
99+ if (pipe(pdes) < 0)
59e0d9fe 100 return (NULL);
59e0d9fe 101 }
34e8f829
A
102- if (pipe(pdes) < 0)
103- return (NULL);
59e0d9fe 104
34e8f829
A
105- if ((cur = malloc(sizeof(struct pid))) == NULL) {
106+ /* fdopen can now fail */
107+ if (*type == 'r') {
108+ iop = fdopen(pdes[0], type);
109+ other = pdes[1];
110+ } else {
111+ iop = fdopen(pdes[1], type);
112+ other = pdes[0];
113+ }
114+ if (iop == NULL) {
59e0d9fe 115 (void)_close(pdes[0]);
34e8f829
A
116 (void)_close(pdes[1]);
117 return (NULL);
118 }
119
120+ if ((cur = malloc(sizeof(struct pid))) == NULL) {
121+ (void)fclose(iop);
122+ (void)_close(other);
123+ return (NULL);
124+ }
125+
126+ if ((err = posix_spawn_file_actions_init(&file_actions)) != 0) {
127+ (void)fclose(iop);
128+ (void)_close(other);
129+ free(cur);
130+ errno = err;
131+ return (NULL);
132+ }
133+ if (*type == 'r') {
134+ /*
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
140+ * variables.
141+ */
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]);
146+ if (twoway)
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);
150+ } else {
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]);
154+ }
155+ (void)posix_spawn_file_actions_addclose(&file_actions, pdes[1]);
156+ }
1f2f436a 157+ SLIST_FOREACH(p, &pidlist, next)
34e8f829 158+ (void)posix_spawn_file_actions_addclose(&file_actions, p->fd);
34e8f829
A
159+
160 argv[0] = "sh";
161 argv[1] = "-c";
162 argv[2] = (char *)command;
eb1cde05
A
163 argv[3] = NULL;
164
34e8f829 165- THREAD_LOCK();
eb1cde05 166- switch (pid = vfork()) {
34e8f829
A
167- case -1: /* Error. */
168- THREAD_UNLOCK();
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);
173+
174+ if (err == ENOMEM || err == EAGAIN) { /* as if fork failed */
175+ (void)fclose(iop);
176+ (void)_close(other);
177 free(cur);
178+ errno = err;
179 return (NULL);
180- /* NOTREACHED */
181- case 0: /* Child. */
182- if (*type == 'r') {
183- /*
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
189- * variables.
190- */
191- (void)_close(pdes[0]);
192- if (pdes[1] != STDOUT_FILENO) {
193- (void)_dup2(pdes[1], STDOUT_FILENO);
194- (void)_close(pdes[1]);
195- if (twoway)
196- (void)_dup2(STDOUT_FILENO, STDIN_FILENO);
197- } else if (twoway && (pdes[1] != STDIN_FILENO))
198- (void)_dup2(pdes[1], STDIN_FILENO);
199- } else {
200- if (pdes[0] != STDIN_FILENO) {
201- (void)_dup2(pdes[0], STDIN_FILENO);
202- (void)_close(pdes[0]);
203- }
204- (void)_close(pdes[1]);
205- }
1f2f436a 206- SLIST_FOREACH(p, &pidlist, next)
59e0d9fe 207- (void)_close(fileno(p->fp));
34e8f829
A
208- _execve(_PATH_BSHELL, argv, environ);
209- _exit(127);
210- /* NOTREACHED */
211+ } else if (err != 0) { /* couldn't exec the shell */
212+ pid = -1;
213 }
214- THREAD_UNLOCK();
215
216- /* Parent; assume fdopen can't fail. */
59e0d9fe 217 if (*type == 'r') {
34e8f829 218- iop = fdopen(pdes[0], type);
59e0d9fe
A
219+ cur->fd = pdes[0];
220 (void)_close(pdes[1]);
221 } else {
34e8f829 222- iop = fdopen(pdes[1], type);
59e0d9fe
A
223+ cur->fd = pdes[1];
224 (void)_close(pdes[0]);
225 }
226
1f2f436a
A
227@@ -158,10 +208,11 @@ popen(command, type)
228 THREAD_LOCK();
229 SLIST_INSERT_HEAD(&pidlist, cur, next);
224c7076
A
230 THREAD_UNLOCK();
231-
232+ fwide(iop, -1); /* byte stream */
233 return (iop);
234 }
235
34e8f829
A
236+#ifndef BUILDING_VARIANT
237 /*
238 * pclose --
239 * Pclose returns -1 if stream is not associated with a `popened' command,
1f2f436a 240@@ -196,6 +247,10 @@ pclose(iop)
34e8f829
A
241
242 (void)fclose(iop);
243
244+ if (cur->pid < 0) {
245+ free(cur);
246+ return W_EXITCODE(127, 0);
247+ }
248 do {
249 pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0);
250 } while (pid == -1 && errno == EINTR);
1f2f436a 251@@ -204,3 +259,4 @@ pclose(iop)
34e8f829
A
252
253 return (pid == -1 ? -1 : pstat);
254 }
255+#endif /* !BUILDING_VARIANT */