aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-07-12 14:01:25 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-07-12 14:03:36 +0200
commitaeb810b01e17d040f9592681ee271f15874dce50 (patch)
treefbf5e93aeb43f6b900f4c813ea5655385b041bdf /src
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')
-rw-r--r--src/libstore/gc.cc80
-rw-r--r--src/libstore/store-api.cc5
-rw-r--r--src/libutil/util.cc9
-rw-r--r--src/libutil/util.hh4
4 files changed, 53 insertions, 45 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 5c5c07e4c..37ca6be4b 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);
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 32aaca6be..0f250a3c7 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -18,10 +18,7 @@ GCOptions::GCOptions()
bool isInStore(const Path & path)
{
- return path[0] == '/'
- && string(path, 0, settings.nixStore.size()) == settings.nixStore
- && path.size() >= settings.nixStore.size() + 2
- && path[settings.nixStore.size()] == '/';
+ return isInDir(path, settings.nixStore);
}
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index b1231e455..dad5f624b 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -148,6 +148,15 @@ string baseNameOf(const Path & path)
}
+bool isInDir(const Path & path, const Path & dir)
+{
+ return path[0] == '/'
+ && string(path, 0, dir.size()) == dir
+ && path.size() >= dir.size() + 2
+ && path[dir.size()] == '/';
+}
+
+
struct stat lstat(const Path & path)
{
struct stat st;
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 9caab4aa1..6c83987c5 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -45,6 +45,10 @@ Path dirOf(const Path & path);
following the final `/'. */
string baseNameOf(const Path & path);
+/* Check whether a given path is a descendant of the given
+ directory. */
+bool isInDir(const Path & path, const Path & dir);
+
/* Get status of `path'. */
struct stat lstat(const Path & path);