about summary refs log tree commit diff
path: root/src/libstore/gc.cc
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-07-12T12·01+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-07-12T12·03+0200
commitaeb810b01e17d040f9592681ee271f15874dce50 (patch)
treefbf5e93aeb43f6b900f4c813ea5655385b041bdf /src/libstore/gc.cc
parent25a00cae5bf702b9e844b05923a9c59de9df6788 (diff)
Garbage collector: Don't follow symlinks arbitrarily
Only indirect roots (symlinks to symlinks to the Nix store) are now
supported.
Diffstat (limited to 'src/libstore/gc.cc')
-rw-r--r--src/libstore/gc.cc80
1 files changed, 39 insertions, 41 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 5c5c07e4c481..37ca6be4b836 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -258,8 +258,7 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
            only succeed if the owning process has died.  In that case
            we don't care about its temporary roots. */
         if (lockFile(*fd, ltWrite, false)) {
-            printMsg(lvlError, format("removing stale temporary roots file `%1%'")
-                % path);
+            printMsg(lvlError, format("removing stale temporary roots file `%1%'") % path);
             unlink(path.c_str());
             writeFull(*fd, (const unsigned char *) "d", 1);
             continue;
@@ -290,46 +289,47 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
 }
 
 
-static void findRoots(StoreAPI & store, const Path & path,
-    bool recurseSymlinks, bool deleteStale, Roots & roots)
+static void foundRoot(StoreAPI & store,
+    const Path & path, const Path & target, Roots & roots)
 {
-    try {
+    Path storePath = toStorePath(target);
+    if (store.isValidPath(storePath))
+        roots[path] = storePath;
+    else
+        printMsg(lvlInfo, format("skipping invalid root from `%1%' to `%2%'") % path % storePath);
+}
 
-        struct stat st;
-        if (lstat(path.c_str(), &st) == -1)
-            throw SysError(format("statting `%1%'") % path);
 
-        printMsg(lvlVomit, format("looking at `%1%'") % path);
+static void findRoots(StoreAPI & store, const Path & path, Roots & roots)
+{
+    try {
+
+        struct stat st = lstat(path);
 
         if (S_ISDIR(st.st_mode)) {
             Strings names = readDirectory(path);
             foreach (Strings::iterator, i, names)
-                findRoots(store, path + "/" + *i, recurseSymlinks, deleteStale, roots);
+                findRoots(store, path + "/" + *i, roots);
         }
 
         else if (S_ISLNK(st.st_mode)) {
-            Path target = absPath(readLink(path), dirOf(path));
-
-            if (isInStore(target)) {
-                debug(format("found root `%1%' in `%2%'")
-                    % target % path);
-                Path storePath = toStorePath(target);
-                if (store.isValidPath(storePath))
-                    roots[path] = storePath;
-                else
-                    printMsg(lvlInfo, format("skipping invalid root from `%1%' to `%2%'")
-                        % path % storePath);
-            }
-
-            else if (recurseSymlinks) {
-                if (pathExists(target))
-                    findRoots(store, target, false, deleteStale, roots);
-                else if (deleteStale) {
-                    printMsg(lvlInfo, format("removing stale link from `%1%' to `%2%'") % path % target);
-                    /* Note that we only delete when recursing, i.e.,
-                       when we are still in the `gcroots' tree.  We
-                       never delete stuff outside that tree. */
-                    unlink(path.c_str());
+            Path target = readLink(path);
+            if (isInStore(target))
+                foundRoot(store, path, target, roots);
+
+            /* Handle indirect roots. */
+            else {
+                target = absPath(target, dirOf(path));
+                if (!pathExists(target)) {
+                    if (isInDir(path, settings.nixStateDir + "/" + gcRootsDir + "/auto")) {
+                        printMsg(lvlInfo, format("removing stale link from `%1%' to `%2%'") % path % target);
+                        unlink(path.c_str());
+                    }
+                } else {
+                    struct stat st2 = lstat(target);
+                    if (!S_ISLNK(st2.st_mode)) return;
+                    Path target2 = readLink(target);
+                    if (isInStore(target2)) foundRoot(store, path, target2, roots);
                 }
             }
         }
@@ -346,18 +346,16 @@ static void findRoots(StoreAPI & store, const Path & path,
 }
 
 
-static Roots findRoots(StoreAPI & store, bool deleteStale)
+Roots LocalStore::findRoots()
 {
     Roots roots;
-    Path rootsDir = canonPath((format("%1%/%2%") % settings.nixStateDir % gcRootsDir).str());
-    findRoots(store, rootsDir, true, deleteStale, roots);
-    return roots;
-}
 
+    /* Process direct roots in {gcroots,manifests,profiles}. */
+    nix::findRoots(*this, settings.nixStateDir + "/" + gcRootsDir, roots);
+    nix::findRoots(*this, settings.nixStateDir + "/manifests", roots);
+    nix::findRoots(*this, settings.nixStateDir + "/profiles", roots);
 
-Roots LocalStore::findRoots()
-{
-    return nix::findRoots(*this, false);
+    return roots;
 }
 
 
@@ -637,7 +635,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
     /* Find the roots.  Since we've grabbed the GC lock, the set of
        permanent roots cannot increase now. */
     printMsg(lvlError, format("finding garbage collector roots..."));
-    Roots rootMap = options.ignoreLiveness ? Roots() : nix::findRoots(*this, true);
+    Roots rootMap = options.ignoreLiveness ? Roots() : findRoots();
 
     foreach (Roots::iterator, i, rootMap) state.roots.insert(i->second);