#include "util.hh" #include "users.hh" #include "environment-variables.hh" #include "file-system.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; } std::string expandTilde(std::string_view path) { // TODO: expand ~user ? auto tilde = path.substr(0, 2); if (tilde == "~/" || tilde == "~") return getHome() + std::string(path.substr(1)); else return std::string(path); } }