diff --git a/CHANGELOG.md b/CHANGELOG.md index 2099494a0..c50fb0da1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ This section is for changes merged to the `major` branch that are not also merge - Wrapping completions (from `complete -w` or `function -w`) can now inject arguments. For example, `complete gco -w 'git checkout'` now works properly (#1976). The `alias` function has been updated to respect this behavior. - The `jobs` builtin now has a `-q` and `--quiet` option to silence the output. - fish now supports `&&`, `||`, and `!` (#4620). +- The machine hostname, where available, is now exposed as `$hostname` which is now a reserved variable. This drops the dependency on the `hostname` executable (#4422). ## Other significant changes - Command substitution output is now limited to 10 MB by default (#3822). diff --git a/README.md b/README.md index b2469aa54..e01f4d1c0 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,6 @@ Running fish requires: * `awk` * `find` * `grep` - * `hostname` * `kill` * `ps` * `sed` diff --git a/share/functions/prompt_hostname.fish b/share/functions/prompt_hostname.fish index 4348bce21..4a068d1d5 100644 --- a/share/functions/prompt_hostname.fish +++ b/share/functions/prompt_hostname.fish @@ -1,10 +1,3 @@ -# Fetching the host name can be expensive if there is a problem with DNS or whatever subsystem the -# hostname command uses. So cache the answer so including it in the prompt doesn't make fish seem -# slow. -if not set -q __fish_prompt_hostname - set -g __fish_prompt_hostname (hostname | string split '.')[1] -end - function prompt_hostname - echo $__fish_prompt_hostname + echo $hostname; end diff --git a/src/env.cpp b/src/env.cpp index fc11bcbd5..f80efdd6d 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -322,7 +322,7 @@ bool string_set_contains(const T &set, const wchar_t *val) { /// Check if a variable may not be set using the set command. static bool is_read_only(const wchar_t *val) { - const string_set_t env_read_only = {L"PWD", L"SHLVL", L"_", L"history", L"status", L"version", L"pid"}; + const string_set_t env_read_only = {L"PWD", L"SHLVL", L"_", L"history", L"status", L"version", L"pid", L"hostname"}; return string_set_contains(env_read_only, val); } @@ -972,6 +972,11 @@ void env_init(const struct config_paths_t *paths /* or NULL */) { // Set the $pid variable (%self replacement) env_set_one(L"pid", ENV_GLOBAL, to_string(getpid())); + // Set the $hostname variable + wcstring hostname = L"fish"; + get_hostname_identifier(hostname); + env_set_one(L"hostname", ENV_GLOBAL, hostname); + // Set up SHLVL variable. Not we can't use env_get because SHLVL is read-only, and therefore was // not inherited from the environment. wcstring nshlvl_str = L"1"; diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index 5a90b0a5d..758c16725 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -44,6 +44,7 @@ #include "utf8.h" #include "util.h" // IWYU pragma: keep #include "wutil.h" +#include "wcstringutil.h" #if __APPLE__ #define FISH_NOTIFYD_AVAILABLE 1 @@ -76,7 +77,6 @@ "changes will be overwritten.\n" static wcstring get_machine_identifier(); -static bool get_hostname_identifier(wcstring *result); static wcstring vars_filename_in_directory(const wcstring &wdir) { if (wdir.empty()) return L""; @@ -495,7 +495,7 @@ bool env_universal_t::load(callback_data_list_t &callbacks) { // Silently "upgraded." tried_renaming = true; wcstring hostname_id; - if (get_hostname_identifier(&hostname_id)) { + if (get_hostname_identifier(hostname_id)) { const wcstring hostname_path = wdirname(vars_path) + L'/' + hostname_id; if (0 == wrename(hostname_path, vars_path)) { // We renamed - try again. @@ -911,11 +911,14 @@ static bool get_mac_address(unsigned char macaddr[MAC_ADDRESS_MAX_LEN]) { return #endif /// Function to get an identifier based on the hostname. -static bool get_hostname_identifier(wcstring *result) { +bool get_hostname_identifier(wcstring &result) { + //The behavior of gethostname if the buffer size is insufficient differs by implementation and libc version + //Work around this by using a "guaranteed" sufficient buffer size then truncating the result. bool success = false; - char hostname[HOSTNAME_LEN + 1] = {}; - if (gethostname(hostname, HOSTNAME_LEN) == 0) { - result->assign(str2wcstring(hostname)); + char hostname[256] = {}; + if (gethostname(hostname, sizeof(hostname)) == 0) { + result.assign(str2wcstring(hostname)); + result.assign(truncate(result, HOSTNAME_LEN)); success = true; } return success; @@ -931,7 +934,7 @@ wcstring get_machine_identifier() { for (size_t i = 0; i < MAC_ADDRESS_MAX_LEN; i++) { append_format(result, L"%02x", mac_addr[i]); } - } else if (!get_hostname_identifier(&result)) { + } else if (!get_hostname_identifier(result)) { result.assign(L"nohost"); // fallback to a dummy value } return result; diff --git a/src/env_universal_common.h b/src/env_universal_common.h index ed4f6b562..d1521cdd3 100644 --- a/src/env_universal_common.h +++ b/src/env_universal_common.h @@ -28,6 +28,7 @@ struct callback_data_t { typedef std::vector callback_data_list_t; +bool get_hostname_identifier(wcstring &result); /// Class representing universal variables. class env_universal_t { var_table_t vars; // current values