From 701cea96c43d185ebe433df9ecca39ecc9742ef3 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Mar 2018 15:35:24 +0000 Subject: win32: tidy up popen implementation Make mingw_popen_fd sufficiently general that it can be used to implement the other two popen routines. mingw_popen now just creates a command line and passes it to mingw_popen_fd. The one call to mingw_popen2 has been replaced by a call to mingw_popen_fd. --- include/mingw.h | 1 - networking/wget.c | 3 +- win32/popen.c | 281 +++++++++++++++--------------------------------------- 3 files changed, 76 insertions(+), 209 deletions(-) diff --git a/include/mingw.h b/include/mingw.h index e56e8f03d..386540b37 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -111,7 +111,6 @@ int mingw_rename(const char*, const char*); FILE *mingw_popen(const char *cmd, const char *mode); int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid); -int mingw_popen2(const char *cmd, pid_t *pid); int mingw_pclose(FILE *fd); #undef popen #undef pclose diff --git a/networking/wget.c b/networking/wget.c index 776894dca..194bf457a 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -768,7 +768,6 @@ static void spawn_ssl_client(const char *host, int network_fd, int flags) static void spawn_ssl_client(const char *host, int network_fd, int flags) { int fd1; - pid_t pid; char *servername, *p, *cmd; servername = xstrdup(host); @@ -781,7 +780,7 @@ static void spawn_ssl_client(const char *host, int network_fd, int flags) (void *)_get_osfhandle(network_fd), servername, flags & TLSLOOP_EXIT_ON_LOCAL_EOF ? " -e" : ""); - if ( (fd1=mingw_popen2(cmd, &pid)) == -1 ) { + if ( (fd1=mingw_popen_fd(cmd, "b", -1, NULL)) == -1 ) { bb_perror_msg_and_die("can't execute ssl_client"); } diff --git a/win32/popen.c b/win32/popen.c index c075e2144..6fc04e169 100644 --- a/win32/popen.c +++ b/win32/popen.c @@ -12,19 +12,47 @@ typedef struct { static pipe_data *pipes = NULL; static int num_pipes = 0; -static int mingw_pipe(HANDLE *readwrite) +static int mingw_pipe(pipe_data *p, int bidi) { + int ret = 0; 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; + if (!bidi) { + /* pipe[0] is the read handle, pipe[i] the write handle */ + if ( !CreatePipe (&p->pipe[0], &p->pipe[1], &sa, 1 << 13) ) { + return -1; + } + } + else { + char *name; + const int ip = 1; /* index of parent end of pipe */ + const int ic = 0; /* index of child end of pipe */ + + name = xasprintf("\\\\.\\pipe\\bb_pipe.%d.%d", getpid(), + (int)(p-pipes)); + + p->pipe[ip] = CreateNamedPipe(name, + PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE|PIPE_WAIT, + 1, 4096, 4096, 0, &sa); + + p->pipe[ic] = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, &sa, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, + NULL); + if (p->pipe[ip] == INVALID_HANDLE_VALUE || + p->pipe[ic] == INVALID_HANDLE_VALUE) { + ret = -1; + } + + free(name); } - return 0; + return ret; } static pipe_data *find_pipe(void) @@ -56,19 +84,16 @@ static pipe_data *find_pipe(void) p->pipe[0] = INVALID_HANDLE_VALUE; p->pipe[1] = INVALID_HANDLE_VALUE; + p->fd = -1; return p; } FILE *mingw_popen(const char *cmd, const char *mode) { - pipe_data *p; FILE *fptr = NULL; - STARTUPINFO siStartInfo; - int success; int fd; int len, count; - int ip, ic; char *cmd_buff = NULL; const char *s; char *t; @@ -78,11 +103,6 @@ FILE *mingw_popen(const char *cmd, const char *mode) return NULL; } - /* find an unused pipe structure */ - if ( (p=find_pipe()) == NULL ) { - return NULL; - } - /* count double quotes */ count = 0; for ( s=cmd; *s; ++s ) { @@ -117,84 +137,25 @@ FILE *mingw_popen(const char *cmd, const char *mode) *t = '\0'; /* Create the pipe */ - if ( mingw_pipe(p->pipe) == -1 ) { - goto finito; - } - - /* index of parent end of pipe */ - ip = !(*mode == 'r'); - /* index of child end of pipe */ - ic = (*mode == 'r'); - - /* Make the parent end of the pipe non-inheritable */ - SetHandleInformation(p->pipe[ip], HANDLE_FLAG_INHERIT, 0); - - /* Now create the child process */ - ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); - siStartInfo.cb = sizeof(STARTUPINFO); - if ( *mode == 'r' ) { - siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - siStartInfo.hStdOutput = p->pipe[ic]; + if ((fd=mingw_popen_fd(cmd_buff, mode, -1, NULL)) != -1) { + fptr = _fdopen(fd, *mode == 'r' ? "rb" : "wb"); } - else { - siStartInfo.hStdInput = p->pipe[ic]; - siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - } - siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); - siStartInfo.wShowWindow = SW_HIDE; - siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; - - success = CreateProcess(NULL, - (LPTSTR)cmd_buff, /* command line */ - NULL, /* process security attributes */ - NULL, /* primary thread security attributes */ - TRUE, /* handles are inherited */ - 0, /* 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 child end of pipe */ - CloseHandle(p->pipe[ic]); - p->pipe[ic] = INVALID_HANDLE_VALUE; - - if ( *mode == 'r' ) { - fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_RDONLY|_O_BINARY); - fptr = _fdopen(fd, "rb"); - } - else { - fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_WRONLY|_O_BINARY); - fptr = _fdopen(fd, "wb"); - } - -finito: - if ( !fptr ) { - if ( p->pipe[0] != INVALID_HANDLE_VALUE ) { - CloseHandle(p->pipe[0]); - } - if ( p->pipe[1] != INVALID_HANDLE_VALUE ) { - CloseHandle(p->pipe[1]); - } - } - else { - p->mode = *mode; - p->fd = fd; - } free(cmd_buff); return fptr; } /* - * Open a pipe to a command where the file descriptor fd0 is used - * as input to the command (read mode) or as the destination of the - * output from the command (write mode). The pid of the command is - * returned in the variable pid, which can be NULL. + * Open a pipe to a command. + * + * - mode may be "r", "w" or "b" for read-only, write-only or + * bidirectional (from the perspective of the parent). + * - if fd0 is a valid file descriptor it's used as input to the + * command ("r") or as the destination of the output from the + * command ("w"). Otherwise (and if not "b") use stdin or stdout. + * - the pid of the command is returned in the variable pid, which + * can be NULL if the pid is not required. */ int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid) { @@ -202,110 +163,29 @@ int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid) STARTUPINFO siStartInfo; int success; int fd = -1; - int ip, ic; + int ip, ic, flags; - if ( cmd == NULL || *cmd == '\0' || mode == NULL || - (*mode != 'r' && *mode != 'w') ) { + if ( cmd == NULL || *cmd == '\0' || mode == NULL ) { return -1; } - /* find an unused pipe structure */ - if ( (p=find_pipe()) == NULL ) { - return -1; - } - - /* Create the pipe */ - if ( mingw_pipe(p->pipe) == -1 ) { - goto finito; - } - - /* index of parent end of pipe */ - ip = !(*mode == 'r'); - /* index of child end of pipe */ - ic = (*mode == 'r'); - - /* Make the parent end of the pipe non-inheritable */ - SetHandleInformation(p->pipe[ip], HANDLE_FLAG_INHERIT, 0); - - /* Now create the child process */ - ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); - siStartInfo.cb = sizeof(STARTUPINFO); - if ( *mode == 'r' ) { - siStartInfo.hStdInput = (HANDLE)_get_osfhandle(fd0); - siStartInfo.hStdOutput = p->pipe[ic]; - } - else { - siStartInfo.hStdInput = p->pipe[ic]; - siStartInfo.hStdOutput = (HANDLE)_get_osfhandle(fd0); - } - siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); - siStartInfo.wShowWindow = SW_HIDE; - siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; - - success = CreateProcess(NULL, - (LPTSTR)cmd, /* command line */ - NULL, /* process security attributes */ - NULL, /* primary thread security attributes */ - TRUE, /* handles are inherited */ - 0, /* 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 child end of pipe */ - CloseHandle(p->pipe[ic]); - p->pipe[ic] = INVALID_HANDLE_VALUE; - - if ( *mode == 'r' ) { - fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_RDONLY|_O_BINARY); - } - else { - fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_WRONLY|_O_BINARY); - } - -finito: - if ( fd == -1 ) { - if ( p->pipe[0] != INVALID_HANDLE_VALUE ) { - CloseHandle(p->pipe[0]); - } - if ( p->pipe[1] != INVALID_HANDLE_VALUE ) { - CloseHandle(p->pipe[1]); - } - } - else { - p->mode = *mode; - p->fd = fd; - if ( pid ) { - *pid = (pid_t)p->piProcInfo.dwProcessId; - } - } - - return fd; -} - -/* - * Open a bidirectional pipe to a command. The pid of the command is - * returned in the variable pid, which can be NULL. - */ -int mingw_popen2(const char *cmd, pid_t *pid) -{ - pipe_data *p; - char *name = NULL; - SECURITY_ATTRIBUTES sa; - STARTUPINFO siStartInfo; - int success; - int fd = -1; - const int ip = 1; /* index of parent end of pipe */ - const int ic = 0; /* index of child end of pipe */ - - if ( cmd == NULL || *cmd == '\0' ) { + switch (*mode) { + case 'r': + ip = 0; + flags = _O_RDONLY|_O_BINARY; + break; + case 'w': + ip = 1; + flags = _O_WRONLY|_O_BINARY; + break; + case 'b': + ip = 1; + flags = _O_RDWR|_O_BINARY; + break; + default: return -1; } + ic = !ip; /* find an unused pipe structure */ if ( (p=find_pipe()) == NULL ) { @@ -313,26 +193,7 @@ int mingw_popen2(const char *cmd, pid_t *pid) } /* Create the pipe */ - name = xasprintf("\\\\.\\pipe\\bb_pipe.%d.%d", getpid(), (int)(p-pipes)); - - sa.nLength = sizeof(sa); /* Length in bytes */ - sa.bInheritHandle = 1; /* the child must inherit these handles */ - sa.lpSecurityDescriptor = NULL; - - p->pipe[ip] = CreateNamedPipe(name, - PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE|PIPE_WAIT, - 1, 4096, 4096, 0, &sa); - if (p->pipe[ip] == INVALID_HANDLE_VALUE) { - goto finito; - } - - /* Connect to the pipe */ - p->pipe[ic] = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, &sa, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, - NULL); - if (p->pipe[ic] == INVALID_HANDLE_VALUE) { + if ( mingw_pipe(p, *mode == 'b') == -1 ) { goto finito; } @@ -342,10 +203,20 @@ int mingw_popen2(const char *cmd, pid_t *pid) /* Now create the child process */ ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); - siStartInfo.wShowWindow = SW_HIDE; + /* default settings for a bidirectional pipe */ siStartInfo.hStdInput = p->pipe[ic]; siStartInfo.hStdOutput = p->pipe[ic]; + /* override for read-only or write-only */ + if ( *mode == 'r' ) { + siStartInfo.hStdInput = fd0 >= 0 ? (HANDLE)_get_osfhandle(fd0) : + GetStdHandle(STD_INPUT_HANDLE); + } + else if ( *mode == 'w' ) { + siStartInfo.hStdOutput = fd0 >= 0 ? (HANDLE)_get_osfhandle(fd0) : + GetStdHandle(STD_OUTPUT_HANDLE); + } siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + siStartInfo.wShowWindow = SW_HIDE; siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; success = CreateProcess(NULL, @@ -367,12 +238,10 @@ int mingw_popen2(const char *cmd, pid_t *pid) CloseHandle(p->pipe[ic]); p->pipe[ic] = INVALID_HANDLE_VALUE; - fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_RDWR|_O_BINARY); + fd = _open_osfhandle((intptr_t)p->pipe[ip], flags); finito: - free(name); if ( fd == -1 ) { - errno = err_win_to_posix(GetLastError()); if ( p->pipe[0] != INVALID_HANDLE_VALUE ) { CloseHandle(p->pipe[0]); } @@ -381,7 +250,7 @@ finito: } } else { - p->mode = 'r'; + p->mode = *mode; p->fd = fd; if ( pid ) { *pid = (pid_t)p->piProcInfo.dwProcessId; -- cgit v1.2.3-55-g6feb