aboutsummaryrefslogtreecommitdiff
path: root/win32/process.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--win32/process.c439
1 files changed, 439 insertions, 0 deletions
diff --git a/win32/process.c b/win32/process.c
new file mode 100644
index 000000000..9a4b05597
--- /dev/null
+++ b/win32/process.c
@@ -0,0 +1,439 @@
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
238static intptr_t
239mingw_spawn_applet(int mode,
240 const char *applet,
241 const char *const *argv,
242 const char *const *envp)
243{
244 char **env = copy_environ(envp);
245 char path[MAX_PATH+20];
246 intptr_t ret;
247
248 sprintf(path, "BUSYBOX_APPLET_NAME=%s", applet);
249 env = env_setenv(env, path);
250 ret = spawnveq(mode, get_busybox_exec_path(), argv, (const char *const *)env);
251 free_environ(env);
252 return ret;
253}
254
255static intptr_t
256mingw_spawn_interpreter(int mode, const char *prog, const char *const *argv, const char *const *envp)
257{
258 intptr_t ret;
259 char **opts;
260 int nopts;
261 const char *interpr = parse_interpreter(prog, &opts, &nopts);
262 const char **new_argv;
263 int argc = 0;
264
265 if (!interpr)
266 return spawnveq(mode, prog, argv, envp);
267
268
269 while (argv[argc])
270 argc++;
271 new_argv = malloc(sizeof(*argv)*(argc+nopts+2));
272 memcpy(new_argv+1, opts, sizeof(*opts)*nopts);
273 memcpy(new_argv+nopts+2, argv+1, sizeof(*argv)*argc);
274 new_argv[nopts+1] = prog; /* pass absolute path */
275
276 if (ENABLE_FEATURE_PREFER_APPLETS && find_applet_by_name(interpr) >= 0) {
277 new_argv[0] = interpr;
278 ret = mingw_spawn_applet(mode, interpr, new_argv, envp);
279 }
280 else {
281 char *path = xstrdup(getenv("PATH"));
282 char *tmp = path;
283 char *iprog = find_executable(interpr, &tmp);
284 free(path);
285 if (!iprog) {
286 free(new_argv);
287 errno = ENOENT;
288 return -1;
289 }
290 new_argv[0] = iprog;
291 ret = spawnveq(mode, iprog, new_argv, envp);
292 free(iprog);
293 }
294
295 free(new_argv);
296 return ret;
297}
298
299static intptr_t
300mingw_spawn_1(int mode, const char *cmd, const char *const *argv, const char *const *envp)
301{
302 intptr_t ret;
303
304 if (ENABLE_FEATURE_PREFER_APPLETS &&
305 find_applet_by_name(cmd) >= 0)
306 return mingw_spawn_applet(mode, cmd, argv, envp);
307 else if (is_absolute_path(cmd))
308 return mingw_spawn_interpreter(mode, cmd, argv, envp);
309 else {
310 char *tmp, *path = getenv("PATH");
311 char *prog;
312
313 if (!path) {
314 errno = ENOENT;
315 return -1;
316 }
317
318 /* executable_exists() does not return new file name */
319 tmp = path = xstrdup(path);
320 prog = find_executable(cmd, &tmp);
321 free(path);
322 if (!prog) {
323 errno = ENOENT;
324 return -1;
325 }
326 ret = mingw_spawn_interpreter(mode, prog, argv, envp);
327 free(prog);
328 }
329 return ret;
330}
331
332pid_t FAST_FUNC
333mingw_spawn(char **argv)
334{
335 intptr_t ret;
336
337 ret = mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)argv,
338 (const char *const *)environ);
339
340 return ret == -1 ? -1 : GetProcessId((HANDLE)ret);
341}
342
343intptr_t FAST_FUNC
344mingw_spawn_proc(char **argv)
345{
346 return mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)argv,
347 (const char *const *)environ);
348}
349
350int
351mingw_execvp(const char *cmd, const char *const *argv)
352{
353 int ret = (int)mingw_spawn_1(P_WAIT, cmd, argv, (const char *const *)environ);
354 if (ret != -1)
355 exit(ret);
356 return ret;
357}
358
359int
360mingw_execve(const char *cmd, const char *const *argv, const char *const *envp)
361{
362 int ret;
363 int mode = P_WAIT;
364
365 if (ENABLE_FEATURE_PREFER_APPLETS &&
366 find_applet_by_name(cmd) >= 0)
367 ret = mingw_spawn_applet(mode, cmd, argv, envp);
368 /*
369 * execve(bb_busybox_exec_path, argv, envp) won't work
370 * because argv[0] will be replaced to bb_busybox_exec_path
371 * by MSVC runtime
372 */
373 else if (argv && cmd != argv[0] && cmd == bb_busybox_exec_path)
374 ret = mingw_spawn_applet(mode, argv[0], argv, envp);
375 else
376 ret = mingw_spawn_interpreter(mode, cmd, argv, envp);
377 if (ret != -1)
378 exit(ret);
379 return ret;
380}
381
382int
383mingw_execv(const char *cmd, const char *const *argv)
384{
385 return mingw_execve(cmd, argv, (const char *const *)environ);
386}
387
388/* POSIX version in libbb/procps.c */
389procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags UNUSED_PARAM)
390{
391 PROCESSENTRY32 pe;
392
393 pe.dwSize = sizeof(pe);
394 if (!sp) {
395 sp = xzalloc(sizeof(struct procps_status_t));
396 sp->snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
397 if (sp->snapshot == INVALID_HANDLE_VALUE) {
398 free(sp);
399 return NULL;
400 }
401 if (!Process32First(sp->snapshot, &pe)) {
402 CloseHandle(sp->snapshot);
403 free(sp);
404 return NULL;
405 }
406 }
407 else {
408 if (!Process32Next(sp->snapshot, &pe)) {
409 CloseHandle(sp->snapshot);
410 free(sp);
411 return NULL;
412 }
413 }
414
415 sp->pid = pe.th32ProcessID;
416 safe_strncpy(sp->comm, pe.szExeFile, COMM_LEN);
417 return sp;
418}
419
420int kill(pid_t pid, int sig)
421{
422 HANDLE h;
423
424 if (pid > 0 && sig == SIGTERM) {
425 if ((h=OpenProcess(PROCESS_TERMINATE, FALSE, pid)) != NULL &&
426 TerminateProcess(h, 0)) {
427 CloseHandle(h);
428 return 0;
429 }
430
431 errno = err_win_to_posix(GetLastError());
432 if (h != NULL)
433 CloseHandle(h);
434 return -1;
435 }
436
437 errno = EINVAL;
438 return -1;
439}