From 19efd22468a9a7fe1fea49000e2aa956972b8b0b Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 11 Jan 2021 18:49:15 +0100 Subject: [PATCH] env: Setup $HOME/$USER *before* the config directories They are based on $HOME, so setting $HOME has to be done first. Fixes #7620 (untested because I'm assuming common CI systems have weird $HOME settings) --- CHANGELOG.rst | 1 + src/env.cpp | 82 ++++++++++++++++++++++++++------------------------- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 463f5e0e9..865228538 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -112,6 +112,7 @@ Scripting improvements - ``functions`` now explains when a function was defined via ``source`` instead of just saying ``Defined in -``. - Significant performance improvements when globbing or in ``math``. - ``echo`` no longer interprets options at the beginning of an argument (``echo "-n foo"``) (:issue:`7614`). +- Fish now better handles an unset $HOME (:issue:`7620`). Interactive improvements ------------------------ diff --git a/src/env.cpp b/src/env.cpp index 99fd3c7ca..ff13b6273 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -273,17 +273,6 @@ void env_init(const struct config_paths_t *paths /* or NULL */) { vars.set_one(FISH_BIN_DIR, ENV_GLOBAL, paths->bin); } - wcstring user_config_dir; - path_get_config(user_config_dir); - vars.set_one(FISH_CONFIG_DIR, ENV_GLOBAL, user_config_dir); - - wcstring user_data_dir; - path_get_data(user_data_dir); - vars.set_one(FISH_USER_DATA_DIR, ENV_GLOBAL, user_data_dir); - - // Set up the USER and PATH variables - setup_path(); - // Some `su`s keep $USER when changing to root. // This leads to issues later on (and e.g. in prompts), // so we work around it by resetting $USER. @@ -292,40 +281,13 @@ void env_init(const struct config_paths_t *paths /* or NULL */) { uid_t uid = getuid(); setup_user(uid == 0); - // Set up $IFS - this used to be in share/config.fish, but really breaks if it isn't done. - vars.set_one(L"IFS", ENV_GLOBAL, L"\n \t"); - - // Set up the version variable. - wcstring version = str2wcstring(get_fish_version()); - vars.set_one(L"version", ENV_GLOBAL, version); - vars.set_one(L"FISH_VERSION", ENV_GLOBAL, version); - - // Set the $fish_pid variable. - vars.set_one(L"fish_pid", ENV_GLOBAL, to_string(getpid())); - - // Set the $hostname variable - wcstring hostname = L"fish"; - get_hostname_identifier(hostname); - vars.set_one(L"hostname", ENV_GLOBAL, hostname); - - // Set up SHLVL variable. Not we can't use vars.get() because SHLVL is read-only, and therefore - // was not inherited from the environment. - wcstring nshlvl_str = L"1"; - if (const char *shlvl_var = getenv("SHLVL")) { - const wchar_t *end; - // TODO: Figure out how to handle invalid numbers better. Shouldn't we issue a diagnostic? - long shlvl_i = fish_wcstol(str2wcstring(shlvl_var).c_str(), &end); - if (!errno && shlvl_i >= 0) { - nshlvl_str = to_string(shlvl_i + 1); - } - } - vars.set_one(L"SHLVL", ENV_GLOBAL | ENV_EXPORT, nshlvl_str); - // Set up the HOME variable. // Unlike $USER, it doesn't seem that `su`s pass this along // if the target user is root, unless "--preserve-environment" is used. // Since that is an explicit choice, we should allow it to enable e.g. // env HOME=(mktemp -d) su --preserve-environment fish + // + // Note: This needs to be *before* path_get_*, because that uses $HOME! if (vars.get(L"HOME").missing_or_empty()) { auto user_var = vars.get(L"USER"); if (!user_var.missing_or_empty()) { @@ -357,6 +319,46 @@ void env_init(const struct config_paths_t *paths /* or NULL */) { } } + wcstring user_config_dir; + path_get_config(user_config_dir); + vars.set_one(FISH_CONFIG_DIR, ENV_GLOBAL, user_config_dir); + + wcstring user_data_dir; + path_get_data(user_data_dir); + vars.set_one(FISH_USER_DATA_DIR, ENV_GLOBAL, user_data_dir); + + // Set up a default PATH + setup_path(); + + // Set up $IFS - this used to be in share/config.fish, but really breaks if it isn't done. + vars.set_one(L"IFS", ENV_GLOBAL, L"\n \t"); + + // Set up the version variable. + wcstring version = str2wcstring(get_fish_version()); + vars.set_one(L"version", ENV_GLOBAL, version); + vars.set_one(L"FISH_VERSION", ENV_GLOBAL, version); + + // Set the $fish_pid variable. + vars.set_one(L"fish_pid", ENV_GLOBAL, to_string(getpid())); + + // Set the $hostname variable + wcstring hostname = L"fish"; + get_hostname_identifier(hostname); + vars.set_one(L"hostname", ENV_GLOBAL, hostname); + + // Set up SHLVL variable. Not we can't use vars.get() because SHLVL is read-only, and therefore + // was not inherited from the environment. + wcstring nshlvl_str = L"1"; + if (const char *shlvl_var = getenv("SHLVL")) { + const wchar_t *end; + // TODO: Figure out how to handle invalid numbers better. Shouldn't we issue a diagnostic? + long shlvl_i = fish_wcstol(str2wcstring(shlvl_var).c_str(), &end); + if (!errno && shlvl_i >= 0) { + nshlvl_str = to_string(shlvl_i + 1); + } + } + vars.set_one(L"SHLVL", ENV_GLOBAL | ENV_EXPORT, nshlvl_str); + // initialize the PWD variable if necessary // Note we may inherit a virtual PWD that doesn't match what getcwd would return; respect that // if and only if it matches getcwd (#5647). Note we treat PWD as read-only so it was not set in