summaryrefslogtreecommitdiff
path: root/win32/popen.c
diff options
context:
space:
mode:
Diffstat (limited to 'win32/popen.c')
-rw-r--r--win32/popen.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/win32/popen.c b/win32/popen.c
new file mode 100644
index 000000000..a7b2c7ec9
--- /dev/null
+++ b/win32/popen.c
@@ -0,0 +1,208 @@
1#include <fcntl.h>
2#include "libbb.h"
3
4typedef struct {
5 PROCESS_INFORMATION piProcInfo;
6 HANDLE pipe[2];
7 char mode;
8 int 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 int ip, ic;
39 char *cmd_buff = NULL;
40 const char *s;
41 char *t;
42
43 if ( cmd == NULL || *cmd == '\0' || mode == NULL ||
44 (*mode != 'r' && *mode != 'w') ) {
45 return NULL;
46 }
47
48 /* find an unused pipe structure */
49 for ( i=0; i<num_pipes; ++i ) {
50 if ( pipes[i].mode == '\0' ) {
51 p = pipes+i;
52 break;
53 }
54 }
55
56 if ( p == NULL ) {
57 /* need to extend array */
58 if ( (p=realloc(pipes, sizeof(pipe_data)*(num_pipes+10))) == NULL ) {
59 return NULL;
60 }
61
62 pipes = p;
63 for ( i=0; i<10; ++i ) {
64 memset(pipes+num_pipes+i, 0, sizeof(pipe_data));
65 }
66 p = pipes + num_pipes;
67 num_pipes += 10;
68 }
69
70 /* count double quotes */
71 count = 0;
72 for ( s=cmd; *s; ++s ) {
73 if ( *s == '"' ) {
74 ++count;
75 }
76 }
77
78 len = strlen(cmd) + 10 + count;
79 if ( (cmd_buff=malloc(len)) == NULL ) {
80 return NULL;
81 }
82
83 /* escape double quotes */
84 strcpy(cmd_buff, "sh -c \"");
85 for ( s=cmd,t=cmd_buff+strlen(cmd_buff); *s; ++s ) {
86 if ( *s == '"' ) {
87 *t++ = '\\';
88 }
89 *t++ = *s;
90 }
91 *t++ = '"';
92 *t = '\0';
93
94 p->pipe[0] = INVALID_HANDLE_VALUE;
95 p->pipe[1] = INVALID_HANDLE_VALUE;
96
97 /* Create the pipe */
98 if ( mingw_pipe(p->pipe) == -1 ) {
99 goto finito;
100 }
101
102 /* index of parent end of pipe */
103 ip = !(*mode == 'r');
104 /* index of child end of pipe */
105 ic = (*mode == 'r');
106
107 /* Make the parent end of the pipe non-inheritable */
108 SetHandleInformation(p->pipe[ip], HANDLE_FLAG_INHERIT, 0);
109
110 /* Now create the child process */
111 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
112 siStartInfo.cb = sizeof(STARTUPINFO);
113 if ( *mode == 'r' ) {
114 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
115 siStartInfo.hStdOutput = p->pipe[ic];
116 }
117 else {
118 siStartInfo.hStdInput = p->pipe[ic];
119 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
120 }
121 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
122 siStartInfo.wShowWindow = SW_HIDE;
123 siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
124
125 success = CreateProcess(NULL,
126 (LPTSTR)cmd_buff, /* command line */
127 NULL, /* process security attributes */
128 NULL, /* primary thread security attributes */
129 TRUE, /* handles are inherited */
130 0, /* creation flags */
131 NULL, /* use parent's environment */
132 NULL, /* use parent's current directory */
133 &siStartInfo, /* STARTUPINFO pointer */
134 &p->piProcInfo); /* receives PROCESS_INFORMATION */
135
136 if ( !success ) {
137 goto finito;
138 }
139
140 /* close child end of pipe */
141 CloseHandle(p->pipe[ic]);
142 p->pipe[ic] = INVALID_HANDLE_VALUE;
143
144 if ( *mode == 'r' ) {
145 fd = _open_osfhandle((long)p->pipe[ip], _O_RDONLY|_O_BINARY);
146 fptr = _fdopen(fd, "rb");
147 }
148 else {
149 fd = _open_osfhandle((long)p->pipe[ip], _O_WRONLY|_O_BINARY);
150 fptr = _fdopen(fd, "wb");
151 }
152
153finito:
154 if ( !fptr ) {
155 if ( p->pipe[0] != INVALID_HANDLE_VALUE ) {
156 CloseHandle(p->pipe[0]);
157 }
158 if ( p->pipe[1] != INVALID_HANDLE_VALUE ) {
159 CloseHandle(p->pipe[1]);
160 }
161 }
162 else {
163 p->mode = *mode;
164 p->fd = fd;
165 }
166 free(cmd_buff);
167
168 return fptr;
169}
170
171int mingw_pclose(FILE *fp)
172{
173 int i, ip, fd;
174 pipe_data *p = NULL;
175 DWORD ret;
176
177 if ( fp == NULL ) {
178 return -1;
179 }
180
181 /* find struct containing fd */
182 fd = fileno(fp);
183 for ( i=0; i<num_pipes; ++i ) {
184 if ( pipes[i].mode && pipes[i].fd == fd ) {
185 p = pipes+i;
186 break;
187 }
188 }
189
190 if ( p == NULL ) {
191 /* no pipe data, maybe fd isn't a pipe? */
192 return -1;
193 }
194
195 fclose(fp);
196
197 ip = !(p->mode == 'r');
198 CloseHandle(p->pipe[ip]);
199
200 ret = WaitForSingleObject(p->piProcInfo.hProcess, INFINITE);
201
202 CloseHandle(p->piProcInfo.hProcess);
203 CloseHandle(p->piProcInfo.hThread);
204
205 p->mode = '\0';
206
207 return (ret == WAIT_OBJECT_0) ? 0 : -1;
208}