diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2017-05-05T14·40+0200 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2017-05-05T15·08+0200 |
commit | 465cb6824401541d82489e11b5223dbfd50bb132 (patch) | |
tree | 98b112563cbf08c29e94c4ddc0755de95524186f /src | |
parent | eba840c8a13b465ace90172ff76a0db2899ab11b (diff) |
Figure out the user's home directory if $HOME is not set
Diffstat (limited to 'src')
-rw-r--r-- | src/libexpr/parser.y | 2 | ||||
-rw-r--r-- | src/libutil/lazy.hh | 48 | ||||
-rw-r--r-- | src/libutil/util.cc | 45 | ||||
-rw-r--r-- | src/libutil/util.hh | 3 | ||||
-rwxr-xr-x | src/nix-channel/nix-channel.cc | 4 | ||||
-rw-r--r-- | src/nix-env/nix-env.cc | 14 |
6 files changed, 84 insertions, 32 deletions
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index d07eedddaf6b..62982650a22e 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -376,7 +376,7 @@ expr_simple $$ = stripIndentation(CUR_POS, data->symbols, *$2); } | PATH { $$ = new ExprPath(absPath($1, data->basePath)); } - | HPATH { $$ = new ExprPath(getEnv("HOME", "") + string{$1 + 1}); } + | HPATH { $$ = new ExprPath(getHome() + string{$1 + 1}); } | SPATH { string path($1 + 1, strlen($1) - 2); $$ = new ExprApp(CUR_POS, diff --git a/src/libutil/lazy.hh b/src/libutil/lazy.hh new file mode 100644 index 000000000000..d073e486c2eb --- /dev/null +++ b/src/libutil/lazy.hh @@ -0,0 +1,48 @@ +#include <exception> +#include <functional> +#include <mutex> + +namespace nix { + +/* A helper class for lazily-initialized variables. + + Lazy<T> var([]() { return value; }); + + declares a variable of type T that is initialized to 'value' (in a + thread-safe way) on first use, that is, when var() is first + called. If the initialiser code throws an exception, then all + subsequent calls to var() will rethrow that exception. */ +template<typename T> +class Lazy +{ + + typedef std::function<T()> Init; + + Init init; + + std::once_flag done; + + T value; + + std::exception_ptr ex; + +public: + + Lazy(Init init) : init(init) + { } + + const T & operator () () + { + std::call_once(done, [&]() { + try { + value = init(); + } catch (...) { + ex = std::current_exception(); + } + }); + if (ex) std::rethrow_exception(ex); + return value; + } +}; + +} diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 98c0aff1e722..1d1f68fc8452 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1,3 +1,4 @@ +#include "lazy.hh" #include "util.hh" #include "affinity.hh" #include "sync.hh" @@ -13,10 +14,12 @@ #include <thread> #include <future> -#include <sys/wait.h> -#include <unistd.h> #include <fcntl.h> #include <limits.h> +#include <pwd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> #ifdef __APPLE__ #include <sys/syscall.h> @@ -417,14 +420,28 @@ Path createTempDir(const Path & tmpRoot, const Path & prefix, } +static Lazy<Path> getHome2([]() { + Path homeDir = getEnv("HOME"); + if (homeDir.empty()) { + char buf[16384]; + struct passwd pwbuf; + struct passwd * pw; + if (getpwuid_r(getuid(), &pwbuf, buf, sizeof(buf), &pw) != 0 + || !pw || !pw->pw_dir || !pw->pw_dir[0]) + throw Error("cannot determine user's home directory"); + homeDir = pw->pw_dir; + } + return homeDir; +}); + +Path getHome() { return getHome2(); } + + Path getCacheDir() { Path cacheDir = getEnv("XDG_CACHE_HOME"); - if (cacheDir.empty()) { - Path homeDir = getEnv("HOME"); - if (homeDir.empty()) throw Error("$XDG_CACHE_HOME and $HOME are not set"); - cacheDir = homeDir + "/.cache"; - } + if (cacheDir.empty()) + cacheDir = getHome() + "/.cache"; return cacheDir; } @@ -432,11 +449,8 @@ Path getCacheDir() Path getConfigDir() { Path configDir = getEnv("XDG_CONFIG_HOME"); - if (configDir.empty()) { - Path homeDir = getEnv("HOME"); - if (homeDir.empty()) throw Error("$XDG_CONFIG_HOME and $HOME are not set"); - configDir = homeDir + "/.config"; - } + if (configDir.empty()) + configDir = getHome() + "/.config"; return configDir; } @@ -444,11 +458,8 @@ Path getConfigDir() Path getDataDir() { Path dataDir = getEnv("XDG_DATA_HOME"); - if (dataDir.empty()) { - Path homeDir = getEnv("HOME"); - if (homeDir.empty()) throw Error("$XDG_DATA_HOME and $HOME are not set"); - dataDir = homeDir + "/.local/share"; - } + if (dataDir.empty()) + dataDir = getHome() + "/.local/share"; return dataDir; } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index a9950f830c50..5a9c9513fd5c 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -110,6 +110,9 @@ void deletePath(const Path & path, unsigned long long & bytesFreed); Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix", bool includePid = true, bool useGlobalCounter = true, mode_t mode = 0755); +/* Return $HOME or the user's home directory from /etc/passwd. */ +Path getHome(); + /* Return $XDG_CACHE_HOME or $HOME/.cache. */ Path getCacheDir(); diff --git a/src/nix-channel/nix-channel.cc b/src/nix-channel/nix-channel.cc index 0f50f6242c48..2aaae2f471b9 100755 --- a/src/nix-channel/nix-channel.cc +++ b/src/nix-channel/nix-channel.cc @@ -169,9 +169,7 @@ int main(int argc, char ** argv) setenv("NIX_DOWNLOAD_CACHE", channelCache.c_str(), 1); // Figure out the name of the `.nix-channels' file to use - auto home = getEnv("HOME"); - if (home.empty()) - throw Error("$HOME not set"); + auto home = getHome(); channelsList = home + "/.nix-channels"; nixDefExpr = home + "/.nix-defexpr"; diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 908c09bc8c8a..da39bf36ab65 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -192,17 +192,9 @@ static void loadDerivations(EvalState & state, Path nixExprPath, } -static Path getHomeDir() -{ - Path homeDir(getEnv("HOME", "")); - if (homeDir == "") throw Error("HOME environment variable not set"); - return homeDir; -} - - static Path getDefNixExprPath() { - return getHomeDir() + "/.nix-defexpr"; + return getHome() + "/.nix-defexpr"; } @@ -1188,7 +1180,7 @@ static void opSwitchProfile(Globals & globals, Strings opFlags, Strings opArgs) throw UsageError(format("exactly one argument expected")); Path profile = absPath(opArgs.front()); - Path profileLink = getHomeDir() + "/.nix-profile"; + Path profileLink = getHome() + "/.nix-profile"; switchLink(profileLink, profile); } @@ -1413,7 +1405,7 @@ int main(int argc, char * * argv) globals.profile = getEnv("NIX_PROFILE", ""); if (globals.profile == "") { - Path profileLink = getHomeDir() + "/.nix-profile"; + Path profileLink = getHome() + "/.nix-profile"; globals.profile = pathExists(profileLink) ? absPath(readLink(profileLink), dirOf(profileLink)) : canonPath(settings.nixStateDir + "/profiles/default"); |