From 9ee8e87d5affe019aeb2b8afe4b908672c4c2fa5 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Fri, 14 Jun 2024 08:12:08 +0100 Subject: [PATCH] win32: allow for trailing separator in PATH In recent versions of Windows the PATH environment variable has a trailing semicolon. This is insignificant to Windows because it's ignored. busybox-w32 conforms to the POSIX interpretation of PATH which treats an empty path element as denoting the current directory. As result, on these versions of Windows executables may by default be run from the current directory, contrary to usual Unix practice. Attempt to detect and remove the trailing semicolon on applet start up. If the user insists, they can add a trailing semicolon to the shell variable PATH and it will be respected in the conventional manner. Adds 88-112 bytes. (GitHub issue #422) --- include/mingw.h | 1 + libbb/appletlib.c | 12 ++++++++++++ shell/ash.c | 46 ++++++++-------------------------------------- win32/mingw.c | 26 ++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 38 deletions(-) diff --git a/include/mingw.h b/include/mingw.h index 2a6cae4ee9..fae732332c 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -638,3 +638,4 @@ char *get_user_name(void); char *quote_arg(const char *arg); char *find_first_executable(const char *name); char *xappendword(const char *str, const char *word); +int windows_env(void); diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 1232d97c94..1f9968f106 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -1410,6 +1410,18 @@ int main(int argc UNUSED_PARAM, char **argv) if (s) *s = '\0'; } + + if (windows_env()) { + /* remove single trailing separator from PATH */ + for (char **envp = environ; envp && *envp; envp++) { + if (is_prefixed_with_case(*envp, "PATH=")) { + char *end = last_char_is(*envp, ';'); + if (end && end[-1] != ';') + *end = '\0'; + break; + } + } + } # endif applet_name = bb_basename(applet_name); diff --git a/shell/ash.c b/shell/ash.c index d2c88c4bc9..ad77689e74 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -15885,30 +15885,6 @@ static void setvar_if_unset(const char *key, const char *value) } #endif -#if ENABLE_PLATFORM_MINGW32 -/* - * Detect if the environment contains certain mixed-case names: - * - * Path is present in a standard Windows environment - * ComSpec is present in WINE - * ProgramData is present in Cygwin/MSYS2 - */ -static int mixed_case_special_name(const char *envp) -{ - const char *names = "PATH=\0""COMSPEC=\0""PROGRAMDATA=\0"; - const char *n; - - for (n = names; *n; ) { - if (is_prefixed_with_case(envp, n) && !is_prefixed_with(envp, n)) { - return TRUE; - } - while (*n++) - ; - } - return FALSE; -} -#endif - /* Don't inline: conserve stack of caller from having our locals too */ static NOINLINE void init(void) @@ -15941,26 +15917,20 @@ init(void) * We may end up having both Path and PATH. Then Path will be chosen * because it appears first. */ - for (envp = environ; envp && *envp; envp++) { - if (mixed_case_special_name(*envp)) { - /* mintty sets HOME: unset it */ - const char *tty = getenv("TERM_PROGRAM"); - if (tty && strcmp(tty, "mintty") == 0) { - unsetenv("HOME"); - } - break; - } - } - - if (envp && *envp) { + if (windows_env()) { /* - * If we get here it's because the environment contains a path - * variable called something other than PATH. This suggests we + * If we get here it's because the environment suggests we * haven't been invoked from an earlier instance of BusyBox. */ char *start, *end; struct passwd *pw; + /* mintty sets HOME: unset it */ + const char *tty = getenv("TERM_PROGRAM"); + if (tty && strcmp(tty, "mintty") == 0) { + unsetenv("HOME"); + } + import = VIMPORT; for (envp = environ; envp && *envp; envp++) { if (!(end=strchr(*envp, '='))) diff --git a/win32/mingw.c b/win32/mingw.c index d3daf8315a..f96b5b49a7 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -2464,3 +2464,29 @@ char *xappendword(const char *str, const char *word) free((void *)str); return newstr; } + +/* + * Detect if the environment contains certain mixed-case names: + * + * Path is present in a standard Windows environment + * ComSpec is present in WINE + * ProgramData is present in Cygwin/MSYS2 + */ +int +windows_env(void) +{ + const char *names = "PATH=\0""COMSPEC=\0""PROGRAMDATA=\0"; + const char *n; + + for (char **envp = environ; envp && *envp; envp++) { + for (n = names; *n; ) { + if (is_prefixed_with_case(*envp, n) && + !is_prefixed_with(*envp, n)) { + return TRUE; + } + while (*n++) + ; + } + } + return FALSE; +}