From 548ec7045bc7c80eaf03e92f390d1da2c9e9cd86 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 28 Mar 2019 12:52:44 +0000 Subject: win32: interpret absolute paths as relative to %SYSTEMDRIVE% BusyBox contains hardcoded references to absolute paths which are unique in the *nix world but on Microsoft Windows are interpreted as being on the current drive. To make these unique again consider them to be relative to %SYSTEMDRIVE%. Support this by adding functions to: - determine the system drive (not using the environment variable); - change a process's current directory to the root of the system drive; - make relative paths absolute before changing directory (if needed). The following applications have been modified: - ash references /etc/profile from the system drive; - dpkg places its data store on and installs files to the system drive; - rpm installs files to the system drive; - man looks for configuration files and man pages on the system drive. See GitHub issue #158. --- archival/dpkg.c | 24 ++++++++++++++++++++++++ archival/rpm.c | 3 +++ include/mingw.h | 3 +++ miscutils/man.c | 14 +++++++++++++- shell/ash.c | 13 +++++++++++++ win32/mingw.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/archival/dpkg.c b/archival/dpkg.c index 8b25cfd47..08f15ad44 100644 --- a/archival/dpkg.c +++ b/archival/dpkg.c @@ -1752,6 +1752,10 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv) int state_status; int status_num; int i; +#if ENABLE_PLATFORM_MINGW32 + char **ptr, *path; + int fd; +#endif #if ENABLE_LONG_OPTS static const char dpkg_longopts[] ALIGN1 = // FIXME: we use -C non-compatibly, should be: @@ -1796,6 +1800,26 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); } +#if ENABLE_PLATFORM_MINGW32 + if (opt & OPT_install) { + /* add system drive prefix to filenames, if necessary */ + for (ptr = argv; *ptr; ++ptr) { + *ptr = xabsolute_path(*ptr); + } + } + + chdir_system_drive(); + + /* initialise data store */ + path = xstrdup("/var/lib/dpkg/info"); + bb_make_directory(path, -1, FILEUTILS_RECUR); + free(path); + + fd = open("/var/lib/dpkg/status", O_RDWR|O_CREAT, 0666); + if (fd >= 0) + xclose(fd); +#endif + /* puts("(Reading database ... xxxxx files and directories installed.)"); */ index_status_file("/var/lib/dpkg/status"); diff --git a/archival/rpm.c b/archival/rpm.c index 3dd4d4777..c9e8785e2 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -303,6 +303,9 @@ static void extract_cpio(int fd, const char *source_rpm) if (source_rpm != NULL) { /* Binary rpm (it was built from some SRPM), install to root */ +#if ENABLE_PLATFORM_MINGW32 + if (chdir_system_drive()) +#endif xchdir("/"); } /* else: SRPM, install to current dir */ diff --git a/include/mingw.h b/include/mingw.h index 7c9423cad..d77a9beb9 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -525,3 +525,6 @@ void hide_console(void); int unc_root_len(const char *dir); int root_len(const char *path); +char *get_system_drive(void); +int chdir_system_drive(void); +char *xabsolute_path(char *path); diff --git a/miscutils/man.c b/miscutils/man.c index 3c1a79085..0bc11e623 100644 --- a/miscutils/man.c +++ b/miscutils/man.c @@ -253,11 +253,22 @@ int man_main(int argc UNUSED_PARAM, char **argv) int cur_mp; int opt, not_found; char *token[2]; +#if ENABLE_PLATFORM_MINGW32 + char **ptr; +#endif INIT_G(); opt = getopt32(argv, "^+" "aw" "\0" "-1"/*at least one arg*/); argv += optind; +#if ENABLE_PLATFORM_MINGW32 + /* add system drive prefix to filenames, if necessary */ + for (ptr = argv; *ptr; ++ptr) { + if (strchr(*ptr, '/') || strchr(*ptr, '\\')) + *ptr = xabsolute_path(*ptr); + } + chdir_system_drive(); +#endif sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9"); @@ -311,7 +322,8 @@ int man_main(int argc UNUSED_PARAM, char **argv) char *relpath = concat_path_file(dirname(exepath), "man"); if (count_mp == 0) { /* default must match path set above */ - man_path_list = add_MANPATH(man_path_list, &count_mp, "/usr/man"); + man_path_list = add_MANPATH(man_path_list, &count_mp, + (char *)"/usr/man"); } man_path_list = add_MANPATH(man_path_list, &count_mp, relpath); free(relpath); diff --git a/shell/ash.c b/shell/ash.c index 34ddc14f1..40965bafa 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -14906,6 +14906,9 @@ int ash_main(int argc UNUSED_PARAM, char **argv) struct jmploc jmploc; struct stackmark smark; int login_sh; +#if ENABLE_PLATFORM_MINGW32 + char *sd; +#endif /* Initialize global data */ INIT_G_misc(); @@ -15014,6 +15017,16 @@ int ash_main(int argc UNUSED_PARAM, char **argv) #endif state = 1; +#if ENABLE_PLATFORM_MINGW32 + sd = get_system_drive(); + if (sd) { + char *path = xasprintf("%s/etc/profile", sd); + read_profile(path); + free(sd); + free(path); + } + else +#endif read_profile("/etc/profile"); state1: state = 2; diff --git a/win32/mingw.c b/win32/mingw.c index 3ee1a2496..1d5644f92 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -1644,3 +1644,59 @@ int root_len(const char *path) return 2; return unc_root_len(path); } + +char *get_system_drive(void) +{ + struct passwd *pwd; + char *drive = NULL; + int len; + + pwd = getpwuid(0); + if (pwd != NULL && (len=root_len(pwd->pw_dir))) { + drive = xstrdup(pwd->pw_dir); + drive[len] = '\0'; + } + + return drive; +} + +int chdir_system_drive(void) +{ + char *sd = get_system_drive(); + int ret = -1; + + if (sd) { + strcat(sd, "/"); + ret = chdir(sd); + } + free(sd); + return ret; +} + +/* + * This function is used to make relative paths absolute before a call + * to chdir_system_drive(). It's unlikely to be useful in other cases. + * + * If the argument is an absolute path or a relative path which resolves + * to a path on the system drive return 'path'. If it's a relative path + * which resolves to a path that isn't on the system drive return an + * allocated string containing the resolved path. Die on failure, + * which is most likely because the file doesn't exist. + */ +char *xabsolute_path(char *path) +{ + char *rpath, *sd; + + if (root_len(path) != 0) + return path; // absolute path + rpath = xmalloc_realpath(path); + if (rpath) { + sd = auto_string(get_system_drive()); + if (sd && is_prefixed_with_case(rpath, sd)) { + free(rpath); + return path; // resolved path is on system drive + } + return rpath; + } + bb_perror_msg_and_die("can't open '%s'", path); +} -- cgit v1.2.3-55-g6feb