diff options
Diffstat (limited to 'win32/popen.c')
-rw-r--r-- | win32/popen.c | 208 |
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 | |||
4 | typedef struct { | ||
5 | PROCESS_INFORMATION piProcInfo; | ||
6 | HANDLE pipe[2]; | ||
7 | char mode; | ||
8 | int 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 | 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 | |||
153 | finito: | ||
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 | |||
171 | int 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 | } | ||