diff options
author | Ron Yorston <rmy@pobox.com> | 2020-08-13 14:27:56 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2020-08-13 14:58:01 +0100 |
commit | 41ef232fc522d91f29931ea4ee547432ca8899ee (patch) | |
tree | d2acfdc43839b68b569debb4494d5c7fbd8bc66b | |
parent | 16e5930a65f3c7c570b8a0dda8daa19ab4792fa2 (diff) | |
download | busybox-w32-41ef232fc522d91f29931ea4ee547432ca8899ee.tar.gz busybox-w32-41ef232fc522d91f29931ea4ee547432ca8899ee.tar.bz2 busybox-w32-41ef232fc522d91f29931ea4ee547432ca8899ee.zip |
win32: use built-in applets for non-existent binaries with Unix-style paths
Shell scripts moved from Unix may contain hard-coded paths to
binaries such as /bin/sh. A recent commit made it possible to
execute such binaries reliably, but that does require them to be
installed. As an alternative solution: if a binary with a
standard Unix path prefix can't be found but is available as a
built-in applet, run the applet.
Add the function unix_path() to detect paths starting with /bin,
/usr/bin, /sbin or /usr/sbin.
Use this function in:
- the 'which' applet
- shellexec(), describe_command() and find_command() in ash
- mingw_spawn_1()
See GitHub issue #195.
-rw-r--r-- | debianutils/which.c | 10 | ||||
-rw-r--r-- | include/mingw.h | 1 | ||||
-rw-r--r-- | shell/ash.c | 55 | ||||
-rw-r--r-- | win32/mingw.c | 13 | ||||
-rw-r--r-- | win32/process.c | 15 |
5 files changed, 83 insertions, 11 deletions
diff --git a/debianutils/which.c b/debianutils/which.c index c8e99acda..384e2cfec 100644 --- a/debianutils/which.c +++ b/debianutils/which.c | |||
@@ -71,6 +71,10 @@ int which_main(int argc UNUSED_PARAM, char **argv) | |||
71 | if (strchr(*argv, '/')) { | 71 | if (strchr(*argv, '/')) { |
72 | #else | 72 | #else |
73 | if (has_path(*argv)) { | 73 | if (has_path(*argv)) { |
74 | # if ENABLE_FEATURE_SH_STANDALONE | ||
75 | const char *name = bb_basename(*argv); | ||
76 | int is_unix_path = unix_path(*argv); | ||
77 | # endif | ||
74 | *argv = auto_add_system_drive(*argv); | 78 | *argv = auto_add_system_drive(*argv); |
75 | if ((p=auto_win32_extension(*argv)) != NULL) { | 79 | if ((p=auto_win32_extension(*argv)) != NULL) { |
76 | missing = 0; | 80 | missing = 0; |
@@ -86,6 +90,12 @@ int which_main(int argc UNUSED_PARAM, char **argv) | |||
86 | puts(*argv); | 90 | puts(*argv); |
87 | #endif | 91 | #endif |
88 | } | 92 | } |
93 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
94 | else if (is_unix_path && find_applet_by_name(name) >= 0) { | ||
95 | missing = 0; | ||
96 | puts(name); | ||
97 | } | ||
98 | #endif | ||
89 | } else { | 99 | } else { |
90 | char *path; | 100 | char *path; |
91 | #if !ENABLE_PLATFORM_MINGW32 | 101 | #if !ENABLE_PLATFORM_MINGW32 |
diff --git a/include/mingw.h b/include/mingw.h index 434f3a474..b34d8772c 100644 --- a/include/mingw.h +++ b/include/mingw.h | |||
@@ -555,4 +555,5 @@ char *get_drive_cwd(const char *path, char *buffer, int size); | |||
555 | void fix_path_case(char *path); | 555 | void fix_path_case(char *path); |
556 | void make_sparse(int fd, off_t start, off_t end); | 556 | void make_sparse(int fd, off_t start, off_t end); |
557 | int skip_ansi_emulation(int reset); | 557 | int skip_ansi_emulation(int reset); |
558 | int unix_path(const char *path); | ||
558 | int has_path(const char *file); | 559 | int has_path(const char *file); |
diff --git a/shell/ash.c b/shell/ash.c index 0a638b1df..2267e841f 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -8754,6 +8754,9 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
8754 | #endif | 8754 | #endif |
8755 | ) { | 8755 | ) { |
8756 | #if ENABLE_PLATFORM_MINGW32 | 8756 | #if ENABLE_PLATFORM_MINGW32 |
8757 | # if ENABLE_FEATURE_SH_STANDALONE | ||
8758 | char *oldprog = prog; | ||
8759 | # endif | ||
8757 | prog = auto_add_system_drive(prog); | 8760 | prog = auto_add_system_drive(prog); |
8758 | #endif | 8761 | #endif |
8759 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); | 8762 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); |
@@ -8764,6 +8767,14 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
8764 | */ | 8767 | */ |
8765 | goto try_PATH; | 8768 | goto try_PATH; |
8766 | } | 8769 | } |
8770 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
8771 | if (oldprog != prog && unix_path(oldprog)) { | ||
8772 | if ((applet_no = find_applet_by_name(bb_basename(oldprog))) >= 0) | ||
8773 | tryexec(applet_no, bb_basename(oldprog), argv, envp); | ||
8774 | else | ||
8775 | errno = ENOENT; | ||
8776 | } | ||
8777 | #endif | ||
8767 | e = errno; | 8778 | e = errno; |
8768 | } else { | 8779 | } else { |
8769 | try_PATH: | 8780 | try_PATH: |
@@ -9191,6 +9202,12 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
9191 | case CMDNORMAL: { | 9202 | case CMDNORMAL: { |
9192 | int j = entry.u.index; | 9203 | int j = entry.u.index; |
9193 | char *p; | 9204 | char *p; |
9205 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
9206 | if (j == INT_MIN) { | ||
9207 | p = (char *)bb_basename(command); | ||
9208 | goto describe; | ||
9209 | } | ||
9210 | #endif | ||
9194 | if (j < 0) { | 9211 | if (j < 0) { |
9195 | #if ENABLE_PLATFORM_MINGW32 | 9212 | #if ENABLE_PLATFORM_MINGW32 |
9196 | /* can't use auto_add_system_drive, need space for extension */ | 9213 | /* can't use auto_add_system_drive, need space for extension */ |
@@ -9211,6 +9228,7 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
9211 | #if ENABLE_PLATFORM_MINGW32 | 9228 | #if ENABLE_PLATFORM_MINGW32 |
9212 | add_win32_extension(p); | 9229 | add_win32_extension(p); |
9213 | bs_to_slash(p); | 9230 | bs_to_slash(p); |
9231 | IF_FEATURE_SH_STANDALONE(describe:) | ||
9214 | #endif | 9232 | #endif |
9215 | if (describe_command_verbose) { | 9233 | if (describe_command_verbose) { |
9216 | out1fmt(" is %s", p); | 9234 | out1fmt(" is %s", p); |
@@ -14268,24 +14286,16 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
14268 | struct builtincmd *bcmd; | 14286 | struct builtincmd *bcmd; |
14269 | int len; | 14287 | int len; |
14270 | 14288 | ||
14289 | #if !ENABLE_PLATFORM_MINGW32 | ||
14271 | /* If name contains a slash, don't use PATH or hash table */ | 14290 | /* If name contains a slash, don't use PATH or hash table */ |
14272 | #if ENABLE_PLATFORM_MINGW32 | ||
14273 | if (has_path(name)) { | ||
14274 | name = auto_add_system_drive(name); | ||
14275 | #else | ||
14276 | if (strchr(name, '/') != NULL) { | 14291 | if (strchr(name, '/') != NULL) { |
14277 | #endif | ||
14278 | entry->u.index = -1; | 14292 | entry->u.index = -1; |
14279 | if (act & DO_ABS) { | 14293 | if (act & DO_ABS) { |
14280 | #if ENABLE_PLATFORM_MINGW32 | ||
14281 | if (auto_win32_extension(name) == NULL && stat(name, &statb) < 0) { | ||
14282 | #else | ||
14283 | while (stat(name, &statb) < 0) { | 14294 | while (stat(name, &statb) < 0) { |
14284 | #ifdef SYSV | 14295 | #ifdef SYSV |
14285 | if (errno == EINTR) | 14296 | if (errno == EINTR) |
14286 | continue; | 14297 | continue; |
14287 | #endif | 14298 | #endif |
14288 | #endif | ||
14289 | entry->cmdtype = CMDUNKNOWN; | 14299 | entry->cmdtype = CMDUNKNOWN; |
14290 | return; | 14300 | return; |
14291 | } | 14301 | } |
@@ -14293,6 +14303,33 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
14293 | entry->cmdtype = CMDNORMAL; | 14303 | entry->cmdtype = CMDNORMAL; |
14294 | return; | 14304 | return; |
14295 | } | 14305 | } |
14306 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
14307 | /* If name contains a slash or drive prefix, don't use PATH or hash table */ | ||
14308 | if (has_path(name)) { | ||
14309 | # if ENABLE_FEATURE_SH_STANDALONE | ||
14310 | char *oldname = name; | ||
14311 | # endif | ||
14312 | name = auto_add_system_drive(name); | ||
14313 | entry->u.index = -1; | ||
14314 | if (act & DO_ABS) { | ||
14315 | if (auto_win32_extension(name) == NULL && stat(name, &statb) < 0) { | ||
14316 | # if ENABLE_FEATURE_SH_STANDALONE | ||
14317 | int applet_no; | ||
14318 | if (unix_path(oldname) && | ||
14319 | (applet_no = find_applet_by_name(bb_basename(oldname))) >= 0) { | ||
14320 | entry->cmdtype = CMDNORMAL; | ||
14321 | entry->u.index = INT_MIN; | ||
14322 | return; | ||
14323 | } | ||
14324 | # endif | ||
14325 | entry->cmdtype = CMDUNKNOWN; | ||
14326 | return; | ||
14327 | } | ||
14328 | } | ||
14329 | entry->cmdtype = CMDNORMAL; | ||
14330 | return; | ||
14331 | } | ||
14332 | #endif /* ENABLE_PLATFORM_MINGW32 */ | ||
14296 | 14333 | ||
14297 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ | 14334 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ |
14298 | 14335 | ||
diff --git a/win32/mingw.c b/win32/mingw.c index e63ffa0ac..4ffc49e9a 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -1818,6 +1818,19 @@ void *get_proc_addr(const char *dll, const char *function, | |||
1818 | return proc->pfunction; | 1818 | return proc->pfunction; |
1819 | } | 1819 | } |
1820 | 1820 | ||
1821 | #if ENABLE_FEATURE_SH_STANDALONE || ENABLE_FEATURE_PREFER_APPLETS | ||
1822 | int unix_path(const char *path) | ||
1823 | { | ||
1824 | int i; | ||
1825 | char *p = strdup(path); | ||
1826 | |||
1827 | #define UNIX_PATHS "/bin\0/usr/bin\0/sbin\0/usr/sbin\0" | ||
1828 | i = index_in_strings(UNIX_PATHS, dirname(p)); | ||
1829 | free(p); | ||
1830 | return i >= 0; | ||
1831 | } | ||
1832 | #endif | ||
1833 | |||
1821 | /* Return true if file is referenced using a path. This means a path | 1834 | /* Return true if file is referenced using a path. This means a path |
1822 | * look-up isn't required. */ | 1835 | * look-up isn't required. */ |
1823 | int has_path(const char *file) | 1836 | int has_path(const char *file) |
diff --git a/win32/process.c b/win32/process.c index cd164e0ed..a050ec11d 100644 --- a/win32/process.c +++ b/win32/process.c | |||
@@ -350,6 +350,7 @@ mingw_spawn_1(int mode, const char *cmd, char *const *argv, char *const *envp) | |||
350 | { | 350 | { |
351 | char *prog; | 351 | char *prog; |
352 | const char *path; | 352 | const char *path; |
353 | intptr_t ret; | ||
353 | 354 | ||
354 | #if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE | 355 | #if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE |
355 | if (find_applet_by_name(cmd) >= 0) | 356 | if (find_applet_by_name(cmd) >= 0) |
@@ -357,12 +358,22 @@ mingw_spawn_1(int mode, const char *cmd, char *const *argv, char *const *envp) | |||
357 | else | 358 | else |
358 | #endif | 359 | #endif |
359 | if (has_path(cmd)) { | 360 | if (has_path(cmd)) { |
361 | #if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE | ||
362 | const char *oldcmd = cmd; | ||
363 | #endif | ||
360 | cmd = auto_add_system_drive(cmd); | 364 | cmd = auto_add_system_drive(cmd); |
361 | path = auto_win32_extension(cmd); | 365 | path = auto_win32_extension(cmd); |
362 | return mingw_spawn_interpreter(mode, path ? path : cmd, argv, envp, 0); | 366 | ret = mingw_spawn_interpreter(mode, path ? path : cmd, argv, envp, 0); |
367 | #if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE | ||
368 | if (ret == -1 && cmd != oldcmd && unix_path(oldcmd) && | ||
369 | find_applet_by_name(bb_basename(oldcmd))) { | ||
370 | return mingw_spawn_applet(mode, argv, envp); | ||
371 | } | ||
372 | #endif | ||
373 | return ret; | ||
363 | } | 374 | } |
364 | else if ((prog=find_first_executable(cmd)) != NULL) { | 375 | else if ((prog=find_first_executable(cmd)) != NULL) { |
365 | intptr_t ret = mingw_spawn_interpreter(mode, prog, argv, envp, 0); | 376 | ret = mingw_spawn_interpreter(mode, prog, argv, envp, 0); |
366 | free(prog); | 377 | free(prog); |
367 | return ret; | 378 | return ret; |
368 | } | 379 | } |