From ece4cb7f6debdb741b8a43053aeea817b80f49e7 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 23 Apr 2012 10:14:18 +0100 Subject: win32: add popen implementation that uses shell --- include/mingw.h | 5 ++ win32/Kbuild | 1 + win32/env.c | 4 +- win32/popen.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 win32/popen.c 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*); #define fopen mingw_fopen #define rename mingw_rename +FILE *mingw_popen(const char *cmd, const char *mode); +int mingw_pclose(FILE *fd); +#define popen mingw_popen +#define pclose mingw_pclose + #define setlinebuf(fd) setvbuf(fd, (char *) NULL, _IOLBF, 0) /* 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 lib-$(CONFIG_PLATFORM_MINGW32) += regex.o lib-$(CONFIG_WIN32_NET) += net.o lib-$(CONFIG_PLATFORM_MINGW32) += poll.o +lib-$(CONFIG_PLATFORM_MINGW32) += popen.o lib-$(CONFIG_PLATFORM_MINGW32) += termios.o lib-$(CONFIG_PLATFORM_MINGW32) += uname.o 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) free(env[i]); if (*eq) env[i] = xstrdup(name); - else + else { for (; env[i]; i++) env[i] = env[i+1]; + SetEnvironmentVariable(name, NULL); + } } return env; } 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 @@ +#include +#include "libbb.h" + +typedef struct { + PROCESS_INFORMATION piProcInfo; + HANDLE in[2], out[2], err[2]; + char mode; + FILE *fd; +} pipe_data; + +static pipe_data *pipes = NULL; +static int num_pipes = 0; + +static int mingw_pipe(HANDLE *readwrite) +{ + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof(sa); /* Length in bytes */ + sa.bInheritHandle = 1; /* the child must inherit these handles */ + sa.lpSecurityDescriptor = NULL; + + if ( !CreatePipe (&readwrite[0], &readwrite[1], &sa, 1 << 13) ) { + return -1; + } + + return 0; +} + +FILE *mingw_popen(const char *cmd, const char *mode) +{ + int i; + pipe_data *p = NULL; + FILE *fptr = NULL; + STARTUPINFO siStartInfo; + int success; + int fd; + int len, count; + char *cmd_buff = NULL; + const char *s; + char *t; + + if ( cmd == NULL || *cmd == '\0' || mode == NULL || + (*mode != 'r' && *mode != 'w') ) { + return NULL; + } + + /* find an unused pipe structure */ + for ( i=0; iin[0] = INVALID_HANDLE_VALUE; + p->in[1] = INVALID_HANDLE_VALUE; + p->out[0] = INVALID_HANDLE_VALUE; + p->out[1] = INVALID_HANDLE_VALUE; + p->err[0] = INVALID_HANDLE_VALUE; + p->err[1] = INVALID_HANDLE_VALUE; + + /* Create the Pipes... */ + if ( mingw_pipe(p->in) == -1 || + mingw_pipe(p->out) == -1 || + mingw_pipe(p->err) == -1) { + goto finito; + } + + /* Make the parent ends of the pipes non-inheritable */ + SetHandleInformation(p->in[1], HANDLE_FLAG_INHERIT, 0); + SetHandleInformation(p->out[0], HANDLE_FLAG_INHERIT, 0); + SetHandleInformation(p->err[0], HANDLE_FLAG_INHERIT, 0); + + /* Now create the child process */ + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdInput = p->in[0]; + siStartInfo.hStdOutput = p->out[1]; + siStartInfo.hStdError = p->err[1]; + siStartInfo.dwFlags = STARTF_USESTDHANDLES; + + success = CreateProcess(NULL, + (LPTSTR)cmd_buff, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attributes */ + TRUE, /* handles are inherited */ + CREATE_NO_WINDOW, /* creation flags */ + NULL, /* use parent's environment */ + NULL, /* use parent's current directory */ + &siStartInfo, /* STARTUPINFO pointer */ + &p->piProcInfo); /* receives PROCESS_INFORMATION */ + + if ( !success ) { + goto finito; + } + + /* Close the child ends of the pipes */ + CloseHandle(p->in[0]); p->in[0] = INVALID_HANDLE_VALUE; + CloseHandle(p->out[1]); p->out[1] = INVALID_HANDLE_VALUE; + CloseHandle(p->err[1]); p->err[1] = INVALID_HANDLE_VALUE; + + if ( *mode == 'r' ) { + fd = _open_osfhandle((long)p->out[0], _O_RDONLY|_O_BINARY); + fptr = _fdopen(fd, "rb"); + } + else { + fd = _open_osfhandle((long)p->in[1], _O_WRONLY|_O_BINARY); + fptr = _fdopen(fd, "wb"); + } + +finito: + if ( !fptr ) { + if ( p->in[0] != INVALID_HANDLE_VALUE ) { + CloseHandle(p->in[0]); + } + if ( p->in[1] != INVALID_HANDLE_VALUE ) { + CloseHandle(p->in[1]); + } + if ( p->out[0] != INVALID_HANDLE_VALUE ) { + CloseHandle(p->out[0]); + } + if ( p->out[1] != INVALID_HANDLE_VALUE ) { + CloseHandle(p->out[1]); + } + if ( p->err[0] != INVALID_HANDLE_VALUE ) { + CloseHandle(p->err[0]); + } + if ( p->err[1] != INVALID_HANDLE_VALUE ) { + CloseHandle(p->err[1]); + } + } + else { + p->mode = *mode; + } + free(cmd_buff); + + p->fd = fptr; + return fptr; +} + +int mingw_pclose(FILE *fd) +{ + int i; + pipe_data *p = NULL; + DWORD ret; + + if ( fd == NULL ) { + return -1; + } + + /* find struct containing fd */ + for ( i=0; ierr[0]); + if ( p->mode == 'r' ) { + CloseHandle(p->in[1]); + } + else { + CloseHandle(p->out[0]); + } + + ret = WaitForSingleObject(p->piProcInfo.hProcess, INFINITE); + + CloseHandle(p->piProcInfo.hProcess); + CloseHandle(p->piProcInfo.hThread); + + p->mode = '\0'; + + return (ret == WAIT_OBJECT_0) ? 0 : -1; +} -- cgit v1.2.3-55-g6feb