summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libmain/shared.cc35
-rw-r--r--src/libutil/util.hh13
2 files changed, 37 insertions, 11 deletions
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index a93d6cb501..42f17cf4ed 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -1,7 +1,10 @@
-
 #include <iostream>
 #include <cctype>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
 extern "C" {
 #include <aterm2.h>
 }
@@ -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 54673c28c6..1b0600006a 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. */