diff options
author | Ron Yorston <rmy@pobox.com> | 2012-04-23 10:14:18 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2012-04-23 10:14:18 +0100 |
commit | ece4cb7f6debdb741b8a43053aeea817b80f49e7 (patch) | |
tree | a97498a671ef3ddb5691396ec771cbd0bb2514bf | |
parent | 073257d2d34097e4ace7daa5882b090c07d528cc (diff) | |
download | busybox-w32-ece4cb7f6debdb741b8a43053aeea817b80f49e7.tar.gz busybox-w32-ece4cb7f6debdb741b8a43053aeea817b80f49e7.tar.bz2 busybox-w32-ece4cb7f6debdb741b8a43053aeea817b80f49e7.zip |
win32: add popen implementation that uses shell
-rw-r--r-- | include/mingw.h | 5 | ||||
-rw-r--r-- | win32/Kbuild | 1 | ||||
-rw-r--r-- | win32/env.c | 4 | ||||
-rw-r--r-- | win32/popen.c | 220 |
4 files changed, 229 insertions, 1 deletions
diff --git a/include/mingw.h b/include/mingw.h index 910eff412..b81a6e180 100644 --- a/include/mingw.h +++ b/include/mingw.h | |||
@@ -139,6 +139,11 @@ int mingw_rename(const char*, const char*); | |||
139 | #define fopen mingw_fopen | 139 | #define fopen mingw_fopen |
140 | #define rename mingw_rename | 140 | #define rename mingw_rename |
141 | 141 | ||
142 | FILE *mingw_popen(const char *cmd, const char *mode); | ||
143 | int mingw_pclose(FILE *fd); | ||
144 | #define popen mingw_popen | ||
145 | #define pclose mingw_pclose | ||
146 | |||
142 | #define setlinebuf(fd) setvbuf(fd, (char *) NULL, _IOLBF, 0) | 147 | #define setlinebuf(fd) setvbuf(fd, (char *) NULL, _IOLBF, 0) |
143 | 148 | ||
144 | /* | 149 | /* |
diff --git a/win32/Kbuild b/win32/Kbuild index 3b06e83a7..42df86692 100644 --- a/win32/Kbuild +++ b/win32/Kbuild | |||
@@ -11,6 +11,7 @@ lib-$(CONFIG_PLATFORM_MINGW32) += process.o | |||
11 | lib-$(CONFIG_PLATFORM_MINGW32) += regex.o | 11 | lib-$(CONFIG_PLATFORM_MINGW32) += regex.o |
12 | lib-$(CONFIG_WIN32_NET) += net.o | 12 | lib-$(CONFIG_WIN32_NET) += net.o |
13 | lib-$(CONFIG_PLATFORM_MINGW32) += poll.o | 13 | lib-$(CONFIG_PLATFORM_MINGW32) += poll.o |
14 | lib-$(CONFIG_PLATFORM_MINGW32) += popen.o | ||
14 | lib-$(CONFIG_PLATFORM_MINGW32) += termios.o | 15 | lib-$(CONFIG_PLATFORM_MINGW32) += termios.o |
15 | lib-$(CONFIG_PLATFORM_MINGW32) += uname.o | 16 | lib-$(CONFIG_PLATFORM_MINGW32) += uname.o |
16 | lib-$(CONFIG_PLATFORM_MINGW32) += winansi.o | 17 | lib-$(CONFIG_PLATFORM_MINGW32) += winansi.o |
diff --git a/win32/env.c b/win32/env.c index 21b5f3d2f..f8d231a8f 100644 --- a/win32/env.c +++ b/win32/env.c | |||
@@ -101,9 +101,11 @@ char **env_setenv(char **env, const char *name) | |||
101 | free(env[i]); | 101 | free(env[i]); |
102 | if (*eq) | 102 | if (*eq) |
103 | env[i] = xstrdup(name); | 103 | env[i] = xstrdup(name); |
104 | else | 104 | else { |
105 | for (; env[i]; i++) | 105 | for (; env[i]; i++) |
106 | env[i] = env[i+1]; | 106 | env[i] = env[i+1]; |
107 | SetEnvironmentVariable(name, NULL); | ||
108 | } | ||
107 | } | 109 | } |
108 | return env; | 110 | return env; |
109 | } | 111 | } |
diff --git a/win32/popen.c b/win32/popen.c new file mode 100644 index 000000000..b75ddbcb6 --- /dev/null +++ b/win32/popen.c | |||
@@ -0,0 +1,220 @@ | |||
1 | #include <fcntl.h> | ||
2 | #include "libbb.h" | ||
3 | |||
4 | typedef struct { | ||
5 | PROCESS_INFORMATION piProcInfo; | ||
6 | HANDLE in[2], out[2], err[2]; | ||
7 | char mode; | ||
8 | FILE *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 | FILE *mingw_popen(const char *cmd, const char *mode) | ||
30 | { | ||
31 | int i; | ||
32 | pipe_data *p = NULL; | ||
33 | FILE *fptr = NULL; | ||
34 | STARTUPINFO siStartInfo; | ||
35 | int success; | ||
36 | int fd; | ||
37 | int len, count; | ||
38 | char *cmd_buff = NULL; | ||
39 | const char *s; | ||
40 | char *t; | ||
41 | |||
42 | if ( cmd == NULL || *cmd == '\0' || mode == NULL || | ||
43 | (*mode != 'r' && *mode != 'w') ) { | ||
44 | return NULL; | ||
45 | } | ||
46 | |||
47 | /* find an unused pipe structure */ | ||
48 | for ( i=0; i<num_pipes; ++i ) { | ||
49 | if ( pipes[i].mode == '\0' ) { | ||
50 | p = pipes+i; | ||
51 | break; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | if ( p == NULL ) { | ||
56 | /* need to extend array */ | ||
57 | if ( (p=realloc(pipes, sizeof(pipe_data)*(num_pipes+10))) == NULL ) { | ||
58 | return NULL; | ||
59 | } | ||
60 | |||
61 | pipes = p; | ||
62 | for ( i=0; i<10; ++i ) { | ||
63 | memset(pipes+num_pipes+i, 0, sizeof(pipe_data)); | ||
64 | } | ||
65 | p = pipes + num_pipes; | ||
66 | num_pipes += 10; | ||
67 | } | ||
68 | |||
69 | /* count double quotes */ | ||
70 | count = 0; | ||
71 | for ( s=cmd; *s; ++s ) { | ||
72 | if ( *s == '"' ) { | ||
73 | ++count; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | len = strlen(cmd) + 10 + count; | ||
78 | if ( (cmd_buff=malloc(len)) == NULL ) { | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | /* escape double quotes */ | ||
83 | strcpy(cmd_buff, "sh -c \""); | ||
84 | for ( s=cmd,t=cmd_buff+strlen(cmd_buff); *s; ++s ) { | ||
85 | if ( *s == '"' ) { | ||
86 | *t++ = '\\'; | ||
87 | } | ||
88 | *t++ = *s; | ||
89 | } | ||
90 | *t++ = '"'; | ||
91 | *t = '\0'; | ||
92 | |||
93 | p->in[0] = INVALID_HANDLE_VALUE; | ||
94 | p->in[1] = INVALID_HANDLE_VALUE; | ||
95 | p->out[0] = INVALID_HANDLE_VALUE; | ||
96 | p->out[1] = INVALID_HANDLE_VALUE; | ||
97 | p->err[0] = INVALID_HANDLE_VALUE; | ||
98 | p->err[1] = INVALID_HANDLE_VALUE; | ||
99 | |||
100 | /* Create the Pipes... */ | ||
101 | if ( mingw_pipe(p->in) == -1 || | ||
102 | mingw_pipe(p->out) == -1 || | ||
103 | mingw_pipe(p->err) == -1) { | ||
104 | goto finito; | ||
105 | } | ||
106 | |||
107 | /* Make the parent ends of the pipes non-inheritable */ | ||
108 | SetHandleInformation(p->in[1], HANDLE_FLAG_INHERIT, 0); | ||
109 | SetHandleInformation(p->out[0], HANDLE_FLAG_INHERIT, 0); | ||
110 | SetHandleInformation(p->err[0], HANDLE_FLAG_INHERIT, 0); | ||
111 | |||
112 | /* Now create the child process */ | ||
113 | ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); | ||
114 | siStartInfo.cb = sizeof(STARTUPINFO); | ||
115 | siStartInfo.hStdInput = p->in[0]; | ||
116 | siStartInfo.hStdOutput = p->out[1]; | ||
117 | siStartInfo.hStdError = p->err[1]; | ||
118 | siStartInfo.dwFlags = STARTF_USESTDHANDLES; | ||
119 | |||
120 | success = CreateProcess(NULL, | ||
121 | (LPTSTR)cmd_buff, /* command line */ | ||
122 | NULL, /* process security attributes */ | ||
123 | NULL, /* primary thread security attributes */ | ||
124 | TRUE, /* handles are inherited */ | ||
125 | CREATE_NO_WINDOW, /* creation flags */ | ||
126 | NULL, /* use parent's environment */ | ||
127 | NULL, /* use parent's current directory */ | ||
128 | &siStartInfo, /* STARTUPINFO pointer */ | ||
129 | &p->piProcInfo); /* receives PROCESS_INFORMATION */ | ||
130 | |||
131 | if ( !success ) { | ||
132 | goto finito; | ||
133 | } | ||
134 | |||
135 | /* Close the child ends of the pipes */ | ||
136 | CloseHandle(p->in[0]); p->in[0] = INVALID_HANDLE_VALUE; | ||
137 | CloseHandle(p->out[1]); p->out[1] = INVALID_HANDLE_VALUE; | ||
138 | CloseHandle(p->err[1]); p->err[1] = INVALID_HANDLE_VALUE; | ||
139 | |||
140 | if ( *mode == 'r' ) { | ||
141 | fd = _open_osfhandle((long)p->out[0], _O_RDONLY|_O_BINARY); | ||
142 | fptr = _fdopen(fd, "rb"); | ||
143 | } | ||
144 | else { | ||
145 | fd = _open_osfhandle((long)p->in[1], _O_WRONLY|_O_BINARY); | ||
146 | fptr = _fdopen(fd, "wb"); | ||
147 | } | ||
148 | |||
149 | finito: | ||
150 | if ( !fptr ) { | ||
151 | if ( p->in[0] != INVALID_HANDLE_VALUE ) { | ||
152 | CloseHandle(p->in[0]); | ||
153 | } | ||
154 | if ( p->in[1] != INVALID_HANDLE_VALUE ) { | ||
155 | CloseHandle(p->in[1]); | ||
156 | } | ||
157 | if ( p->out[0] != INVALID_HANDLE_VALUE ) { | ||
158 | CloseHandle(p->out[0]); | ||
159 | } | ||
160 | if ( p->out[1] != INVALID_HANDLE_VALUE ) { | ||
161 | CloseHandle(p->out[1]); | ||
162 | } | ||
163 | if ( p->err[0] != INVALID_HANDLE_VALUE ) { | ||
164 | CloseHandle(p->err[0]); | ||
165 | } | ||
166 | if ( p->err[1] != INVALID_HANDLE_VALUE ) { | ||
167 | CloseHandle(p->err[1]); | ||
168 | } | ||
169 | } | ||
170 | else { | ||
171 | p->mode = *mode; | ||
172 | } | ||
173 | free(cmd_buff); | ||
174 | |||
175 | p->fd = fptr; | ||
176 | return fptr; | ||
177 | } | ||
178 | |||
179 | int mingw_pclose(FILE *fd) | ||
180 | { | ||
181 | int i; | ||
182 | pipe_data *p = NULL; | ||
183 | DWORD ret; | ||
184 | |||
185 | if ( fd == NULL ) { | ||
186 | return -1; | ||
187 | } | ||
188 | |||
189 | /* find struct containing fd */ | ||
190 | for ( i=0; i<num_pipes; ++i ) { | ||
191 | if ( pipes[i].fd == fd ) { | ||
192 | p = pipes+i; | ||
193 | break; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | if ( p == NULL ) { | ||
198 | /* no pipe data, maybe fd isn't a pipe? */ | ||
199 | return -1; | ||
200 | } | ||
201 | |||
202 | fclose(fd); | ||
203 | |||
204 | CloseHandle(p->err[0]); | ||
205 | if ( p->mode == 'r' ) { | ||
206 | CloseHandle(p->in[1]); | ||
207 | } | ||
208 | else { | ||
209 | CloseHandle(p->out[0]); | ||
210 | } | ||
211 | |||
212 | ret = WaitForSingleObject(p->piProcInfo.hProcess, INFINITE); | ||
213 | |||
214 | CloseHandle(p->piProcInfo.hProcess); | ||
215 | CloseHandle(p->piProcInfo.hThread); | ||
216 | |||
217 | p->mode = '\0'; | ||
218 | |||
219 | return (ret == WAIT_OBJECT_0) ? 0 : -1; | ||
220 | } | ||