Skip to content

Commit

Permalink
win32: allow for trailing separator in PATH
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
rmyorston committed Jun 14, 2024
1 parent a518a4f commit 9ee8e87
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 38 deletions.
1 change: 1 addition & 0 deletions include/mingw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
12 changes: 12 additions & 0 deletions libbb/appletlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
46 changes: 8 additions & 38 deletions shell/ash.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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, '=')))
Expand Down
26 changes: 26 additions & 0 deletions win32/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit 9ee8e87

Please # to comment.