aboutsummaryrefslogtreecommitdiff
path: root/win32/process.c
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-10 17:57:36 +1000
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-10 19:27:55 +1000
commit5161fa8edd5a84f5b02898f13f343254c68eca23 (patch)
tree64f125651f309dbebfbfe0b268160637d1e311f5 /win32/process.c
parentfa37e9da4b02810eedbb0ac82e8cd0b99336aa82 (diff)
downloadbusybox-w32-5161fa8edd5a84f5b02898f13f343254c68eca23.tar.gz
busybox-w32-5161fa8edd5a84f5b02898f13f343254c68eca23.tar.bz2
busybox-w32-5161fa8edd5a84f5b02898f13f343254c68eca23.zip
win32: add shell script and internal applet execution to spawn* and exec*
Most of this was extracted from commit e56b799d6ad8afba4168fffa7218d44c041a72d2 in Git repository.
Diffstat (limited to 'win32/process.c')
-rw-r--r--win32/process.c254
1 files changed, 254 insertions, 0 deletions
diff --git a/win32/process.c b/win32/process.c
index 77d19fb9a..55f5fef14 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -8,3 +8,257 @@ int waitpid(pid_t pid, int *status, unsigned options)
8 errno = EINVAL; 8 errno = EINVAL;
9 return -1; 9 return -1;
10} 10}
11
12static const char *
13parse_interpreter(const char *cmd)
14{
15 static char buf[100];
16 char *p, *opt;
17 int n, fd;
18
19 /* don't even try a .exe */
20 n = strlen(cmd);
21 if (n >= 4 && !strcasecmp(cmd+n-4, ".exe"))
22 return NULL;
23
24 fd = open(cmd, O_RDONLY);
25 if (fd < 0)
26 return NULL;
27 n = read(fd, buf, sizeof(buf)-1);
28 close(fd);
29 if (n < 4) /* at least '#!/x' and not error */
30 return NULL;
31
32 if (buf[0] != '#' || buf[1] != '!')
33 return NULL;
34 buf[n] = '\0';
35 p = strchr(buf, '\n');
36 if (!p)
37 return NULL;
38
39 *p = '\0';
40 if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\')))
41 return NULL;
42 /* strip options */
43 if ((opt = strchr(p+1, ' ')))
44 *opt = '\0';
45 return p+1;
46}
47
48/*
49 * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
50 * (Parsing C++ Command-Line Arguments)
51 */
52static char *
53quote_arg(const char *arg)
54{
55 /* count chars to quote */
56 int len = 0, n = 0;
57 int force_quotes = 0;
58 char *q, *d;
59 const char *p = arg;
60 if (!*p) force_quotes = 1;
61 while (*p) {
62 if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'')
63 force_quotes = 1;
64 else if (*p == '"')
65 n++;
66 else if (*p == '\\') {
67 int count = 0;
68 while (*p == '\\') {
69 count++;
70 p++;
71 len++;
72 }
73 if (*p == '"')
74 n += count*2 + 1;
75 continue;
76 }
77 len++;
78 p++;
79 }
80 if (!force_quotes && n == 0)
81 return (char*)arg;
82
83 /* insert \ where necessary */
84 d = q = xmalloc(len+n+3);
85 *d++ = '"';
86 while (*arg) {
87 if (*arg == '"')
88 *d++ = '\\';
89 else if (*arg == '\\') {
90 int count = 0;
91 while (*arg == '\\') {
92 count++;
93 *d++ = *arg++;
94 }
95 if (*arg == '"') {
96 while (count-- > 0)
97 *d++ = '\\';
98 *d++ = '\\';
99 }
100 }
101 *d++ = *arg++;
102 }
103 *d++ = '"';
104 *d++ = 0;
105 return q;
106}
107
108static pid_t
109spawnveq(int mode, const char *path, const char *const *argv, const char *const *env)
110{
111 char **new_argv;
112 int i, argc = 0;
113 pid_t ret;
114
115 if (!argv) {
116 const char *empty_argv[] = { path, NULL };
117 return spawnve(mode, path, empty_argv, env);
118 }
119
120
121 while (argv[argc])
122 argc++;
123
124 new_argv = malloc(sizeof(*argv)*(argc+1));
125 for (i = 0;i < argc;i++)
126 new_argv[i] = quote_arg(argv[i]);
127 new_argv[argc] = NULL;
128 ret = spawnve(mode, path, (const char *const *)new_argv, env);
129 for (i = 0;i < argc;i++)
130 if (new_argv[i] != argv[i])
131 free(new_argv[i]);
132 free(new_argv);
133 return ret;
134}
135
136pid_t
137mingw_spawn_applet(int mode,
138 const char *applet,
139 const char *const *argv,
140 const char *const *envp)
141{
142 char **env = copy_environ(envp);
143 char path[MAX_PATH+20];
144 int ret;
145
146 sprintf(path, "BUSYBOX_APPLET_NAME=%s", applet);
147 env = env_setenv(env, path);
148 ret = spawnveq(mode, get_busybox_exec_path(), argv, (const char *const *)env);
149 free_environ(env);
150 return ret;
151}
152
153static pid_t
154mingw_spawn_interpreter(int mode, const char *prog, const char *const *argv, const char *const *envp)
155{
156 int ret;
157 const char *interpr = parse_interpreter(prog);
158
159 if (!interpr)
160 return spawnveq(mode, prog, argv, envp);
161
162 if (ENABLE_FEATURE_PREFER_APPLETS && !strcmp(interpr, "sh")) {
163 const char **new_argv;
164 int argc = 0;
165
166 while (argv[argc])
167 argc++;
168 new_argv = malloc(sizeof(*argv)*(argc+2));
169 memcpy(new_argv+1, argv, sizeof(*argv)*(argc+1));
170 new_argv[0] = prog; /* pass absolute path */
171 ret = mingw_spawn_applet(mode, "sh", new_argv, envp);
172 free(new_argv);
173 }
174 else {
175 char *path = xstrdup(getenv("PATH"));
176 char *tmp = path;
177 char *iprog = find_execable(interpr, &tmp);
178 free(path);
179 if (!prog) {
180 errno = ENOENT;
181 return -1;
182 }
183 ret = spawnveq(mode, iprog, argv, envp);
184 free(iprog);
185 }
186 return ret;
187}
188
189pid_t
190mingw_spawn_1(int mode, const char *cmd, const char *const *argv, const char *const *envp)
191{
192 int ret;
193
194 if (ENABLE_FEATURE_PREFER_APPLETS &&
195 find_applet_by_name(cmd) >= 0)
196 return mingw_spawn_applet(mode, cmd, argv++, envp);
197 else if (is_absolute_path(cmd))
198 return mingw_spawn_interpreter(mode, cmd, argv, envp);
199 else {
200 char *tmp, *path = getenv("PATH");
201 char *prog;
202
203 if (!path) {
204 errno = ENOENT;
205 return -1;
206 }
207
208 /* exists_execable() does not return new file name */
209 tmp = path = xstrdup(path);
210 prog = find_execable(cmd, &tmp);
211 free(path);
212 if (!prog) {
213 errno = ENOENT;
214 return -1;
215 }
216 ret = mingw_spawn_interpreter(mode, prog, argv, envp);
217 free(prog);
218 }
219 return ret;
220}
221
222pid_t
223mingw_spawn(char **argv)
224{
225 return mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)(argv+1), (const char *const *)environ);
226}
227
228int
229mingw_execvp(const char *cmd, const char *const *argv)
230{
231 int ret = (int)mingw_spawn_1(P_WAIT, cmd, argv, (const char *const *)environ);
232 if (ret != -1)
233 exit(ret);
234 return ret;
235}
236
237int
238mingw_execve(const char *cmd, const char *const *argv, const char *const *envp)
239{
240 int ret;
241 int mode = P_WAIT;
242
243 if (ENABLE_FEATURE_PREFER_APPLETS &&
244 find_applet_by_name(cmd) >= 0)
245 ret = mingw_spawn_applet(mode, cmd, argv, envp);
246 /*
247 * execve(bb_busybox_exec_path, argv, envp) won't work
248 * because argv[0] will be replaced to bb_busybox_exec_path
249 * by MSVC runtime
250 */
251 else if (argv && cmd != argv[0] && cmd == bb_busybox_exec_path)
252 ret = mingw_spawn_applet(mode, argv[0], argv, envp);
253 else
254 ret = mingw_spawn_interpreter(mode, cmd, argv, envp);
255 if (ret != -1)
256 exit(ret);
257 return ret;
258}
259
260int
261mingw_execv(const char *cmd, const char *const *argv)
262{
263 return mingw_execve(cmd, argv, (const char *const *)environ);
264}