diff options
Diffstat (limited to 'win32/popen.c')
-rw-r--r-- | win32/popen.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/win32/popen.c b/win32/popen.c new file mode 100644 index 000000000..6b8e52ca9 --- /dev/null +++ b/win32/popen.c | |||
@@ -0,0 +1,318 @@ | |||
1 | #include <fcntl.h> | ||
2 | #include "libbb.h" | ||
3 | |||
4 | typedef struct { | ||
5 | PROCESS_INFORMATION piProcInfo; | ||
6 | HANDLE pipe[2]; | ||
7 | char mode; | ||
8 | int fd; | ||
9 | } pipe_data; | ||
10 | |||
11 | static pipe_data *pipes = NULL; | ||
12 | static int num_pipes = 0; | ||
13 | |||
14 | static int mingw_pipe(HANDLE *readwrite) | ||
15 | { | ||
16 | SECURITY_ATTRIBUTES sa; | ||
17 | |||
18 | sa.nLength = sizeof(sa); /* Length in bytes */ | ||
19 | sa.bInheritHandle = 1; /* the child must inherit these handles */ | ||
20 | sa.lpSecurityDescriptor = NULL; | ||
21 | |||
22 | if ( !CreatePipe (&readwrite[0], &readwrite[1], &sa, 1 << 13) ) { | ||
23 | return -1; | ||
24 | } | ||
25 | |||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | static pipe_data *find_pipe(void) | ||
30 | { | ||
31 | int i; | ||
32 | pipe_data *p = NULL; | ||
33 | |||
34 | /* find an unused pipe structure */ | ||
35 | for ( i=0; i<num_pipes; ++i ) { | ||
36 | if ( pipes[i].mode == '\0' ) { | ||
37 | p = pipes+i; | ||
38 | break; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | if ( p == NULL ) { | ||
43 | /* need to extend array */ | ||
44 | if ( (p=realloc(pipes, sizeof(pipe_data)*(num_pipes+10))) == NULL ) { | ||
45 | return NULL; | ||
46 | } | ||
47 | |||
48 | pipes = p; | ||
49 | for ( i=0; i<10; ++i ) { | ||
50 | memset(pipes+num_pipes+i, 0, sizeof(pipe_data)); | ||
51 | } | ||
52 | p = pipes + num_pipes; | ||
53 | num_pipes += 10; | ||
54 | } | ||
55 | |||
56 | p->pipe[0] = INVALID_HANDLE_VALUE; | ||
57 | p->pipe[1] = INVALID_HANDLE_VALUE; | ||
58 | |||
59 | return p; | ||
60 | } | ||
61 | |||
62 | FILE *mingw_popen(const char *cmd, const char *mode) | ||
63 | { | ||
64 | pipe_data *p; | ||
65 | FILE *fptr = NULL; | ||
66 | STARTUPINFO siStartInfo; | ||
67 | int success; | ||
68 | int fd; | ||
69 | int len, count; | ||
70 | int ip, ic; | ||
71 | char *cmd_buff = NULL; | ||
72 | const char *s; | ||
73 | char *t; | ||
74 | |||
75 | if ( cmd == NULL || *cmd == '\0' || mode == NULL || | ||
76 | (*mode != 'r' && *mode != 'w') ) { | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | /* find an unused pipe structure */ | ||
81 | if ( (p=find_pipe()) == NULL ) { | ||
82 | return NULL; | ||
83 | } | ||
84 | |||
85 | /* count double quotes */ | ||
86 | count = 0; | ||
87 | for ( s=cmd; *s; ++s ) { | ||
88 | if ( *s == '"' ) { | ||
89 | ++count; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | len = strlen(cmd) + 10 + count; | ||
94 | if ( (cmd_buff=malloc(len)) == NULL ) { | ||
95 | return NULL; | ||
96 | } | ||
97 | |||
98 | /* escape double quotes */ | ||
99 | strcpy(cmd_buff, "sh -c \""); | ||
100 | for ( s=cmd,t=cmd_buff+strlen(cmd_buff); *s; ++s ) { | ||
101 | if ( *s == '"' ) { | ||
102 | *t++ = '\\'; | ||
103 | } | ||
104 | *t++ = *s; | ||
105 | } | ||
106 | *t++ = '"'; | ||
107 | *t = '\0'; | ||
108 | |||
109 | /* Create the pipe */ | ||
110 | if ( mingw_pipe(p->pipe) == -1 ) { | ||
111 | goto finito; | ||
112 | } | ||
113 | |||
114 | /* index of parent end of pipe */ | ||
115 | ip = !(*mode == 'r'); | ||
116 | /* index of child end of pipe */ | ||
117 | ic = (*mode == 'r'); | ||
118 | |||
119 | /* Make the parent end of the pipe non-inheritable */ | ||
120 | SetHandleInformation(p->pipe[ip], HANDLE_FLAG_INHERIT, 0); | ||
121 | |||
122 | /* Now create the child process */ | ||
123 | ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); | ||
124 | siStartInfo.cb = sizeof(STARTUPINFO); | ||
125 | if ( *mode == 'r' ) { | ||
126 | siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); | ||
127 | siStartInfo.hStdOutput = p->pipe[ic]; | ||
128 | } | ||
129 | else { | ||
130 | siStartInfo.hStdInput = p->pipe[ic]; | ||
131 | siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); | ||
132 | } | ||
133 | siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); | ||
134 | siStartInfo.wShowWindow = SW_HIDE; | ||
135 | siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; | ||
136 | |||
137 | success = CreateProcess(NULL, | ||
138 | (LPTSTR)cmd_buff, /* command line */ | ||
139 | NULL, /* process security attributes */ | ||
140 | NULL, /* primary thread security attributes */ | ||
141 | TRUE, /* handles are inherited */ | ||
142 | 0, /* creation flags */ | ||
143 | NULL, /* use parent's environment */ | ||
144 | NULL, /* use parent's current directory */ | ||
145 | &siStartInfo, /* STARTUPINFO pointer */ | ||
146 | &p->piProcInfo); /* receives PROCESS_INFORMATION */ | ||
147 | |||
148 | if ( !success ) { | ||
149 | goto finito; | ||
150 | } | ||
151 | |||
152 | /* close child end of pipe */ | ||
153 | CloseHandle(p->pipe[ic]); | ||
154 | p->pipe[ic] = INVALID_HANDLE_VALUE; | ||
155 | |||
156 | if ( *mode == 'r' ) { | ||
157 | fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_RDONLY|_O_BINARY); | ||
158 | fptr = _fdopen(fd, "rb"); | ||
159 | } | ||
160 | else { | ||
161 | fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_WRONLY|_O_BINARY); | ||
162 | fptr = _fdopen(fd, "wb"); | ||
163 | } | ||
164 | |||
165 | finito: | ||
166 | if ( !fptr ) { | ||
167 | if ( p->pipe[0] != INVALID_HANDLE_VALUE ) { | ||
168 | CloseHandle(p->pipe[0]); | ||
169 | } | ||
170 | if ( p->pipe[1] != INVALID_HANDLE_VALUE ) { | ||
171 | CloseHandle(p->pipe[1]); | ||
172 | } | ||
173 | } | ||
174 | else { | ||
175 | p->mode = *mode; | ||
176 | p->fd = fd; | ||
177 | } | ||
178 | free(cmd_buff); | ||
179 | |||
180 | return fptr; | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * Open a pipe to a command where the file descriptor fd0 is used | ||
185 | * as input to the command (read mode) or as the destination of the | ||
186 | * output from the command (write mode). The pid of the command is | ||
187 | * returned in the variable pid, which can be NULL. | ||
188 | */ | ||
189 | int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid) | ||
190 | { | ||
191 | pipe_data *p; | ||
192 | STARTUPINFO siStartInfo; | ||
193 | int success; | ||
194 | int fd = -1; | ||
195 | int ip, ic; | ||
196 | |||
197 | if ( cmd == NULL || *cmd == '\0' || mode == NULL || | ||
198 | (*mode != 'r' && *mode != 'w') ) { | ||
199 | return -1; | ||
200 | } | ||
201 | |||
202 | /* find an unused pipe structure */ | ||
203 | if ( (p=find_pipe()) == NULL ) { | ||
204 | return -1; | ||
205 | } | ||
206 | |||
207 | /* Create the pipe */ | ||
208 | if ( mingw_pipe(p->pipe) == -1 ) { | ||
209 | goto finito; | ||
210 | } | ||
211 | |||
212 | /* index of parent end of pipe */ | ||
213 | ip = !(*mode == 'r'); | ||
214 | /* index of child end of pipe */ | ||
215 | ic = (*mode == 'r'); | ||
216 | |||
217 | /* Make the parent end of the pipe non-inheritable */ | ||
218 | SetHandleInformation(p->pipe[ip], HANDLE_FLAG_INHERIT, 0); | ||
219 | |||
220 | /* Now create the child process */ | ||
221 | ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); | ||
222 | siStartInfo.cb = sizeof(STARTUPINFO); | ||
223 | if ( *mode == 'r' ) { | ||
224 | siStartInfo.hStdInput = (HANDLE)_get_osfhandle(fd0); | ||
225 | siStartInfo.hStdOutput = p->pipe[ic]; | ||
226 | } | ||
227 | else { | ||
228 | siStartInfo.hStdInput = p->pipe[ic]; | ||
229 | siStartInfo.hStdOutput = (HANDLE)_get_osfhandle(fd0); | ||
230 | } | ||
231 | siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); | ||
232 | siStartInfo.wShowWindow = SW_HIDE; | ||
233 | siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; | ||
234 | |||
235 | success = CreateProcess(NULL, | ||
236 | (LPTSTR)cmd, /* command line */ | ||
237 | NULL, /* process security attributes */ | ||
238 | NULL, /* primary thread security attributes */ | ||
239 | TRUE, /* handles are inherited */ | ||
240 | 0, /* creation flags */ | ||
241 | NULL, /* use parent's environment */ | ||
242 | NULL, /* use parent's current directory */ | ||
243 | &siStartInfo, /* STARTUPINFO pointer */ | ||
244 | &p->piProcInfo); /* receives PROCESS_INFORMATION */ | ||
245 | |||
246 | if ( !success ) { | ||
247 | goto finito; | ||
248 | } | ||
249 | |||
250 | /* close child end of pipe */ | ||
251 | CloseHandle(p->pipe[ic]); | ||
252 | p->pipe[ic] = INVALID_HANDLE_VALUE; | ||
253 | |||
254 | if ( *mode == 'r' ) { | ||
255 | fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_RDONLY|_O_BINARY); | ||
256 | } | ||
257 | else { | ||
258 | fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_WRONLY|_O_BINARY); | ||
259 | } | ||
260 | |||
261 | finito: | ||
262 | if ( fd == -1 ) { | ||
263 | if ( p->pipe[0] != INVALID_HANDLE_VALUE ) { | ||
264 | CloseHandle(p->pipe[0]); | ||
265 | } | ||
266 | if ( p->pipe[1] != INVALID_HANDLE_VALUE ) { | ||
267 | CloseHandle(p->pipe[1]); | ||
268 | } | ||
269 | } | ||
270 | else { | ||
271 | p->mode = *mode; | ||
272 | p->fd = fd; | ||
273 | if ( pid ) { | ||
274 | *pid = (pid_t)p->piProcInfo.dwProcessId; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | return fd; | ||
279 | } | ||
280 | |||
281 | int mingw_pclose(FILE *fp) | ||
282 | { | ||
283 | int i, ip, fd; | ||
284 | pipe_data *p = NULL; | ||
285 | DWORD ret; | ||
286 | |||
287 | if ( fp == NULL ) { | ||
288 | return -1; | ||
289 | } | ||
290 | |||
291 | /* find struct containing fd */ | ||
292 | fd = fileno(fp); | ||
293 | for ( i=0; i<num_pipes; ++i ) { | ||
294 | if ( pipes[i].mode && pipes[i].fd == fd ) { | ||
295 | p = pipes+i; | ||
296 | break; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | if ( p == NULL ) { | ||
301 | /* no pipe data, maybe fd isn't a pipe? */ | ||
302 | return -1; | ||
303 | } | ||
304 | |||
305 | fclose(fp); | ||
306 | |||
307 | ip = !(p->mode == 'r'); | ||
308 | CloseHandle(p->pipe[ip]); | ||
309 | |||
310 | ret = WaitForSingleObject(p->piProcInfo.hProcess, INFINITE); | ||
311 | |||
312 | CloseHandle(p->piProcInfo.hProcess); | ||
313 | CloseHandle(p->piProcInfo.hThread); | ||
314 | |||
315 | p->mode = '\0'; | ||
316 | |||
317 | return (ret == WAIT_OBJECT_0) ? 0 : -1; | ||
318 | } | ||