From 41ef232fc522d91f29931ea4ee547432ca8899ee Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 13 Aug 2020 14:27:56 +0100 Subject: 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. --- debianutils/which.c | 10 ++++++++++ include/mingw.h | 1 + shell/ash.c | 55 ++++++++++++++++++++++++++++++++++++++++++++--------- win32/mingw.c | 13 +++++++++++++ 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) if (strchr(*argv, '/')) { #else if (has_path(*argv)) { +# if ENABLE_FEATURE_SH_STANDALONE + const char *name = bb_basename(*argv); + int is_unix_path = unix_path(*argv); +# endif *argv = auto_add_system_drive(*argv); if ((p=auto_win32_extension(*argv)) != NULL) { missing = 0; @@ -86,6 +90,12 @@ int which_main(int argc UNUSED_PARAM, char **argv) puts(*argv); #endif } +#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE + else if (is_unix_path && find_applet_by_name(name) >= 0) { + missing = 0; + puts(name); + } +#endif } else { char *path; #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); void fix_path_case(char *path); void make_sparse(int fd, off_t start, off_t end); int skip_ansi_emulation(int reset); +int unix_path(const char *path); 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) #endif ) { #if ENABLE_PLATFORM_MINGW32 +# if ENABLE_FEATURE_SH_STANDALONE + char *oldprog = prog; +# endif prog = auto_add_system_drive(prog); #endif 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) */ goto try_PATH; } +#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE + if (oldprog != prog && unix_path(oldprog)) { + if ((applet_no = find_applet_by_name(bb_basename(oldprog))) >= 0) + tryexec(applet_no, bb_basename(oldprog), argv, envp); + else + errno = ENOENT; + } +#endif e = errno; } else { try_PATH: @@ -9191,6 +9202,12 @@ describe_command(char *command, const char *path, int describe_command_verbose) case CMDNORMAL: { int j = entry.u.index; char *p; +#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE + if (j == INT_MIN) { + p = (char *)bb_basename(command); + goto describe; + } +#endif if (j < 0) { #if ENABLE_PLATFORM_MINGW32 /* 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) #if ENABLE_PLATFORM_MINGW32 add_win32_extension(p); bs_to_slash(p); + IF_FEATURE_SH_STANDALONE(describe:) #endif if (describe_command_verbose) { out1fmt(" is %s", p); @@ -14268,23 +14286,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) struct builtincmd *bcmd; int len; +#if !ENABLE_PLATFORM_MINGW32 /* If name contains a slash, don't use PATH or hash table */ -#if ENABLE_PLATFORM_MINGW32 - if (has_path(name)) { - name = auto_add_system_drive(name); -#else if (strchr(name, '/') != NULL) { -#endif entry->u.index = -1; if (act & DO_ABS) { -#if ENABLE_PLATFORM_MINGW32 - if (auto_win32_extension(name) == NULL && stat(name, &statb) < 0) { -#else while (stat(name, &statb) < 0) { #ifdef SYSV if (errno == EINTR) continue; -#endif #endif entry->cmdtype = CMDUNKNOWN; return; @@ -14293,6 +14303,33 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) entry->cmdtype = CMDNORMAL; return; } +#else /* ENABLE_PLATFORM_MINGW32 */ + /* If name contains a slash or drive prefix, don't use PATH or hash table */ + if (has_path(name)) { +# if ENABLE_FEATURE_SH_STANDALONE + char *oldname = name; +# endif + name = auto_add_system_drive(name); + entry->u.index = -1; + if (act & DO_ABS) { + if (auto_win32_extension(name) == NULL && stat(name, &statb) < 0) { +# if ENABLE_FEATURE_SH_STANDALONE + int applet_no; + if (unix_path(oldname) && + (applet_no = find_applet_by_name(bb_basename(oldname))) >= 0) { + entry->cmdtype = CMDNORMAL; + entry->u.index = INT_MIN; + return; + } +# endif + entry->cmdtype = CMDUNKNOWN; + return; + } + } + entry->cmdtype = CMDNORMAL; + return; + } +#endif /* ENABLE_PLATFORM_MINGW32 */ /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ 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, return proc->pfunction; } +#if ENABLE_FEATURE_SH_STANDALONE || ENABLE_FEATURE_PREFER_APPLETS +int unix_path(const char *path) +{ + int i; + char *p = strdup(path); + +#define UNIX_PATHS "/bin\0/usr/bin\0/sbin\0/usr/sbin\0" + i = index_in_strings(UNIX_PATHS, dirname(p)); + free(p); + return i >= 0; +} +#endif + /* Return true if file is referenced using a path. This means a path * look-up isn't required. */ 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) { char *prog; const char *path; + intptr_t ret; #if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE 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) else #endif if (has_path(cmd)) { +#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE + const char *oldcmd = cmd; +#endif cmd = auto_add_system_drive(cmd); path = auto_win32_extension(cmd); - return mingw_spawn_interpreter(mode, path ? path : cmd, argv, envp, 0); + ret = mingw_spawn_interpreter(mode, path ? path : cmd, argv, envp, 0); +#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE + if (ret == -1 && cmd != oldcmd && unix_path(oldcmd) && + find_applet_by_name(bb_basename(oldcmd))) { + return mingw_spawn_applet(mode, argv, envp); + } +#endif + return ret; } else if ((prog=find_first_executable(cmd)) != NULL) { - intptr_t ret = mingw_spawn_interpreter(mode, prog, argv, envp, 0); + ret = mingw_spawn_interpreter(mode, prog, argv, envp, 0); free(prog); return ret; } -- cgit v1.2.3-55-g6feb