aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2012-04-17 11:47:16 +0100
committerRon Yorston <rmy@pobox.com>2012-04-17 11:47:16 +0100
commit7209ab16b8ef7ac9d7a298434aaf456d1cc6a982 (patch)
treecb0ca0df2bb4d71ff4096eea5c7c8fa8ad2d66e5
parent3f092d0d50a8212dbc3af096f952c34cba128302 (diff)
downloadbusybox-w32-7209ab16b8ef7ac9d7a298434aaf456d1cc6a982.tar.gz
busybox-w32-7209ab16b8ef7ac9d7a298434aaf456d1cc6a982.tar.bz2
busybox-w32-7209ab16b8ef7ac9d7a298434aaf456d1cc6a982.zip
Detect and execute shell scripts based on presence of '#!'
-rw-r--r--libbb/execable.c30
-rw-r--r--shell/ash.c15
-rw-r--r--win32/process.c74
3 files changed, 91 insertions, 28 deletions
diff --git a/libbb/execable.c b/libbb/execable.c
index e35dad208..afb957e43 100644
--- a/libbb/execable.c
+++ b/libbb/execable.c
@@ -16,15 +16,31 @@
16int FAST_FUNC execable_file(const char *name) 16int FAST_FUNC execable_file(const char *name)
17{ 17{
18 struct stat s; 18 struct stat s;
19 if (ENABLE_PLATFORM_MINGW32) { 19#if ENABLE_PLATFORM_MINGW32
20 int len = strlen(name); 20 if (!stat(name, &s) && S_ISREG(s.st_mode)) {
21 return len > 4 && 21 int len, fd, n;
22 char buf[100];
23
24 if ((len=strlen(name)) > 4 &&
22 (!strcasecmp(name+len-4, ".exe") || 25 (!strcasecmp(name+len-4, ".exe") ||
23 !strcasecmp(name+len-4, ".com")) && 26 !strcasecmp(name+len-4, ".com"))) {
24 !stat(name, &s) && 27 return 1;
25 S_ISREG(s.st_mode); 28 }
29
30 fd = open(name, O_RDONLY);
31 if (fd < 0)
32 return 0;
33 n = read(fd, buf, sizeof(buf)-1);
34 close(fd);
35 if (n < 4) /* at least '#!/x' and not error */
36 return 0;
37
38 return (buf[0] == '#' && buf[1] == '!');
26 } 39 }
40 return 0;
41#else
27 return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode)); 42 return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode));
43#endif
28} 44}
29 45
30/* search (*PATHp) for an executable file; 46/* search (*PATHp) for an executable file;
@@ -67,11 +83,13 @@ char* FAST_FUNC find_execable(const char *filename, char **PATHp)
67 memcpy(np+len, ".exe", 5); 83 memcpy(np+len, ".exe", 5);
68 if (execable_file(np)) { 84 if (execable_file(np)) {
69 *PATHp = n; 85 *PATHp = n;
86 free(p);
70 return np; 87 return np;
71 } 88 }
72 memcpy(np+len, ".com", 5); 89 memcpy(np+len, ".com", 5);
73 if (execable_file(np)) { 90 if (execable_file(np)) {
74 *PATHp = n; 91 *PATHp = n;
92 free(p);
75 return np; 93 return np;
76 } 94 }
77 } 95 }
diff --git a/shell/ash.c b/shell/ash.c
index a809bf181..54c299d7e 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -21,7 +21,9 @@
21 * 21 *
22 * - Environment variables from Windows will all be turned to uppercase. 22 * - Environment variables from Windows will all be turned to uppercase.
23 * - PATH accepts both ; and : as separator, but can't be mixed 23 * - PATH accepts both ; and : as separator, but can't be mixed
24 * - command without ".exe" is still understood as executable (option to turn off?) 24 * - command without ".exe" extension is still understood as executable
25 * - shell scripts on the path are detected by the presence of '#!';
26 * the path to the interpreter is ignored, PATH is searched to find it
25 * - both / and \ are supported in PATH. Usually you must use / 27 * - both / and \ are supported in PATH. Usually you must use /
26 * - trap/job does not work 28 * - trap/job does not work
27 * - /dev/null is supported for redirection 29 * - /dev/null is supported for redirection
@@ -12947,7 +12949,16 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12947 if (stat(fullname, &statb) < 0) { 12949 if (stat(fullname, &statb) < 0) {
12948 if (errno != ENOENT && errno != ENOTDIR) 12950 if (errno != ENOENT && errno != ENOTDIR)
12949 e = errno; 12951 e = errno;
12950 goto loop; 12952 fullname[len] = '\0';
12953 if (stat(fullname, &statb) < 0) {
12954 if (errno != ENOENT && errno != ENOTDIR)
12955 e = errno;
12956 goto loop;
12957 }
12958 if (!execable_file(fullname)) {
12959 e = ENOEXEC;
12960 goto loop;
12961 }
12951 } 12962 }
12952 } 12963 }
12953 fullname[len] = '\0'; 12964 fullname[len] = '\0';
diff --git a/win32/process.c b/win32/process.c
index 3ce152c45..2cfec4fdf 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -30,13 +30,18 @@ next_path_sep(const char *path)
30 return strchr(has_dos_drive_prefix(path) ? path+2 : path, ':'); 30 return strchr(has_dos_drive_prefix(path) ? path+2 : path, ':');
31} 31}
32 32
33#define MAX_OPT 10
34
33static const char * 35static const char *
34parse_interpreter(const char *cmd) 36parse_interpreter(const char *cmd, char ***opts, int *nopts)
35{ 37{
36 static char buf[100]; 38 static char buf[100];
37 char *p, *opt; 39 char *p, *s, *t, *opt[MAX_OPT];
38 int n, fd; 40 int n, fd;
39 41
42 *nopts = 0;
43 *opts = opt;
44
40 /* don't even try a .exe */ 45 /* don't even try a .exe */
41 n = strlen(cmd); 46 n = strlen(cmd);
42 if (n >= 4 && 47 if (n >= 4 &&
@@ -58,13 +63,34 @@ parse_interpreter(const char *cmd)
58 p = strchr(buf, '\n'); 63 p = strchr(buf, '\n');
59 if (!p) 64 if (!p)
60 return NULL; 65 return NULL;
61
62 *p = '\0'; 66 *p = '\0';
67
68 /* remove trailing whitespace */
69 while ( isspace(*--p) ) {
70 *p = '\0';
71 }
72
63 if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\'))) 73 if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\')))
64 return NULL; 74 return NULL;
65 /* strip options */ 75
66 if ((opt = strchr(p+1, ' '))) 76 /* move to end of interpreter name */
67 *opt = '\0'; 77 for ( s=p; *s && !isspace(*s); ++s ) {
78 }
79
80 n = 0;
81 if ( *s != '\0' ) {
82 /* there are options */
83 *s++ = '\0';
84
85 while ( (t=strtok(s, " \t")) && n < MAX_OPT ) {
86 s = NULL;
87 opt[n++] = t;
88 }
89 }
90
91 *nopts = n;
92 *opts = opt;
93
68 return p+1; 94 return p+1;
69} 95}
70 96
@@ -179,35 +205,43 @@ static pid_t
179mingw_spawn_interpreter(int mode, const char *prog, const char *const *argv, const char *const *envp) 205mingw_spawn_interpreter(int mode, const char *prog, const char *const *argv, const char *const *envp)
180{ 206{
181 int ret; 207 int ret;
182 const char *interpr = parse_interpreter(prog); 208 char **opts;
209 int nopts;
210 const char *interpr = parse_interpreter(prog, &opts, &nopts);
211 const char **new_argv;
212 int argc = 0;
183 213
184 if (!interpr) 214 if (!interpr)
185 return spawnveq(mode, prog, argv, envp); 215 return spawnveq(mode, prog, argv, envp);
186 216
187 if (ENABLE_FEATURE_PREFER_APPLETS && !strcmp(interpr, "sh")) { 217
188 const char **new_argv; 218 while (argv[argc])
189 int argc = 0; 219 argc++;
190 220 new_argv = malloc(sizeof(*argv)*(argc+nopts+2));
191 while (argv[argc]) 221 memcpy(new_argv+1, opts, sizeof(*opts)*nopts);
192 argc++; 222 memcpy(new_argv+nopts+2, argv+1, sizeof(*argv)*argc);
193 new_argv = malloc(sizeof(*argv)*(argc+2)); 223 new_argv[nopts+1] = prog; /* pass absolute path */
194 memcpy(new_argv+1, argv, sizeof(*argv)*(argc+1)); 224
195 new_argv[0] = prog; /* pass absolute path */ 225 if (ENABLE_FEATURE_PREFER_APPLETS && find_applet_by_name(interpr) >= 0) {
196 ret = mingw_spawn_applet(mode, "sh", new_argv, envp); 226 new_argv[0] = interpr;
197 free(new_argv); 227 ret = mingw_spawn_applet(mode, interpr, new_argv, envp);
198 } 228 }
199 else { 229 else {
200 char *path = xstrdup(getenv("PATH")); 230 char *path = xstrdup(getenv("PATH"));
201 char *tmp = path; 231 char *tmp = path;
202 char *iprog = find_execable(interpr, &tmp); 232 char *iprog = find_execable(interpr, &tmp);
203 free(path); 233 free(path);
204 if (!prog) { 234 if (!iprog) {
235 free(new_argv);
205 errno = ENOENT; 236 errno = ENOENT;
206 return -1; 237 return -1;
207 } 238 }
208 ret = spawnveq(mode, iprog, argv, envp); 239 new_argv[0] = iprog;
240 ret = spawnveq(mode, iprog, new_argv, envp);
209 free(iprog); 241 free(iprog);
210 } 242 }
243
244 free(new_argv);
211 return ret; 245 return ret;
212} 246}
213 247