]>
Commit | Line | Data |
---|---|---|
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 */ |