eldritch horrors
b0d7a81613
clangd broke because it can't look through symlinks. compile_commands
manipulation does not fix it, clangd configuration does not fix it, a
vfs overlay does not fix it, and while a combination of those can fix
it with a bind mount in place that's just too cursed to even consider
clangd bug: https://github.com/llvm/llvm-project/issues/116877
Change-Id: I8e3e8489548eb3a7aa65ac9d12a5ec8abf814aec
106 lines
2.8 KiB
C++
106 lines
2.8 KiB
C++
#include "lix/libutil/environment-variables.hh"
|
|
#include "lix/libutil/file-system.hh"
|
|
#include "lix/libutil/logging.hh"
|
|
#include "lix/libutil/strings.hh"
|
|
|
|
#include <pwd.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
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<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");
|
|
return pw->pw_dir;
|
|
}
|
|
|
|
Path getHome()
|
|
{
|
|
static Path homeDir = []()
|
|
{
|
|
std::optional<std::string> unownedUserHomeDir = {};
|
|
auto homeDir = getEnv("HOME");
|
|
if (homeDir) {
|
|
// Only use `$HOME` if it exists and 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<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);
|
|
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;
|
|
}
|
|
|
|
}
|