libutil: add tryGetHome that doesn't throw on errors

Change-Id: Ib5bcb277e39093b303fe4a66a8903a7c5692f305
This commit is contained in:
eldritch horrors
2026-01-27 17:13:07 +01:00
parent e083a68a9f
commit ef8a6cc5f5
2 changed files with 25 additions and 15 deletions
+23 -13
View File
@@ -19,21 +19,21 @@ std::string getUserName()
return name;
}
Path getHomeOf(uid_t userId)
static std::optional<Path> tryGetHomeOf(uid_t userId)
{
std::vector<char> 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");
if (getpwuid_r(userId, &pwbuf, buf.data(), buf.size(), &pw) != 0 || !pw || !pw->pw_dir || !pw->pw_dir[0])
{
return std::nullopt;
}
return pw->pw_dir;
}
Path getHome()
{
static Path homeDir = []()
std::optional<Path> tryGetHome()
{
static std::optional<Path> homeDir = []() {
std::optional<std::string> unownedUserHomeDir = {};
auto homeDir = getEnv("HOME");
if (homeDir) {
@@ -55,8 +55,8 @@ Path getHome()
}
}
if (!homeDir) {
homeDir = getHomeOf(geteuid());
if (unownedUserHomeDir.has_value() && unownedUserHomeDir != homeDir) {
homeDir = tryGetHomeOf(geteuid());
if (homeDir && unownedUserHomeDir && unownedUserHomeDir != homeDir) {
printTaggedWarning(
"$HOME ('%s') is not owned by you, falling back to the one defined in the "
"'passwd' file ('%s')",
@@ -65,11 +65,19 @@ Path getHome()
);
}
}
return *homeDir;
return homeDir;
}();
return homeDir;
}
Path getHome()
{
if (auto home = tryGetHome()) {
return std::move(*home);
} else {
throw Error("cannot determine user's home directory");
}
}
Path getCacheDir()
{
@@ -102,14 +110,16 @@ Path getConfigDir()
std::vector<Path> getConfigDirs()
{
Path configHome = getConfigDir();
auto configDirs = getEnv("XDG_CONFIG_DIRS").value_or("/etc/xdg");
std::vector<Path> result = tokenizeString<std::vector<std::string>>(configDirs, ":");
result.insert(result.begin(), configHome);
if (auto configHome = getEnv("XDG_CONFIG_HOME")) {
result.insert(result.begin(), *configHome);
} else if (auto userHome = tryGetHome()) {
result.insert(result.begin(), *userHome + "/.config");
}
return result;
}
Path getDataDir()
{
auto dataDir = getEnv("XDG_DATA_HOME");
+2 -2
View File
@@ -10,9 +10,9 @@ namespace nix {
std::string getUserName();
/**
* @return the given user's home directory from /etc/passwd.
* @return $HOME or the user's home directory from /etc/passwd, if available.
*/
Path getHomeOf(uid_t userId);
std::optional<Path> tryGetHome();
/**
* @return $HOME or the user's home directory from /etc/passwd.