diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index a93d6cb50..42f17cf4e 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -1,7 +1,10 @@ - #include #include +#include +#include +#include + extern "C" { #include } @@ -27,6 +30,22 @@ void setLogType(string lt) } +void checkStoreNotSymlink(Path path) +{ + struct stat st; + while (path.size()) { + if (lstat(path.c_str(), &st)) + throw SysError(format("getting status of `%1%'") % path); + if (S_ISLNK(st.st_mode)) + throw Error(format( + "the path `%1%' is a symlink; " + "this is not allowed for the Nix store and its parent directories") + % path); + path = dirOf(path); + } +} + + /* Initialize and reorder arguments, then call the actual argument processor. */ static void initAndRun(int argc, char * * argv) @@ -39,11 +58,15 @@ static void initAndRun(int argc, char * * argv) } /* Setup Nix paths. */ - nixStore = NIX_STORE_DIR; - nixDataDir = NIX_DATA_DIR; - nixLogDir = NIX_LOG_DIR; - nixStateDir = (string) NIX_STATE_DIR; - nixDBPath = (string) NIX_STATE_DIR + "/db"; + nixStore = canonPath(NIX_STORE_DIR); + nixDataDir = canonPath(NIX_DATA_DIR); + nixLogDir = canonPath(NIX_LOG_DIR); + nixStateDir = canonPath(NIX_STATE_DIR); + nixDBPath = canonPath(NIX_STATE_DIR) + "/db"; + + /* Check that the store directory and its parent are not + symlinks. */ + checkStoreNotSymlink(nixStore); /* Catch SIGINT. */ struct sigaction act, oact; diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 54673c28c..1b0600006 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -60,15 +60,18 @@ extern string thisSystem; is also canonicalised. */ Path absPath(Path path, Path dir = ""); -/* Canonicalise a path (as in realpath(3)). */ +/* Canonicalise a path by removing all `.' or `..' components and + double or trailing slashes. */ Path canonPath(const Path & path); -/* Return the directory part of the given path, i.e., everything - before the final `/'. */ +/* Return the directory part of the given canonical path, i.e., + everything before the final `/'. If the path is the root or an + immediate child thereof (e.g., `/foo'), this means an empty string + is returned. */ Path dirOf(const Path & path); -/* Return the base name of the given path, i.e., everything following - the final `/'. */ +/* Return the base name of the given canonical path, i.e., everything + following the final `/'. */ string baseNameOf(const Path & path); /* Return true iff the given path exists. */