aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-04-14 02:17:06 +0200
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-04-20 19:14:11 +0200
commite8f92b7bdbc1f36e2dc76aae5c3431087c6ca10c (patch)
tree415e57b4f46ee6df6d9f3818ad60fda3fc2bdbac
parent4b393c73cbfd40c40dc40e609cf248883ce52573 (diff)
downloadbusybox-w32-e8f92b7bdbc1f36e2dc76aae5c3431087c6ca10c.tar.gz
busybox-w32-e8f92b7bdbc1f36e2dc76aae5c3431087c6ca10c.tar.bz2
busybox-w32-e8f92b7bdbc1f36e2dc76aae5c3431087c6ca10c.zip
win32: add shell script and internal applet execution to spawn* and exec*
Most of this was extracted from commit e56b799d6ad8afba4168fffa7218d44c041a72d2 in Git repository. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
-rw-r--r--win32/process.c347
1 files changed, 347 insertions, 0 deletions
diff --git a/win32/process.c b/win32/process.c
index 77d19fb9a..c97474fb9 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -8,3 +8,350 @@ int waitpid(pid_t pid, int *status, unsigned options)
8 errno = EINVAL; 8 errno = EINVAL;
9 return -1; 9 return -1;
10} 10}
11
12/*
13 * Splits the PATH into parts.
14 */
15static char **
16get_path_split(void)
17{
18 char *p, **path, *envpath = getenv("PATH");
19 int i, n = 0;
20
21 if (!envpath || !*envpath)
22 return NULL;
23
24 envpath = xstrdup(envpath);
25 p = envpath;
26 while (p) {
27 char *dir = p;
28 p = strchr(p, ';');
29 if (p) *p++ = '\0';
30 if (*dir) { /* not earlier, catches series of ; */
31 ++n;
32 }
33 }
34 if (!n)
35 return NULL;
36
37 path = xmalloc((n+1)*sizeof(char*));
38 p = envpath;
39 i = 0;
40 do {
41 if (*p)
42 path[i++] = xstrdup(p);
43 p = p+strlen(p)+1;
44 } while (i < n);
45 path[i] = NULL;
46
47 free(envpath);
48
49 return path;
50}
51
52static void
53free_path_split(char **path)
54{
55 if (path) {
56 char **p = path;
57
58 while (*p)
59 free(*p++);
60 free(path);
61 }
62}
63
64/*
65 * exe_only means that we only want to detect .exe files, but not scripts
66 * (which do not have an extension)
67 */
68static char *
69lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
70{
71 char path[MAX_PATH];
72 snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
73
74 if (!isexe && access(path, F_OK) == 0)
75 return xstrdup(path);
76 path[strlen(path)-4] = '\0';
77 if ((!exe_only || isexe) && access(path, F_OK) == 0)
78 if (!(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY))
79 return xstrdup(path);
80 return NULL;
81}
82
83/*
84 * Determines the absolute path of cmd using the the split path in path.
85 * If cmd contains a slash or backslash, no lookup is performed.
86 */
87static char *
88path_lookup(const char *cmd, char **path, int exe_only)
89{
90 char *prog = NULL;
91 int len = strlen(cmd);
92 int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
93
94 if (strchr(cmd, '/') || strchr(cmd, '\\')) {
95 if (!isexe) {
96 char path_exe[MAX_PATH];
97 sprintf(path_exe, "%s.exe", cmd);
98 if (!access(path_exe, F_OK))
99 return xstrdup(path_exe);
100 }
101 prog = xstrdup(cmd);
102 }
103
104 while (!prog && *path)
105 prog = lookup_prog(*path++, cmd, isexe, exe_only);
106
107 return prog;
108}
109
110static const char *
111parse_interpreter(const char *cmd)
112{
113 static char buf[100];
114 char *p, *opt;
115 int n, fd;
116
117 /* don't even try a .exe */
118 n = strlen(cmd);
119 if (n >= 4 && !strcasecmp(cmd+n-4, ".exe"))
120 return NULL;
121
122 fd = open(cmd, O_RDONLY);
123 if (fd < 0)
124 return NULL;
125 n = read(fd, buf, sizeof(buf)-1);
126 close(fd);
127 if (n < 4) /* at least '#!/x' and not error */
128 return NULL;
129
130 if (buf[0] != '#' || buf[1] != '!')
131 return NULL;
132 buf[n] = '\0';
133 p = strchr(buf, '\n');
134 if (!p)
135 return NULL;
136
137 *p = '\0';
138 if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\')))
139 return NULL;
140 /* strip options */
141 if ((opt = strchr(p+1, ' ')))
142 *opt = '\0';
143 return p+1;
144}
145
146/*
147 * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
148 * (Parsing C++ Command-Line Arguments)
149 */
150static char *
151quote_arg(const char *arg)
152{
153 /* count chars to quote */
154 int len = 0, n = 0;
155 int force_quotes = 0;
156 char *q, *d;
157 const char *p = arg;
158 if (!*p) force_quotes = 1;
159 while (*p) {
160 if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'')
161 force_quotes = 1;
162 else if (*p == '"')
163 n++;
164 else if (*p == '\\') {
165 int count = 0;
166 while (*p == '\\') {
167 count++;
168 p++;
169 len++;
170 }
171 if (*p == '"')
172 n += count*2 + 1;
173 continue;
174 }
175 len++;
176 p++;
177 }
178 if (!force_quotes && n == 0)
179 return (char*)arg;
180
181 /* insert \ where necessary */
182 d = q = xmalloc(len+n+3);
183 *d++ = '"';
184 while (*arg) {
185 if (*arg == '"')
186 *d++ = '\\';
187 else if (*arg == '\\') {
188 int count = 0;
189 while (*arg == '\\') {
190 count++;
191 *d++ = *arg++;
192 }
193 if (*arg == '"') {
194 while (count-- > 0)
195 *d++ = '\\';
196 *d++ = '\\';
197 }
198 }
199 *d++ = *arg++;
200 }
201 *d++ = '"';
202 *d++ = 0;
203 return q;
204}
205
206static pid_t
207spawnveq(int mode, const char *path, const char *const *argv, const char *const *env)
208{
209 char **new_argv;
210 int i, argc = 0;
211 pid_t ret;
212
213 if (!argv) {
214 const char *empty_argv[] = { path, NULL };
215 return spawnve(mode, path, empty_argv, env);
216 }
217
218
219 while (argv[argc])
220 argc++;
221
222 new_argv = malloc(sizeof(*argv)*(argc+1));
223 for (i = 0;i < argc;i++)
224 new_argv[i] = quote_arg(argv[i]);
225 new_argv[argc] = NULL;
226 ret = spawnve(mode, path, (const char *const *)new_argv, env);
227 for (i = 0;i < argc;i++)
228 if (new_argv[i] != argv[i])
229 free(new_argv[i]);
230 free(new_argv);
231 return ret;
232}
233
234pid_t
235mingw_spawn_applet(int mode,
236 const char *applet,
237 const char *const *argv,
238 const char *const *envp,
239 int transfer_fd)
240{
241 char **env = copy_environ(envp);
242 char path[MAX_PATH+20];
243 int ret;
244
245 sprintf(path, "BUSYBOX_APPLET_NAME=%s", applet);
246 env = env_setenv(env, path);
247 if (transfer_fd) {
248 sprintf(path, "BUSYBOX_ASH_TRANSFER=%x", (int)_get_osfhandle(transfer_fd));
249 env = env_setenv(env, path);
250 }
251 ret = spawnveq(mode, get_busybox_exec_path(), argv, (const char *const *)env);
252 free_environ(env);
253 return ret;
254}
255
256static pid_t
257mingw_spawn_interpreter(int mode, const char *prog, const char *const *argv, char **path, const char *const *envp)
258{
259 const char *interpr = parse_interpreter(prog);
260
261 if (!interpr)
262 return spawnveq(mode, prog, argv, envp);
263
264 if (ENABLE_FEATURE_PREFER_APPLETS && !strcmp(interpr, "sh")) {
265 int ret;
266 const char **new_argv;
267 int argc = 0;
268
269 while (argv[argc])
270 argc++;
271 new_argv = malloc(sizeof(*argv)*(argc+2));
272 memcpy(new_argv+1, argv, sizeof(*argv)*(argc+1));
273 new_argv[0] = prog; /* pass absolute path */
274 ret = mingw_spawn_applet(mode, "sh", new_argv, envp, 0);
275 free(new_argv);
276 return ret;
277 }
278 else {
279 int ret;
280 char *iprog = path_lookup(interpr, path, 1);
281 if (!iprog) {
282 errno = ENOENT;
283 return -1;
284 }
285 ret = spawnveq(mode, iprog, argv, envp);
286 free(iprog);
287 return ret;
288 }
289}
290
291pid_t
292mingw_spawn_1(int mode, const char *cmd, const char *const *argv, const char *const *envp)
293{
294 int ret;
295
296 if (ENABLE_FEATURE_PREFER_APPLETS &&
297 find_applet_by_name(cmd) >= 0)
298 return mingw_spawn_applet(mode, cmd, argv++, envp, 0);
299 else {
300 char **path = get_path_split();
301 char *prog = path_lookup(cmd, path, 0);
302
303 if (prog) {
304 ret = mingw_spawn_interpreter(mode, prog, argv, path, envp);
305 free(prog);
306 free_path_split(path);
307 return ret;
308 }
309 else {
310 errno = ENOENT;
311 free_path_split(path);
312 return -1;
313 }
314 }
315 return ret;
316}
317
318pid_t
319mingw_spawn(char **argv)
320{
321 return mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)(argv+1), (const char *const *)environ);
322}
323
324int
325mingw_execvp(const char *cmd, const char *const *argv)
326{
327 int ret = (int)mingw_spawn_1(P_WAIT, cmd, argv,
328 (const char *const *)environ);
329 if (ret != -1)
330 exit(ret);
331 return ret;
332}
333
334int
335mingw_execve(const char *cmd, const char *const *argv, const char *const *envp)
336{
337 int ret;
338 int mode = P_WAIT;
339
340 if (ENABLE_FEATURE_PREFER_APPLETS &&
341 find_applet_by_name(cmd) >= 0)
342 ret = mingw_spawn_applet(mode, cmd, argv++, envp, 0);
343 else {
344 char **path = get_path_split();
345 ret = mingw_spawn_interpreter(mode, cmd, argv, path, envp);
346 free_path_split(path);
347 }
348 if (ret != -1)
349 exit(ret);
350 return ret;
351}
352
353int
354mingw_execv(const char *cmd, const char *const *argv)
355{
356 return mingw_execve(cmd, argv, (const char *const *)environ);
357}