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