]> git.saurik.com Git - apple/libc.git/blame - gen/FreeBSD/popen.c.patch
Libc-594.9.5.tar.gz
[apple/libc.git] / gen / FreeBSD / popen.c.patch
CommitLineData
34e8f829
A
1--- popen.c.orig 2009-03-03 02:04:57.000000000 -0800
2+++ popen.c 2009-03-03 15:28:31.000000000 -0800
3@@ -34,6 +34,10 @@
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 */
14@@ -43,7 +47,8 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/pop
59e0d9fe
A
15 #include "namespace.h"
16 #include <sys/param.h>
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>
34e8f829
A
24@@ -52,17 +57,29 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/pop
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())
35
34e8f829 36-static struct pid {
59e0d9fe 37+/* 3516149 - store file descriptor and use that to close to prevent blocking */
34e8f829 38+struct pid {
9385eb3d 39 struct pid *next;
59e0d9fe
A
40 FILE *fp;
41+ int fd;
42 pid_t pid;
34e8f829
A
43-} *pidlist;
44-static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
45+};
46+#define pidlist __popen_pidlist
47+#define pidlist_mutex __popen_pidlist_mutex
48+#ifndef BUILDING_VARIANT
49+__private_extern__ struct pid *pidlist = NULL;
50+__private_extern__ pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
51+#else /* BUILDING_VARIANT */
52+extern struct pid *pidlist;
53+extern pthread_mutex_t pidlist_mutex;
54+#endif /* !BUILDING_VARIANT */
55
56 #define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&pidlist_mutex)
57 #define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&pidlist_mutex)
58@@ -73,85 +90,109 @@ popen(command, type)
59 {
60 struct pid *cur;
61 FILE *iop;
62- int pdes[2], pid, twoway;
63+ int pdes[2], pid, twoway, other;
59e0d9fe
A
64 char *argv[4];
65 struct pid *p;
34e8f829
A
66+ posix_spawn_file_actions_t file_actions;
67+ int err;
59e0d9fe
A
68
69- /*
70- * Lite2 introduced two-way popen() pipes using _socketpair().
71- * FreeBSD's pipe() is bidirectional, so we use that.
72- */
224c7076
A
73- if (strchr(type, '+')) {
74+ if (type == NULL) {
75+ errno = EINVAL;
76+ return (NULL);
77+ }
78+ if (strcmp(type, "r+") == 0) {
59e0d9fe
A
79 twoway = 1;
80 type = "r+";
81+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pdes) < 0)
82+ return (NULL);
83 } else {
84 twoway = 0;
224c7076
A
85- if ((*type != 'r' && *type != 'w') || type[1])
86+ if ((*type != 'r' && *type != 'w') || type[1]) {
87+ errno = EINVAL;
34e8f829
A
88+ return (NULL);
89+ }
90+ if (pipe(pdes) < 0)
59e0d9fe 91 return (NULL);
59e0d9fe 92 }
34e8f829
A
93- if (pipe(pdes) < 0)
94- return (NULL);
59e0d9fe 95
34e8f829
A
96- if ((cur = malloc(sizeof(struct pid))) == NULL) {
97+ /* fdopen can now fail */
98+ if (*type == 'r') {
99+ iop = fdopen(pdes[0], type);
100+ other = pdes[1];
101+ } else {
102+ iop = fdopen(pdes[1], type);
103+ other = pdes[0];
104+ }
105+ if (iop == NULL) {
59e0d9fe 106 (void)_close(pdes[0]);
34e8f829
A
107 (void)_close(pdes[1]);
108 return (NULL);
109 }
110
111+ if ((cur = malloc(sizeof(struct pid))) == NULL) {
112+ (void)fclose(iop);
113+ (void)_close(other);
114+ return (NULL);
115+ }
116+
117+ if ((err = posix_spawn_file_actions_init(&file_actions)) != 0) {
118+ (void)fclose(iop);
119+ (void)_close(other);
120+ free(cur);
121+ errno = err;
122+ return (NULL);
123+ }
124+ if (*type == 'r') {
125+ /*
126+ * The dup2() to STDIN_FILENO is repeated to avoid
127+ * writing to pdes[1], which might corrupt the
128+ * parent's copy. This isn't good enough in
129+ * general, since the _exit() is no return, so
130+ * the compiler is free to corrupt all the local
131+ * variables.
132+ */
133+ (void)posix_spawn_file_actions_addclose(&file_actions, pdes[0]);
134+ if (pdes[1] != STDOUT_FILENO) {
135+ (void)posix_spawn_file_actions_adddup2(&file_actions, pdes[1], STDOUT_FILENO);
136+ (void)posix_spawn_file_actions_addclose(&file_actions, pdes[1]);
137+ if (twoway)
138+ (void)posix_spawn_file_actions_adddup2(&file_actions, STDOUT_FILENO, STDIN_FILENO);
139+ } else if (twoway && (pdes[1] != STDIN_FILENO))
140+ (void)posix_spawn_file_actions_adddup2(&file_actions, pdes[1], STDIN_FILENO);
141+ } else {
142+ if (pdes[0] != STDIN_FILENO) {
143+ (void)posix_spawn_file_actions_adddup2(&file_actions, pdes[0], STDIN_FILENO);
144+ (void)posix_spawn_file_actions_addclose(&file_actions, pdes[0]);
145+ }
146+ (void)posix_spawn_file_actions_addclose(&file_actions, pdes[1]);
147+ }
148+ for (p = pidlist; p; p = p->next) {
149+ (void)posix_spawn_file_actions_addclose(&file_actions, p->fd);
150+ }
151+
152 argv[0] = "sh";
153 argv[1] = "-c";
154 argv[2] = (char *)command;
eb1cde05
A
155 argv[3] = NULL;
156
34e8f829 157- THREAD_LOCK();
eb1cde05 158- switch (pid = vfork()) {
34e8f829
A
159- case -1: /* Error. */
160- THREAD_UNLOCK();
161- (void)_close(pdes[0]);
162- (void)_close(pdes[1]);
163+ err = posix_spawn(&pid, _PATH_BSHELL, &file_actions, NULL, argv, environ);
164+ posix_spawn_file_actions_destroy(&file_actions);
165+
166+ if (err == ENOMEM || err == EAGAIN) { /* as if fork failed */
167+ (void)fclose(iop);
168+ (void)_close(other);
169 free(cur);
170+ errno = err;
171 return (NULL);
172- /* NOTREACHED */
173- case 0: /* Child. */
174- if (*type == 'r') {
175- /*
176- * The _dup2() to STDIN_FILENO is repeated to avoid
177- * writing to pdes[1], which might corrupt the
178- * parent's copy. This isn't good enough in
179- * general, since the _exit() is no return, so
180- * the compiler is free to corrupt all the local
181- * variables.
182- */
183- (void)_close(pdes[0]);
184- if (pdes[1] != STDOUT_FILENO) {
185- (void)_dup2(pdes[1], STDOUT_FILENO);
186- (void)_close(pdes[1]);
187- if (twoway)
188- (void)_dup2(STDOUT_FILENO, STDIN_FILENO);
189- } else if (twoway && (pdes[1] != STDIN_FILENO))
190- (void)_dup2(pdes[1], STDIN_FILENO);
191- } else {
192- if (pdes[0] != STDIN_FILENO) {
193- (void)_dup2(pdes[0], STDIN_FILENO);
194- (void)_close(pdes[0]);
195- }
196- (void)_close(pdes[1]);
197- }
198- for (p = pidlist; p; p = p->next) {
59e0d9fe 199- (void)_close(fileno(p->fp));
34e8f829
A
200- }
201- _execve(_PATH_BSHELL, argv, environ);
202- _exit(127);
203- /* NOTREACHED */
204+ } else if (err != 0) { /* couldn't exec the shell */
205+ pid = -1;
206 }
207- THREAD_UNLOCK();
208
209- /* Parent; assume fdopen can't fail. */
59e0d9fe 210 if (*type == 'r') {
34e8f829 211- iop = fdopen(pdes[0], type);
59e0d9fe
A
212+ cur->fd = pdes[0];
213 (void)_close(pdes[1]);
214 } else {
34e8f829 215- iop = fdopen(pdes[1], type);
59e0d9fe
A
216+ cur->fd = pdes[1];
217 (void)_close(pdes[0]);
218 }
219
34e8f829 220@@ -162,10 +203,11 @@ popen(command, type)
224c7076
A
221 cur->next = pidlist;
222 pidlist = cur;
223 THREAD_UNLOCK();
224-
225+ fwide(iop, -1); /* byte stream */
226 return (iop);
227 }
228
34e8f829
A
229+#ifndef BUILDING_VARIANT
230 /*
231 * pclose --
232 * Pclose returns -1 if stream is not associated with a `popened' command,
233@@ -198,6 +240,10 @@ pclose(iop)
234
235 (void)fclose(iop);
236
237+ if (cur->pid < 0) {
238+ free(cur);
239+ return W_EXITCODE(127, 0);
240+ }
241 do {
242 pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0);
243 } while (pid == -1 && errno == EINTR);
244@@ -206,3 +252,4 @@ pclose(iop)
245
246 return (pid == -1 ? -1 : pstat);
247 }
248+#endif /* !BUILDING_VARIANT */