aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2012-04-23 10:14:18 +0100
committerRon Yorston <rmy@pobox.com>2012-04-23 10:14:18 +0100
commitece4cb7f6debdb741b8a43053aeea817b80f49e7 (patch)
treea97498a671ef3ddb5691396ec771cbd0bb2514bf
parent073257d2d34097e4ace7daa5882b090c07d528cc (diff)
downloadbusybox-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.h5
-rw-r--r--win32/Kbuild1
-rw-r--r--win32/env.c4
-rw-r--r--win32/popen.c220
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
142FILE *mingw_popen(const char *cmd, const char *mode);
143int 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
11lib-$(CONFIG_PLATFORM_MINGW32) += regex.o 11lib-$(CONFIG_PLATFORM_MINGW32) += regex.o
12lib-$(CONFIG_WIN32_NET) += net.o 12lib-$(CONFIG_WIN32_NET) += net.o
13lib-$(CONFIG_PLATFORM_MINGW32) += poll.o 13lib-$(CONFIG_PLATFORM_MINGW32) += poll.o
14lib-$(CONFIG_PLATFORM_MINGW32) += popen.o
14lib-$(CONFIG_PLATFORM_MINGW32) += termios.o 15lib-$(CONFIG_PLATFORM_MINGW32) += termios.o
15lib-$(CONFIG_PLATFORM_MINGW32) += uname.o 16lib-$(CONFIG_PLATFORM_MINGW32) += uname.o
16lib-$(CONFIG_PLATFORM_MINGW32) += winansi.o 17lib-$(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
4typedef struct {
5 PROCESS_INFORMATION piProcInfo;
6 HANDLE in[2], out[2], err[2];
7 char mode;
8 FILE *fd;
9} pipe_data;
10
11static pipe_data *pipes = NULL;
12static int num_pipes = 0;
13
14static 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
29FILE *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
149finito:
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
179int 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}