From a236242374daf911a01e998fabb1cc1268b2be7b Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Fri, 14 Dec 2018 15:27:54 +0000 Subject: win32: special treatment for PATH The PATH shell variable is a special case. It can be exported to the environment where it might be interpreted by native applications which assume the separator is ';'. Hence: - require that the separator used in PATH is ';' - enforce this by intercepting calls to setvareq() that set PATH and adjusting its value if necessary. As a result of this the code to parse PATH can be simplified by replacing the hardcoded Unix ':' path separator by the platform- dependent macro PATH_SEP. The MANPATH variable is also required to use ';' as its separator but since it's less likely to be used this isn't enforced. --- include/libbb.h | 6 ++++ include/mingw.h | 1 - libbb/executable.c | 15 +++------- libbb/lineedit.c | 12 ++------ miscutils/man.c | 17 ++--------- shell/ash.c | 86 ++++++++++++++++++++++++++++++++++++++---------------- win32/process.c | 20 ------------- 7 files changed, 75 insertions(+), 82 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index a17da9c1f..8b18782c8 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -2130,7 +2130,13 @@ extern const char bb_busybox_exec_path[] ALIGN1; #ifndef BB_ADDITIONAL_PATH #define BB_ADDITIONAL_PATH "" #endif +#if !ENABLE_PLATFORM_MINGW32 #define BB_PATH_ROOT_PATH "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH +#define PATH_SEP ':' +#else +#define BB_PATH_ROOT_PATH "PATH=/sbin;/usr/sbin;/bin;/usr/bin" BB_ADDITIONAL_PATH +#define PATH_SEP ';' +#endif extern const char bb_PATH_root_path[] ALIGN1; /* BB_PATH_ROOT_PATH */ #define bb_default_root_path (bb_PATH_root_path + sizeof("PATH")) /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, diff --git a/include/mingw.h b/include/mingw.h index 8a695d2d2..cef53a7c9 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -443,7 +443,6 @@ int mingw_execve(const char *cmd, char *const *argv, char *const *envp); #define execve mingw_execve #define execv mingw_execv -const char * next_path_sep(const char *path); #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_absolute_path(path) ((path)[0] == '/' || (path)[0] == '\\' || has_dos_drive_prefix(path)) diff --git a/libbb/executable.c b/libbb/executable.c index 835341ed9..87a40eeda 100644 --- a/libbb/executable.c +++ b/libbb/executable.c @@ -40,28 +40,21 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp) */ char *p, *n; #if ENABLE_PLATFORM_MINGW32 - char sep, *w; + char *w; #endif p = *PATHp; while (p) { int ex; -#if !ENABLE_PLATFORM_MINGW32 - n = strchr(p, ':'); + n = strchr(p, PATH_SEP); if (n) *n = '\0'; -#else - n = (char*)next_path_sep(p); - if (n) { sep = *n; *n = '\0'; } -#endif p = concat_path_file( p[0] ? p : ".", /* handle "::" case */ filename ); -#if !ENABLE_PLATFORM_MINGW32 - if (n) *n++ = ':'; -#else - if (n) *n++ = sep; + if (n) *n++ = PATH_SEP; +#if ENABLE_PLATFORM_MINGW32 if ((w=alloc_win32_extension(p))) { free(p); p = w; diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 89178bbc3..6513219ce 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -798,11 +798,7 @@ static int path_parse(char ***p) tmp = (char*)pth; npth = 1; /* path component count */ while (1) { -#if ENABLE_PLATFORM_MINGW32 - tmp = (char *)next_path_sep(tmp); -#else - tmp = strchr(tmp, ':'); -#endif + tmp = strchr(tmp, PATH_SEP); if (!tmp) break; tmp++; @@ -815,11 +811,7 @@ static int path_parse(char ***p) res[0] = tmp = xstrdup(pth); npth = 1; while (1) { -#if ENABLE_PLATFORM_MINGW32 - tmp = (char *)next_path_sep(tmp); -#else - tmp = strchr(tmp, ':'); -#endif + tmp = strchr(tmp, PATH_SEP); if (!tmp) break; *tmp++ = '\0'; /* ':' -> '\0' */ diff --git a/miscutils/man.c b/miscutils/man.c index 567323a88..4ff58a9a0 100644 --- a/miscutils/man.c +++ b/miscutils/man.c @@ -199,19 +199,10 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) if (path) while (*path) { char *next_path; char **path_element; -#if ENABLE_PLATFORM_MINGW32 - char save; - - next_path = (char *)next_path_sep(path); -#else - next_path = strchr(path, ':'); -#endif + next_path = strchr(path, PATH_SEP); if (next_path) { if (next_path == path) /* "::"? */ goto next; -#if ENABLE_PLATFORM_MINGW32 - save = *next_path; -#endif *next_path = '\0'; } /* Do we already have path? */ @@ -230,11 +221,7 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) if (!next_path) break; /* "path" may be a result of getenv(), be nice and don't mangle it */ -#if ENABLE_PLATFORM_MINGW32 - *next_path = save; -#else - *next_path = ':'; -#endif + *next_path = PATH_SEP; next: path = next_path + 1; } diff --git a/shell/ash.c b/shell/ash.c index 3bbfbd694..a659fd703 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2422,6 +2422,42 @@ bltinlookup(const char *name) return lookupvar(name); } +#if ENABLE_PLATFORM_MINGW32 +static char * +fix_pathvar(const char *path) +{ + char *newpath = xstrdup(path); + char *p; + int modified = FALSE; + + p = newpath + 5; + while (*p) { + if (*p != ':' && *p != ';') { + /* skip drive */ + if (isalpha(*p) && p[1] == ':') + p += 2; + /* skip through path component */ + for (; *p != '\0' && *p != ':' && *p != ';'; ++p) + continue; + } + /* *p is ':', ';' or '\0' here */ + if (*p == ':') { + *p++ = ';'; + modified = TRUE; + } + else if (*p == ';') { + ++p; + } + } + + if (!modified) { + free(newpath); + newpath = NULL; + } + return newpath; +} +#endif + /* * Same as setvar except that the variable and value are passed in * the first argument as name=value. Since the first argument will @@ -2434,6 +2470,19 @@ setvareq(char *s, int flags) { struct var *vp, **vpp; +#if ENABLE_PLATFORM_MINGW32 + if (strncmp(s, "PATH=", 5) == 0) { + char *newpath = fix_pathvar(s); + if (newpath) { + if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE) + free(s); + flags |= VNOSAVE; + flags &= ~(VTEXTFIXED|VSTACK); + s = newpath; + } + } +#endif + vpp = hashvar(s); flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); vpp = findvar(vpp, s); @@ -2646,18 +2695,8 @@ path_advance(const char **path, const char *name) if (*path == NULL) return NULL; start = *path; -#if ENABLE_PLATFORM_MINGW32 - p = next_path_sep(start); - q = strchr(start, '%'); - if ((p && q && q < p) || (!p && q)) - p = q; - if (!p) - for (p = start; *p; p++) - continue; -#else - for (p = start; *p && *p != ':' && *p != '%'; p++) + for (p = start; *p && *p != PATH_SEP && *p != '%'; p++) continue; -#endif len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ /* reserve space for suffix on WIN32 */ @@ -2672,19 +2711,10 @@ path_advance(const char **path, const char *name) pathopt = NULL; if (*p == '%') { pathopt = ++p; -#if ENABLE_PLATFORM_MINGW32 - p = next_path_sep(start); - - /* *p != ':' and '*' would suffice */ - if (!p) - p = pathopt - 1; -#else - while (*p && *p != ':') + while (*p && *p != PATH_SEP) p++; -#endif } - if (*p == ':' || - (ENABLE_PLATFORM_MINGW32 && *p == ';')) + if (*p == PATH_SEP) *path = p + 1; else *path = NULL; @@ -8733,8 +8763,8 @@ changepath(const char *new) for (;;) { if (*old != *new) { firstchange = idx; - if ((*old == '\0' && *new == ':') - || (*old == ':' && *new == '\0') + if ((*old == '\0' && *new == PATH_SEP) + || (*old == PATH_SEP && *new == '\0') ) { firstchange++; } @@ -8744,7 +8774,7 @@ changepath(const char *new) break; if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) idx_bltin = idx; - if (*new == ':') + if (*new == PATH_SEP) idx++; new++; old++; @@ -10585,7 +10615,13 @@ evalcommand(union node *cmd, int flags) */ p = (*spp)->text; if (varcmp(p, path) == 0) +#if !ENABLE_PLATFORM_MINGW32 path = p; +#else + /* fix_pathvar may have modified the value of the local + * variable so we look it up again */ + path = vpath.var_text; +#endif } /* Print the command if xflag is set. */ diff --git a/win32/process.c b/win32/process.c index 60fea01ad..37496db7b 100644 --- a/win32/process.c +++ b/win32/process.c @@ -24,26 +24,6 @@ int waitpid(pid_t pid, int *status, int options) return -1; } -const char * -next_path_sep(const char *path) -{ - static const char *from = NULL, *to; - static int has_semicolon; - int len = strlen(path); - - if (!from || !(path >= from && path+len <= to)) { - from = path; - to = from+len; - has_semicolon = strchr(path, ';') != NULL; - } - - /* Semicolons take precedence, it's Windows PATH */ - if (has_semicolon) - return strchr(path, ';'); - /* PATH=C:, not really a separator */ - return strchr(has_dos_drive_prefix(path) ? path+2 : path, ':'); -} - typedef struct { char *path; char *name; -- cgit v1.2.3-55-g6feb