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 | } | ||
