diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 02aa5a272..49865aa90 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -31,6 +31,7 @@ #include "print.hh" #include "progress-bar.hh" #include "gc-small-vector.hh" +#include "users.hh" #if HAVE_BOEHMGC #define GC_INCLUDE_NEW diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index 5969ee449..90fbfa308 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -1,8 +1,8 @@ #include "eval-cache.hh" #include "sqlite.hh" #include "eval.hh" -#include "eval-inline.hh" #include "store-api.hh" +#include "users.hh" namespace nix::eval_cache { diff --git a/src/libexpr/eval-settings.cc b/src/libexpr/eval-settings.cc index 046ca557d..105fd3e9d 100644 --- a/src/libexpr/eval-settings.cc +++ b/src/libexpr/eval-settings.cc @@ -1,6 +1,7 @@ +#include "file-system.hh" #include "globals.hh" #include "profiles.hh" -#include "eval.hh" +#include "users.hh" #include "eval-settings.hh" namespace nix { diff --git a/src/libexpr/flake/config.cc b/src/libexpr/flake/config.cc index b9613462a..35c605de2 100644 --- a/src/libexpr/flake/config.cc +++ b/src/libexpr/flake/config.cc @@ -1,5 +1,5 @@ #include "flake.hh" -#include "globals.hh" +#include "users.hh" #include "fetch-settings.hh" #include diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 5424d8741..91cc7d089 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -19,7 +19,7 @@ #include #include "finally.hh" -#include "util.hh" +#include "users.hh" #include "nixexpr.hh" #include "eval.hh" diff --git a/src/libfetchers/cache.cc b/src/libfetchers/cache.cc index 672e1e0bc..eec77c2dc 100644 --- a/src/libfetchers/cache.cc +++ b/src/libfetchers/cache.cc @@ -2,6 +2,7 @@ #include "sqlite.hh" #include "sync.hh" #include "store-api.hh" +#include "users.hh" #include diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 86d9d437f..07cbc781c 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -6,7 +6,7 @@ #include "store-api.hh" #include "url-parts.hh" #include "pathlocks.hh" -#include "util.hh" +#include "users.hh" #include "git.hh" #include "logging.hh" #include "finally.hh" diff --git a/src/libfetchers/mercurial.cc b/src/libfetchers/mercurial.cc index 086db498f..4fffa71d3 100644 --- a/src/libfetchers/mercurial.cc +++ b/src/libfetchers/mercurial.cc @@ -3,6 +3,7 @@ #include "processes.hh" #include "store-api.hh" #include "url-parts.hh" +#include "users.hh" #include "fetch-settings.hh" diff --git a/src/libfetchers/registry.cc b/src/libfetchers/registry.cc index 4b2d61f52..96e9ed1c6 100644 --- a/src/libfetchers/registry.cc +++ b/src/libfetchers/registry.cc @@ -1,6 +1,6 @@ #include "registry.hh" #include "fetchers.hh" -#include "util.hh" +#include "users.hh" #include "globals.hh" #include "store-api.hh" #include "local-fs-store.hh" diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 30fd4e9e3..8ef25c469 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -1,6 +1,6 @@ #include "environment-variables.hh" #include "globals.hh" -#include "util.hh" +#include "users.hh" #include "archive.hh" #include "args.hh" #include "abstract-setting-to-json.hh" diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc index c7176d30f..0413abbf1 100644 --- a/src/libstore/nar-info-disk-cache.cc +++ b/src/libstore/nar-info-disk-cache.cc @@ -2,6 +2,7 @@ #include "sync.hh" #include "sqlite.hh" #include "globals.hh" +#include "users.hh" #include #include diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc index 239047dd6..e8b88693d 100644 --- a/src/libstore/profiles.cc +++ b/src/libstore/profiles.cc @@ -1,7 +1,7 @@ #include "profiles.hh" #include "store-api.hh" #include "local-fs-store.hh" -#include "util.hh" +#include "users.hh" #include #include diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index ed3566f5e..c5631dfd8 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -14,6 +14,7 @@ // FIXME this should not be here, see TODO below on // `addMultipleToStore`. #include "worker-protocol.hh" +#include "users.hh" #include #include diff --git a/src/libutil/file-system.cc b/src/libutil/file-system.cc index 9804c449c..721bf97e2 100644 --- a/src/libutil/file-system.cc +++ b/src/libutil/file-system.cc @@ -9,6 +9,7 @@ #include "serialise.hh" #include "signals.hh" #include "types.hh" +#include "users.hh" namespace fs = std::filesystem; diff --git a/src/libutil/meson.build b/src/libutil/meson.build index b662ea455..5e767b447 100644 --- a/src/libutil/meson.build +++ b/src/libutil/meson.build @@ -39,6 +39,7 @@ libutil_sources = files( 'unix-domain-socket.cc', 'url.cc', 'url-name.cc', + 'users.cc', 'util.cc', 'xml-writer.cc', ) @@ -109,6 +110,7 @@ libutil_headers = files( 'url-parts.hh', 'url-name.hh', 'url.hh', + 'users.hh', 'util.hh', 'variant-wrapper.hh', 'xml-writer.hh', diff --git a/src/libutil/users.cc b/src/libutil/users.cc new file mode 100644 index 000000000..a9a8a7353 --- /dev/null +++ b/src/libutil/users.cc @@ -0,0 +1,105 @@ +#include "environment-variables.hh" +#include "file-system.hh" +#include "logging.hh" +#include "strings.hh" + +#include +#include +#include + +namespace nix { + +std::string getUserName() +{ + auto pw = getpwuid(geteuid()); + std::string name = pw ? pw->pw_name : getEnv("USER").value_or(""); + if (name.empty()) + throw Error("cannot figure out user name"); + return name; +} + +Path getHomeOf(uid_t userId) +{ + std::vector buf(16384); + struct passwd pwbuf; + struct passwd * pw; + if (getpwuid_r(userId, &pwbuf, buf.data(), buf.size(), &pw) != 0 + || !pw || !pw->pw_dir || !pw->pw_dir[0]) + throw Error("cannot determine user's home directory"); + return pw->pw_dir; +} + +Path getHome() +{ + static Path homeDir = []() + { + std::optional unownedUserHomeDir = {}; + auto homeDir = getEnv("HOME"); + if (homeDir) { + // Only use $HOME if doesn't exist or is owned by the current user. + struct stat st; + int result = stat(homeDir->c_str(), &st); + if (result != 0) { + if (errno != ENOENT) { + warn("couldn't stat $HOME ('%s') for reason other than not existing ('%d'), falling back to the one defined in the 'passwd' file", *homeDir, errno); + homeDir.reset(); + } + } else if (st.st_uid != geteuid()) { + unownedUserHomeDir.swap(homeDir); + } + } + if (!homeDir) { + homeDir = getHomeOf(geteuid()); + if (unownedUserHomeDir.has_value() && unownedUserHomeDir != homeDir) { + warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file ('%s')", *unownedUserHomeDir, *homeDir); + } + } + return *homeDir; + }(); + return homeDir; +} + + +Path getCacheDir() +{ + auto cacheDir = getEnv("XDG_CACHE_HOME"); + return cacheDir ? *cacheDir : getHome() + "/.cache"; +} + + +Path getConfigDir() +{ + auto configDir = getEnv("XDG_CONFIG_HOME"); + return configDir ? *configDir : getHome() + "/.config"; +} + +std::vector getConfigDirs() +{ + Path configHome = getConfigDir(); + auto configDirs = getEnv("XDG_CONFIG_DIRS").value_or("/etc/xdg"); + std::vector result = tokenizeString>(configDirs, ":"); + result.insert(result.begin(), configHome); + return result; +} + + +Path getDataDir() +{ + auto dataDir = getEnv("XDG_DATA_HOME"); + return dataDir ? *dataDir : getHome() + "/.local/share"; +} + +Path getStateDir() +{ + auto stateDir = getEnv("XDG_STATE_HOME"); + return stateDir ? *stateDir : getHome() + "/.local/state"; +} + +Path createNixStateDir() +{ + Path dir = getStateDir() + "/nix"; + createDirs(dir); + return dir; +} + +} diff --git a/src/libutil/users.hh b/src/libutil/users.hh new file mode 100644 index 000000000..3add4c732 --- /dev/null +++ b/src/libutil/users.hh @@ -0,0 +1,61 @@ +#pragma once +///@file + +#include "types.hh" + +#include + +namespace nix { + +std::string getUserName(); + +/** + * @return the given user's home directory from /etc/passwd. + */ +Path getHomeOf(uid_t userId); + +/** + * @return $HOME or the user's home directory from /etc/passwd. + */ +Path getHome(); + +/** + * @return $XDG_CACHE_HOME or $HOME/.cache. + */ +Path getCacheDir(); + +/** + * @return $XDG_CONFIG_HOME or $HOME/.config. + */ +Path getConfigDir(); + +/** + * @return the directories to search for user configuration files + */ +std::vector getConfigDirs(); + +/** + * @return $XDG_DATA_HOME or $HOME/.local/share. + */ +Path getDataDir(); + +/** + * @return $XDG_STATE_HOME or $HOME/.local/state. + * + * @note Not to be confused with settings.nixStateDir. + */ +Path getStateDir(); + +/** + * Create $XDG_STATE_HOME/nix or $HOME/.local/state/nix, and return + * the path to it. + * @note Not to be confused with settings.nixStateDir. + */ +Path createNixStateDir(); + +/** + * Perform tilde expansion on a path. + */ +std::string expandTilde(std::string_view path); + +} diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 099a07622..8e813abc2 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -56,103 +56,6 @@ namespace nix { -std::string getUserName() -{ - auto pw = getpwuid(geteuid()); - std::string name = pw ? pw->pw_name : getEnv("USER").value_or(""); - if (name.empty()) - throw Error("cannot figure out user name"); - return name; -} - -Path getHomeOf(uid_t userId) -{ - std::vector buf(16384); - struct passwd pwbuf; - struct passwd * pw; - if (getpwuid_r(userId, &pwbuf, buf.data(), buf.size(), &pw) != 0 - || !pw || !pw->pw_dir || !pw->pw_dir[0]) - throw Error("cannot determine user's home directory"); - return pw->pw_dir; -} - -Path getHome() -{ - static Path homeDir = []() - { - std::optional unownedUserHomeDir = {}; - auto homeDir = getEnv("HOME"); - if (homeDir) { - // Only use $HOME if doesn't exist or is owned by the current user. - struct stat st; - int result = stat(homeDir->c_str(), &st); - if (result != 0) { - if (errno != ENOENT) { - warn("couldn't stat $HOME ('%s') for reason other than not existing ('%d'), falling back to the one defined in the 'passwd' file", *homeDir, errno); - homeDir.reset(); - } - } else if (st.st_uid != geteuid()) { - unownedUserHomeDir.swap(homeDir); - } - } - if (!homeDir) { - homeDir = getHomeOf(geteuid()); - if (unownedUserHomeDir.has_value() && unownedUserHomeDir != homeDir) { - warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file ('%s')", *unownedUserHomeDir, *homeDir); - } - } - return *homeDir; - }(); - return homeDir; -} - - -Path getCacheDir() -{ - auto cacheDir = getEnv("XDG_CACHE_HOME"); - return cacheDir ? *cacheDir : getHome() + "/.cache"; -} - - -Path getConfigDir() -{ - auto configDir = getEnv("XDG_CONFIG_HOME"); - return configDir ? *configDir : getHome() + "/.config"; -} - -std::vector getConfigDirs() -{ - Path configHome = getConfigDir(); - auto configDirs = getEnv("XDG_CONFIG_DIRS").value_or("/etc/xdg"); - std::vector result = tokenizeString>(configDirs, ":"); - result.insert(result.begin(), configHome); - return result; -} - - -Path getDataDir() -{ - auto dataDir = getEnv("XDG_DATA_HOME"); - return dataDir ? *dataDir : getHome() + "/.local/share"; -} - -Path getStateDir() -{ - auto stateDir = getEnv("XDG_STATE_HOME"); - return stateDir ? *stateDir : getHome() + "/.local/state"; -} - -Path createNixStateDir() -{ - Path dir = getStateDir() + "/nix"; - createDirs(dir); - return dir; -} - - - - - ////////////////////////////////////////////////////////////////////// diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 907bdf4ed..e408821b9 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -39,53 +39,6 @@ struct Source; extern const std::string nativeSystem; -std::string getUserName(); - -/** - * @return the given user's home directory from /etc/passwd. - */ -Path getHomeOf(uid_t userId); - -/** - * @return $HOME or the user's home directory from /etc/passwd. - */ -Path getHome(); - -/** - * @return $XDG_CACHE_HOME or $HOME/.cache. - */ -Path getCacheDir(); - -/** - * @return $XDG_CONFIG_HOME or $HOME/.config. - */ -Path getConfigDir(); - -/** - * @return the directories to search for user configuration files - */ -std::vector getConfigDirs(); - -/** - * @return $XDG_DATA_HOME or $HOME/.local/share. - */ -Path getDataDir(); - -/** - * @return $XDG_STATE_HOME or $HOME/.local/state. - * - * @note Not to be confused with settings.nixStateDir. - */ -Path getStateDir(); - -/** - * Create $XDG_STATE_HOME/nix or $HOME/.local/state/nix, and return - * the path to it. - * @note Not to be confused with settings.nixStateDir. - */ -Path createNixStateDir(); - - /** * Save the current mount namespace. Ignored if called more than * once. diff --git a/src/nix-channel/nix-channel.cc b/src/nix-channel/nix-channel.cc index 26003f021..971337b63 100644 --- a/src/nix-channel/nix-channel.cc +++ b/src/nix-channel/nix-channel.cc @@ -6,7 +6,7 @@ #include "legacy.hh" #include "fetchers.hh" #include "eval-settings.hh" // for defexpr -#include "util.hh" +#include "users.hh" #include #include diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index ad255a1e1..227a3331c 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -11,7 +11,7 @@ #include "store-api.hh" #include "local-fs-store.hh" #include "user-env.hh" -#include "util.hh" +#include "users.hh" #include "value-to-json.hh" #include "xml-writer.hh" #include "legacy.hh"