aboutsummaryrefslogtreecommitdiff
path: root/win32/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'win32/process.c')
-rw-r--r--win32/process.c425
1 files changed, 425 insertions, 0 deletions
diff --git a/win32/process.c b/win32/process.c
new file mode 100644
index 000000000..968ea9afd
--- /dev/null
+++ b/win32/process.c
@@ -0,0 +1,425 @@
1#include "libbb.h"
2#include <tlhelp32.h>
3
4int waitpid(pid_t pid, int *status, int options)
5{
6 HANDLE proc;
7 intptr_t ret;
8
9 /* Windows does not understand parent-child */
10 if (pid > 0 && options == 0) {
11 if ( (proc=OpenProcess(SYNCHRONIZE|PROCESS_QUERY_INFORMATION,
12 FALSE, pid)) != NULL ) {
13 ret = _cwait(status, (intptr_t)proc, 0);
14 CloseHandle(proc);
15 return ret == -1 ? -1 : pid;
16 }
17 }
18 errno = EINVAL;
19 return -1;
20}
21
22const char *
23next_path_sep(const char *path)
24{
25 static const char *from = NULL, *to;
26 static int has_semicolon;
27 int len = strlen(path);
28
29 if (!from || !(path >= from && path+len <= to)) {
30 from = path;
31 to = from+len;
32 has_semicolon = strchr(path, ';') != NULL;
33 }
34
35 /* Semicolons take precedence, it's Windows PATH */
36 if (has_semicolon)
37 return strchr(path, ';');
38 /* PATH=C:, not really a separator */
39 return strchr(has_dos_drive_prefix(path) ? path+2 : path, ':');
40}
41
42#define MAX_OPT 10
43
44static const char *
45parse_interpreter(const char *cmd, char ***opts, int *nopts)
46{
47 static char buf[100], *opt[MAX_OPT];
48 char *p, *s, *t;
49 int n, fd;
50
51 *nopts = 0;
52 *opts = opt;
53
54 /* don't even try a .exe */
55 n = strlen(cmd);
56 if (n >= 4 &&
57 (!strcasecmp(cmd+n-4, ".exe") ||
58 !strcasecmp(cmd+n-4, ".com")))
59 return NULL;
60
61 fd = open(cmd, O_RDONLY);
62 if (fd < 0)
63 return NULL;
64 n = read(fd, buf, sizeof(buf)-1);
65 close(fd);
66 if (n < 4) /* at least '#!/x' and not error */
67 return NULL;
68
69 /*
70 * See http://www.in-ulm.de/~mascheck/various/shebang/ for trivia
71 * relating to '#!'.
72 */
73 if (buf[0] != '#' || buf[1] != '!')
74 return NULL;
75 buf[n] = '\0';
76 p = strchr(buf, '\n');
77 if (!p)
78 return NULL;
79 *p = '\0';
80
81 /* remove trailing whitespace */
82 while ( isspace(*--p) ) {
83 *p = '\0';
84 }
85
86 /* skip whitespace after '#!' */
87 for ( s=buf+2; *s && isspace(*s); ++s ) {
88 }
89
90 /* move to end of interpreter path (which may not contain spaces) */
91 for ( ; *s && !isspace(*s); ++s ) {
92 }
93
94 n = 0;
95 if ( *s != '\0' ) {
96 /* there are options */
97 *s++ = '\0';
98
99 while ( (t=strtok(s, " \t")) && n < MAX_OPT ) {
100 s = NULL;
101 opt[n++] = t;
102 }
103 }
104
105 /* find interpreter name */
106 if (!(p = strrchr(buf+2, '/')))
107 return NULL;
108
109 *nopts = n;
110 *opts = opt;
111
112 return p+1;
113}
114
115/*
116 * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
117 * (Parsing C++ Command-Line Arguments)
118 */
119static char *
120quote_arg(const char *arg)
121{
122 int len = 0, n = 0;
123 int force_quotes = 0;
124 char *q, *d;
125 const char *p = arg;
126
127 /* empty arguments must be quoted */
128 if (!*p) {
129 force_quotes = 1;
130 }
131
132 while (*p) {
133 if (isspace(*p)) {
134 /* arguments containing whitespace must be quoted */
135 force_quotes = 1;
136 }
137 else if (*p == '"') {
138 /* double quotes in arguments need to be escaped */
139 n++;
140 }
141 else if (*p == '\\') {
142 /* count contiguous backslashes */
143 int count = 0;
144 while (*p == '\\') {
145 count++;
146 p++;
147 len++;
148 }
149
150 /*
151 * Only escape backslashes before explicit double quotes or
152 * or where the backslashes are at the end of an argument
153 * that is scheduled to be quoted.
154 */
155 if (*p == '"' || (force_quotes && *p == '\0')) {
156 n += count*2 + 1;
157 }
158
159 if (*p == '\0') {
160 break;
161 }
162 continue;
163 }
164 len++;
165 p++;
166 }
167
168 if (!force_quotes && n == 0) {
169 return (char*)arg;
170 }
171
172 /* insert double quotes and backslashes where necessary */
173 d = q = xmalloc(len+n+3);
174 if (force_quotes) {
175 *d++ = '"';
176 }
177
178 while (*arg) {
179 if (*arg == '"') {
180 *d++ = '\\';
181 }
182 else if (*arg == '\\') {
183 int count = 0;
184 while (*arg == '\\') {
185 count++;
186 *d++ = *arg++;
187 }
188
189 if (*arg == '"' || (force_quotes && *arg == '\0')) {
190 while (count-- > 0) {
191 *d++ = '\\';
192 }
193 if (*arg == '"') {
194 *d++ = '\\';
195 }
196 }
197 }
198 if (*arg != '\0') {
199 *d++ = *arg++;
200 }
201 }
202 if (force_quotes) {
203 *d++ = '"';
204 }
205 *d = '\0';
206
207 return q;
208}
209
210static intptr_t
211spawnveq(int mode, const char *path, const char *const *argv, const char *const *env)
212{
213 char **new_argv;
214 int i, argc = 0;
215 intptr_t ret;
216
217 if (!argv) {
218 const char *empty_argv[] = { path, NULL };
219 return spawnve(mode, path, empty_argv, env);
220 }
221
222
223 while (argv[argc])
224 argc++;
225
226 new_argv = malloc(sizeof(*argv)*(argc+1));
227 for (i = 0;i < argc;i++)
228 new_argv[i] = quote_arg(argv[i]);
229 new_argv[argc] = NULL;
230 ret = spawnve(mode, path, (const char *const *)new_argv, env);
231 for (i = 0;i < argc;i++)
232 if (new_argv[i] != argv[i])
233 free(new_argv[i]);
234 free(new_argv);
235 return ret;
236}
237
238#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE
239static intptr_t
240mingw_spawn_applet(int mode,
241 const char *const *argv,
242 const char *const *envp)
243{
244 return spawnveq(mode, bb_busybox_exec_path, argv, envp);
245}
246#endif
247
248static intptr_t
249mingw_spawn_interpreter(int mode, const char *prog, const char *const *argv, const char *const *envp)
250{
251 intptr_t ret;
252 char **opts;
253 int nopts;
254 const char *interpr = parse_interpreter(prog, &opts, &nopts);
255 const char **new_argv;
256 int argc = 0;
257
258 if (!interpr)
259 return spawnveq(mode, prog, argv, envp);
260
261
262 while (argv[argc])
263 argc++;
264 new_argv = malloc(sizeof(*argv)*(argc+nopts+2));
265 memcpy(new_argv+1, opts, sizeof(*opts)*nopts);
266 memcpy(new_argv+nopts+2, argv+1, sizeof(*argv)*argc);
267 new_argv[nopts+1] = prog; /* pass absolute path */
268
269#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE
270 if (find_applet_by_name(interpr) >= 0) {
271 new_argv[0] = interpr;
272 ret = mingw_spawn_applet(mode, new_argv, envp);
273 } else
274#endif
275 {
276 char *path = xstrdup(getenv("PATH"));
277 char *tmp = path;
278 char *iprog = find_executable(interpr, &tmp);
279 free(path);
280 if (!iprog) {
281 free(new_argv);
282 errno = ENOENT;
283 return -1;
284 }
285 new_argv[0] = iprog;
286 ret = spawnveq(mode, iprog, new_argv, envp);
287 free(iprog);
288 }
289
290 free(new_argv);
291 return ret;
292}
293
294static intptr_t
295mingw_spawn_1(int mode, const char *cmd, const char *const *argv, const char *const *envp)
296{
297 intptr_t ret;
298
299#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE
300 if (find_applet_by_name(cmd) >= 0)
301 return mingw_spawn_applet(mode, argv, envp);
302 else
303#endif
304 if (strchr(cmd, '/') || strchr(cmd, '\\'))
305 return mingw_spawn_interpreter(mode, cmd, argv, envp);
306 else {
307 char *tmp, *path = getenv("PATH");
308 char *prog;
309
310 if (!path) {
311 errno = ENOENT;
312 return -1;
313 }
314
315 /* executable_exists() does not return new file name */
316 tmp = path = xstrdup(path);
317 prog = find_executable(cmd, &tmp);
318 free(path);
319 if (!prog) {
320 errno = ENOENT;
321 return -1;
322 }
323 ret = mingw_spawn_interpreter(mode, prog, argv, envp);
324 free(prog);
325 }
326 return ret;
327}
328
329pid_t FAST_FUNC
330mingw_spawn(char **argv)
331{
332 intptr_t ret;
333
334 ret = mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)argv,
335 (const char *const *)environ);
336
337 return ret == -1 ? -1 : GetProcessId((HANDLE)ret);
338}
339
340intptr_t FAST_FUNC
341mingw_spawn_proc(char **argv)
342{
343 return mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)argv,
344 (const char *const *)environ);
345}
346
347int
348mingw_execvp(const char *cmd, const char *const *argv)
349{
350 int ret = (int)mingw_spawn_1(P_WAIT, cmd, argv, (const char *const *)environ);
351 if (ret != -1)
352 exit(ret);
353 return ret;
354}
355
356int
357mingw_execve(const char *cmd, const char *const *argv, const char *const *envp)
358{
359 int ret;
360 int mode = P_WAIT;
361
362 ret = (int)mingw_spawn_interpreter(mode, cmd, argv, envp);
363 if (ret != -1)
364 exit(ret);
365 return ret;
366}
367
368int
369mingw_execv(const char *cmd, const char *const *argv)
370{
371 return mingw_execve(cmd, argv, (const char *const *)environ);
372}
373
374/* POSIX version in libbb/procps.c */
375procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags UNUSED_PARAM)
376{
377 PROCESSENTRY32 pe;
378
379 pe.dwSize = sizeof(pe);
380 if (!sp) {
381 sp = xzalloc(sizeof(struct procps_status_t));
382 sp->snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
383 if (sp->snapshot == INVALID_HANDLE_VALUE) {
384 free(sp);
385 return NULL;
386 }
387 if (!Process32First(sp->snapshot, &pe)) {
388 CloseHandle(sp->snapshot);
389 free(sp);
390 return NULL;
391 }
392 }
393 else {
394 if (!Process32Next(sp->snapshot, &pe)) {
395 CloseHandle(sp->snapshot);
396 free(sp);
397 return NULL;
398 }
399 }
400
401 sp->pid = pe.th32ProcessID;
402 safe_strncpy(sp->comm, pe.szExeFile, COMM_LEN);
403 return sp;
404}
405
406int kill(pid_t pid, int sig)
407{
408 HANDLE h;
409
410 if (pid > 0 && sig == SIGTERM) {
411 if ((h=OpenProcess(PROCESS_TERMINATE, FALSE, pid)) != NULL &&
412 TerminateProcess(h, 0)) {
413 CloseHandle(h);
414 return 0;
415 }
416
417 errno = err_win_to_posix(GetLastError());
418 if (h != NULL)
419 CloseHandle(h);
420 return -1;
421 }
422
423 errno = EINVAL;
424 return -1;
425}