about summary refs log tree commit diff
path: root/src/libstore/local-store.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/local-store.cc')
-rw-r--r--src/libstore/local-store.cc310
1 files changed, 176 insertions, 134 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 05b2b9c6e542..bd63ce55d095 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -6,7 +6,7 @@
 #include "worker-protocol.hh"
 #include "derivations.hh"
 #include "immutable.hh"
-    
+
 #include <iostream>
 #include <algorithm>
 
@@ -147,11 +147,11 @@ struct SQLiteStmtUse
 };
 
 
-struct SQLiteTxn 
+struct SQLiteTxn
 {
     bool active;
     sqlite3 * db;
-    
+
     SQLiteTxn(sqlite3 * db) : active(false) {
         this->db = db;
         if (sqlite3_exec(db, "begin;", 0, 0, 0) != SQLITE_OK)
@@ -159,14 +159,14 @@ struct SQLiteTxn
         active = true;
     }
 
-    void commit() 
+    void commit()
     {
         if (sqlite3_exec(db, "commit;", 0, 0, 0) != SQLITE_OK)
             throwSQLiteError(db, "committing transaction");
         active = false;
     }
-    
-    ~SQLiteTxn() 
+
+    ~SQLiteTxn()
     {
         try {
             if (active && sqlite3_exec(db, "rollback;", 0, 0, 0) != SQLITE_OK)
@@ -181,7 +181,7 @@ struct SQLiteTxn
 void checkStoreNotSymlink()
 {
     if (getEnv("NIX_IGNORE_SYMLINK_STORE") == "1") return;
-    Path path = nixStore;
+    Path path = settings.nixStore;
     struct stat st;
     while (path != "/") {
         if (lstat(path.c_str(), &st))
@@ -198,29 +198,27 @@ void checkStoreNotSymlink()
 
 LocalStore::LocalStore(bool reserveSpace)
 {
-    substitutablePathsLoaded = false;
-    
-    schemaPath = nixDBPath + "/schema";
-    
-    if (readOnlyMode) {
+    schemaPath = settings.nixDBPath + "/schema";
+
+    if (settings.readOnlyMode) {
         openDB(false);
         return;
     }
 
     /* Create missing state directories if they don't already exist. */
-    createDirs(nixStore);
-    createDirs(linksDir = nixStore + "/.links");
-    Path profilesDir = nixStateDir + "/profiles";
-    createDirs(nixStateDir + "/profiles");
-    createDirs(nixStateDir + "/temproots");
-    createDirs(nixDBPath);
-    Path gcRootsDir = nixStateDir + "/gcroots";
+    createDirs(settings.nixStore);
+    createDirs(linksDir = settings.nixStore + "/.links");
+    Path profilesDir = settings.nixStateDir + "/profiles";
+    createDirs(settings.nixStateDir + "/profiles");
+    createDirs(settings.nixStateDir + "/temproots");
+    createDirs(settings.nixDBPath);
+    Path gcRootsDir = settings.nixStateDir + "/gcroots";
     if (!pathExists(gcRootsDir)) {
         createDirs(gcRootsDir);
         if (symlink(profilesDir.c_str(), (gcRootsDir + "/profiles").c_str()) == -1)
             throw SysError(format("creating symlink to `%1%'") % profilesDir);
     }
-  
+
     checkStoreNotSymlink();
 
     /* We can't open a SQLite database if the disk is full.  Since
@@ -228,13 +226,12 @@ LocalStore::LocalStore(bool reserveSpace)
        needed, we reserve some dummy space that we can free just
        before doing a garbage collection. */
     try {
-        Path reservedPath = nixDBPath + "/reserved";
+        Path reservedPath = settings.nixDBPath + "/reserved";
         if (reserveSpace) {
-            int reservedSize = queryIntSetting("gc-reserved-space", 1024 * 1024);
             struct stat st;
             if (stat(reservedPath.c_str(), &st) == -1 ||
-                st.st_size != reservedSize)
-                writeFile(reservedPath, string(reservedSize, 'X'));
+                st.st_size != settings.reservedSize)
+                writeFile(reservedPath, string(settings.reservedSize, 'X'));
         }
         else
             deletePath(reservedPath);
@@ -244,15 +241,15 @@ LocalStore::LocalStore(bool reserveSpace)
     /* Acquire the big fat lock in shared mode to make sure that no
        schema upgrade is in progress. */
     try {
-        Path globalLockPath = nixDBPath + "/big-lock";
+        Path globalLockPath = settings.nixDBPath + "/big-lock";
         globalLock = openLockFile(globalLockPath.c_str(), true);
     } catch (SysError & e) {
         if (e.errNo != EACCES) throw;
-        readOnlyMode = true;
+        settings.readOnlyMode = true;
         openDB(false);
         return;
     }
-    
+
     if (!lockFile(globalLock, ltRead, false)) {
         printMsg(lvlError, "waiting for the big Nix store lock...");
         lockFile(globalLock, ltRead, true);
@@ -264,20 +261,20 @@ LocalStore::LocalStore(bool reserveSpace)
     if (curSchema > nixSchemaVersion)
         throw Error(format("current Nix store schema is version %1%, but I only support %2%")
             % curSchema % nixSchemaVersion);
-    
+
     else if (curSchema == 0) { /* new store */
         curSchema = nixSchemaVersion;
         openDB(true);
         writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
     }
-    
+
     else if (curSchema < nixSchemaVersion) {
         if (curSchema < 5)
             throw Error(
                 "Your Nix store has a database in Berkeley DB format,\n"
                 "which is no longer supported. To convert to the new format,\n"
                 "please upgrade Nix to version 0.12 first.");
-        
+
         if (!lockFile(globalLock, ltWrite, false)) {
             printMsg(lvlError, "waiting for exclusive access to the Nix store...");
             lockFile(globalLock, ltWrite, true);
@@ -293,7 +290,7 @@ LocalStore::LocalStore(bool reserveSpace)
 
         lockFile(globalLock, ltRead, true);
     }
-    
+
     else openDB(false);
 }
 
@@ -327,7 +324,7 @@ int LocalStore::getSchema()
 void LocalStore::openDB(bool create)
 {
     /* Open the Nix database. */
-    if (sqlite3_open_v2((nixDBPath + "/db.sqlite").c_str(), &db.db,
+    if (sqlite3_open_v2((settings.nixDBPath + "/db.sqlite").c_str(), &db.db,
             SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK)
         throw Error("cannot open SQLite database");
 
@@ -339,18 +336,18 @@ void LocalStore::openDB(bool create)
 
     /* !!! check whether sqlite has been built with foreign key
        support */
-    
+
     /* Whether SQLite should fsync().  "Normal" synchronous mode
        should be safe enough.  If the user asks for it, don't sync at
        all.  This can cause database corruption if the system
        crashes. */
-    string syncMode = queryBoolSetting("fsync-metadata", true) ? "normal" : "off";
+    string syncMode = settings.fsyncMetadata ? "normal" : "off";
     if (sqlite3_exec(db, ("pragma synchronous = " + syncMode + ";").c_str(), 0, 0, 0) != SQLITE_OK)
         throwSQLiteError(db, "setting synchronous mode");
 
     /* Set the SQLite journal mode.  WAL mode is fastest, so it's the
        default. */
-    string mode = queryBoolSetting("use-sqlite-wal", true) ? "wal" : "truncate";
+    string mode = settings.useSQLiteWAL ? "wal" : "truncate";
     string prevMode;
     {
         SQLiteStmt stmt;
@@ -368,7 +365,7 @@ void LocalStore::openDB(bool create)
        derivation is done in a single fsync(). */
     if (mode == "wal" && sqlite3_exec(db, "pragma wal_autocheckpoint = 8192;", 0, 0, 0) != SQLITE_OK)
         throwSQLiteError(db, "setting autocheckpoint interval");
-    
+
     /* Initialise the database schema, if necessary. */
     if (create) {
 #include "schema.sql.hh"
@@ -423,7 +420,7 @@ void canonicalisePathMetaData(const Path & path, bool recurse)
 
     struct stat st;
     if (lstat(path.c_str(), &st))
-	throw SysError(format("getting attributes of path `%1%'") % path);
+        throw SysError(format("getting attributes of path `%1%'") % path);
 
     /* Really make sure that the path is of a supported type.  This
        has already been checked in dumpPath(). */
@@ -451,7 +448,7 @@ void canonicalisePathMetaData(const Path & path, bool recurse)
 
         /* Mask out all type related bits. */
         mode_t mode = st.st_mode & ~S_IFMT;
-        
+
         if (mode != 0444 && mode != 0555) {
             mode = (st.st_mode & S_IFMT)
                  | 0444
@@ -461,7 +458,7 @@ void canonicalisePathMetaData(const Path & path, bool recurse)
         }
 
     }
-    
+
     if (st.st_mtime != mtimeStore) {
         struct timeval times[2];
         times[0].tv_sec = st.st_atime;
@@ -472,14 +469,14 @@ void canonicalisePathMetaData(const Path & path, bool recurse)
         if (lutimes(path.c_str(), times) == -1)
 #else
         if (!S_ISLNK(st.st_mode) && utimes(path.c_str(), times) == -1)
-#endif                
+#endif
             throw SysError(format("changing modification time of `%1%'") % path);
     }
 
     if (recurse && S_ISDIR(st.st_mode)) {
         Strings names = readDirectory(path);
-	foreach (Strings::iterator, i, names)
-	    canonicalisePathMetaData(path + "/" + *i, true);
+        foreach (Strings::iterator, i, names)
+            canonicalisePathMetaData(path + "/" + *i, true);
     }
 
     makeImmutable(path);
@@ -494,7 +491,7 @@ void canonicalisePathMetaData(const Path & path)
        be a symlink, since we can't change its ownership. */
     struct stat st;
     if (lstat(path.c_str(), &st))
-	throw SysError(format("getting attributes of path `%1%'") % path);
+        throw SysError(format("getting attributes of path `%1%'") % path);
 
     if (st.st_uid != geteuid()) {
         assert(S_ISLNK(st.st_mode));
@@ -508,7 +505,7 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
     string drvName = storePathToName(drvPath);
     assert(isDerivation(drvName));
     drvName = string(drvName, 0, drvName.size() - drvExtension.size());
-        
+
     if (isFixedOutputDrv(drv)) {
         DerivationOutputs::const_iterator out = drv.outputs.find("out");
         if (out == drv.outputs.end())
@@ -532,7 +529,7 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
         }
 
         Hash h = hashDerivationModulo(*this, drvCopy);
-        
+
         foreach (DerivationOutputs::const_iterator, i, drv.outputs) {
             Path outPath = makeOutputPath(i->first, h, drvName);
             StringPairs::const_iterator j = drv.env.find(i->first);
@@ -568,14 +565,14 @@ unsigned long long LocalStore::addValidPath(const ValidPathInfo & info, bool che
        derivation. */
     if (isDerivation(info.path)) {
         Derivation drv = parseDerivation(readFile(info.path));
-        
+
         /* Verify that the output paths in the derivation are correct
            (i.e., follow the scheme for computing output paths from
            derivations).  Note that if this throws an error, then the
            DB transaction is rolled back, so the path validity
            registration above is undone. */
         if (checkOutputs) checkDerivationOutputs(info.path, drv);
-        
+
         foreach (DerivationOutputs::iterator, i, drv.outputs) {
             SQLiteStmtUse use(stmtAddDerivationOutput);
             stmtAddDerivationOutput.bind(id);
@@ -681,7 +678,7 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path)
     SQLiteStmtUse use1(stmtQueryPathInfo);
 
     stmtQueryPathInfo.bind(path);
-    
+
     int r = sqlite3_step(stmtQueryPathInfo);
     if (r == SQLITE_DONE) throw Error(format("path `%1%' is not valid") % path);
     if (r != SQLITE_ROW) throwSQLiteError(db, "querying path in database");
@@ -691,7 +688,7 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path)
     const char * s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 1);
     assert(s);
     info.hash = parseHashField(path, s);
-    
+
     info.registrationTime = sqlite3_column_int(stmtQueryPathInfo, 2);
 
     s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 3);
@@ -756,13 +753,22 @@ bool LocalStore::isValidPath(const Path & path)
 }
 
 
-PathSet LocalStore::queryValidPaths()
+PathSet LocalStore::queryValidPaths(const PathSet & paths)
+{
+    PathSet res;
+    foreach (PathSet::const_iterator, i, paths)
+        if (isValidPath(*i)) res.insert(*i);
+    return res;
+}
+
+
+PathSet LocalStore::queryAllValidPaths()
 {
     SQLiteStmt stmt;
     stmt.create(db, "select path from ValidPaths");
-    
+
     PathSet res;
-    
+
     int r;
     while ((r = sqlite3_step(stmt)) == SQLITE_ROW) {
         const char * s = (const char *) sqlite3_column_text(stmt, 0);
@@ -825,10 +831,10 @@ PathSet LocalStore::queryValidDerivers(const Path & path)
         assert(s);
         derivers.insert(s);
     }
-    
+
     if (r != SQLITE_DONE)
         throwSQLiteError(db, format("error getting valid derivers of `%1%'") % path);
-    
+
     return derivers;
 }
 
@@ -836,10 +842,10 @@ PathSet LocalStore::queryValidDerivers(const Path & path)
 PathSet LocalStore::queryDerivationOutputs(const Path & path)
 {
     SQLiteTxn txn(db);
-    
+
     SQLiteStmtUse use(stmtQueryDerivationOutputs);
     stmtQueryDerivationOutputs.bind(queryValidPathId(path));
-    
+
     PathSet outputs;
     int r;
     while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
@@ -847,7 +853,7 @@ PathSet LocalStore::queryDerivationOutputs(const Path & path)
         assert(s);
         outputs.insert(s);
     }
-    
+
     if (r != SQLITE_DONE)
         throwSQLiteError(db, format("error getting outputs of `%1%'") % path);
 
@@ -858,10 +864,10 @@ PathSet LocalStore::queryDerivationOutputs(const Path & path)
 StringSet LocalStore::queryDerivationOutputNames(const Path & path)
 {
     SQLiteTxn txn(db);
-    
+
     SQLiteStmtUse use(stmtQueryDerivationOutputs);
     stmtQueryDerivationOutputs.bind(queryValidPathId(path));
-    
+
     StringSet outputNames;
     int r;
     while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
@@ -869,7 +875,7 @@ StringSet LocalStore::queryDerivationOutputNames(const Path & path)
         assert(s);
         outputNames.insert(s);
     }
-    
+
     if (r != SQLITE_DONE)
         throwSQLiteError(db, format("error getting output names of `%1%'") % path);
 
@@ -880,11 +886,11 @@ StringSet LocalStore::queryDerivationOutputNames(const Path & path)
 Path LocalStore::queryPathFromHashPart(const string & hashPart)
 {
     if (hashPart.size() != 32) throw Error("invalid hash part");
-    
+
     SQLiteTxn txn(db);
 
-    Path prefix = nixStore + "/" + hashPart;
-    
+    Path prefix = settings.nixStore + "/" + hashPart;
+
     SQLiteStmtUse use(stmtQueryPathFromHashPart);
     stmtQueryPathFromHashPart.bind(prefix);
 
@@ -900,16 +906,17 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart)
 void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter & run)
 {
     if (run.pid != -1) return;
-    
+
     debug(format("starting substituter program `%1%'") % substituter);
 
-    Pipe toPipe, fromPipe;
-            
+    Pipe toPipe, fromPipe, errorPipe;
+
     toPipe.create();
     fromPipe.create();
+    errorPipe.create();
 
     run.pid = fork();
-            
+
     switch (run.pid) {
 
     case -1:
@@ -923,13 +930,19 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
                library named libutil.  As a result, substituters
                written in Perl (i.e. all of them) fail. */
             unsetenv("DYLD_LIBRARY_PATH");
-            
+
+            /* Pass configuration options (including those overriden
+               with --option) to the substituter. */
+            setenv("_NIX_OPTIONS", settings.pack().c_str(), 1);
+
             fromPipe.readSide.close();
             toPipe.writeSide.close();
             if (dup2(toPipe.readSide, STDIN_FILENO) == -1)
                 throw SysError("dupping stdin");
             if (dup2(fromPipe.writeSide, STDOUT_FILENO) == -1)
                 throw SysError("dupping stdout");
+            if (dup2(errorPipe.writeSide, STDERR_FILENO) == -1)
+                throw SysError("dupping stderr");
             closeMostFDs(set<int>());
             execl(substituter.c_str(), substituter.c_str(), "--query", NULL);
             throw SysError(format("executing `%1%'") % substituter);
@@ -940,9 +953,10 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
     }
 
     /* Parent. */
-    
+
     run.to = toPipe.writeSide.borrow();
     run.from = fromPipe.readSide.borrow();
+    run.error = errorPipe.readSide.borrow();
 }
 
 
@@ -955,50 +969,79 @@ template<class T> T getIntLine(int fd)
 }
 
 
-bool LocalStore::hasSubstitutes(const Path & path)
+PathSet LocalStore::querySubstitutablePaths(const PathSet & paths)
 {
-    foreach (Paths::iterator, i, substituters) {
+    PathSet res;
+    foreach (Paths::iterator, i, settings.substituters) {
+        if (res.size() == paths.size()) break;
         RunningSubstituter & run(runningSubstituters[*i]);
         startSubstituter(*i, run);
-        writeLine(run.to, "have\n" + path);
-        if (getIntLine<int>(run.from)) return true;
+        string s = "have ";
+        foreach (PathSet::const_iterator, j, paths)
+            if (res.find(*j) == res.end()) { s += *j; s += " "; }
+        writeLine(run.to, s);
+        while (true) {
+            /* FIXME: we only read stderr when an error occurs, so
+               substituters should only write (short) messages to
+               stderr when they fail.  I.e. they shouldn't write debug
+               output. */
+            try {
+                Path path = readLine(run.from);
+                if (path == "") break;
+                res.insert(path);
+            } catch (EndOfFile e) {
+                throw Error(format("substituter `%1%' failed: %2%") % *i % chomp(drainFD(run.error)));
+            }
+        }
     }
-
-    return false;
+    return res;
 }
 
 
-bool LocalStore::querySubstitutablePathInfo(const Path & substituter,
-    const Path & path, SubstitutablePathInfo & info)
+void LocalStore::querySubstitutablePathInfos(const Path & substituter,
+    PathSet & paths, SubstitutablePathInfos & infos)
 {
     RunningSubstituter & run(runningSubstituters[substituter]);
     startSubstituter(substituter, run);
 
-    writeLine(run.to, "info\n" + path);
-
-    if (!getIntLine<int>(run.from)) return false;
-    
-    info.deriver = readLine(run.from);
-    if (info.deriver != "") assertStorePath(info.deriver);
-    int nrRefs = getIntLine<int>(run.from);
-    while (nrRefs--) {
-        Path p = readLine(run.from);
-        assertStorePath(p);
-        info.references.insert(p);
+    string s = "info ";
+    foreach (PathSet::const_iterator, i, paths)
+        if (infos.find(*i) == infos.end()) { s += *i; s += " "; }
+    writeLine(run.to, s);
+
+    while (true) {
+        try {
+            Path path = readLine(run.from);
+            if (path == "") break;
+            if (paths.find(path) == paths.end())
+                throw Error(format("got unexpected path `%1%' from substituter") % path);
+            paths.erase(path);
+            SubstitutablePathInfo & info(infos[path]);
+            info.deriver = readLine(run.from);
+            if (info.deriver != "") assertStorePath(info.deriver);
+            int nrRefs = getIntLine<int>(run.from);
+            while (nrRefs--) {
+                Path p = readLine(run.from);
+                assertStorePath(p);
+                info.references.insert(p);
+            }
+            info.downloadSize = getIntLine<long long>(run.from);
+            info.narSize = getIntLine<long long>(run.from);
+        } catch (EndOfFile e) {
+            throw Error(format("substituter `%1%' failed: %2%") % substituter % chomp(drainFD(run.error)));
+        }
     }
-    info.downloadSize = getIntLine<long long>(run.from);
-    info.narSize = getIntLine<long long>(run.from);
-    
-    return true;
 }
 
 
-bool LocalStore::querySubstitutablePathInfo(const Path & path,
-    SubstitutablePathInfo & info)
+void LocalStore::querySubstitutablePathInfos(const PathSet & paths,
+    SubstitutablePathInfos & infos)
 {
-    foreach (Paths::iterator, i, substituters)
-        if (querySubstitutablePathInfo(*i, path, info)) return true;
-    return false;
+    PathSet todo = paths;
+    foreach (Paths::iterator, i, settings.substituters) {
+        if (todo.empty()) break;
+        querySubstitutablePathInfos(*i, todo, infos);
+    }
 }
 
 
@@ -1018,17 +1061,16 @@ void LocalStore::registerValidPath(const ValidPathInfo & info)
 
 void LocalStore::registerValidPaths(const ValidPathInfos & infos)
 {
-    /* sqlite will fsync by default, but the new valid paths may not be fsync-ed.
+    /* SQLite will fsync by default, but the new valid paths may not be fsync-ed.
      * So some may want to fsync them before registering the validity, at the
      * expense of some speed of the path registering operation. */
-    if (queryBoolSetting("sync-before-registering", false))
-        sync();
+    if (settings.syncBeforeRegistering) sync();
 
     while (1) {
         try {
             SQLiteTxn txn(db);
             PathSet paths;
-    
+
             foreach (ValidPathInfos::const_iterator, i, infos) {
                 assert(i->hash.type == htSHA256);
                 /* !!! Maybe the registration info should be updated if the
@@ -1119,7 +1161,7 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
                 hash = hashPath(htSHA256, dstPath);
 
             optimisePath(dstPath); // FIXME: combine with hashPath()
-            
+
             ValidPathInfo info;
             info.path = dstPath;
             info.hash = hash.first;
@@ -1144,7 +1186,7 @@ Path LocalStore::addToStore(const Path & _srcPath,
        method for very large paths, but `copyPath' is mainly used for
        small files. */
     StringSink sink;
-    if (recursive) 
+    if (recursive)
         dumpPath(srcPath, sink, filter);
     else
         sink.s = readFile(srcPath);
@@ -1157,7 +1199,7 @@ Path LocalStore::addTextToStore(const string & name, const string & s,
     const PathSet & references)
 {
     Path dstPath = computeStorePathForText(name, s, references);
-    
+
     addTempRoot(dstPath);
 
     if (!isValidPath(dstPath)) {
@@ -1175,7 +1217,7 @@ Path LocalStore::addTextToStore(const string & name, const string & s,
             HashResult hash = hashPath(htSHA256, dstPath);
 
             optimisePath(dstPath);
-            
+
             ValidPathInfo info;
             info.path = dstPath;
             info.hash = hash.first;
@@ -1233,7 +1275,7 @@ void LocalStore::exportPath(const Path & path, bool sign,
         throw Error(format("path `%1%' is not valid") % path);
 
     HashAndWriteSink hashAndWriteSink(sink);
-    
+
     dumpPath(path, hashAndWriteSink);
 
     /* Refuse to export paths that have changed.  This prevents
@@ -1248,7 +1290,7 @@ void LocalStore::exportPath(const Path & path, bool sign,
     writeInt(EXPORT_MAGIC, hashAndWriteSink);
 
     writeString(path, hashAndWriteSink);
-    
+
     PathSet references;
     queryReferences(path, references);
     writeStrings(references, hashAndWriteSink);
@@ -1258,15 +1300,15 @@ void LocalStore::exportPath(const Path & path, bool sign,
 
     if (sign) {
         Hash hash = hashAndWriteSink.currentHash();
- 
+
         writeInt(1, hashAndWriteSink);
-        
+
         Path tmpDir = createTempDir();
         AutoDelete delTmp(tmpDir);
         Path hashFile = tmpDir + "/hash";
         writeFile(hashFile, printHash(hash));
 
-        Path secretKey = nixConfDir + "/signing-key.sec";
+        Path secretKey = settings.nixConfDir + "/signing-key.sec";
         checkSecrecy(secretKey);
 
         Strings args;
@@ -1279,7 +1321,7 @@ void LocalStore::exportPath(const Path & path, bool sign,
         string signature = runProgram(OPENSSL_PATH, true, args);
 
         writeString(signature, hashAndWriteSink);
-        
+
     } else
         writeInt(0, hashAndWriteSink);
 }
@@ -1312,7 +1354,7 @@ Path LocalStore::createTempDirInStore()
         /* There is a slight possibility that `tmpDir' gets deleted by
            the GC between createTempDir() and addTempRoot(), so repeat
            until `tmpDir' exists. */
-        tmpDir = createTempDir(nixStore);
+        tmpDir = createTempDir(settings.nixStore);
         addTempRoot(tmpDir);
     } while (!pathExists(tmpDir));
     return tmpDir;
@@ -1322,7 +1364,7 @@ Path LocalStore::createTempDirInStore()
 Path LocalStore::importPath(bool requireSignature, Source & source)
 {
     HashAndReadSource hashAndReadSource(source);
-    
+
     /* We don't yet know what store path this archive contains (the
        store path follows the archive data proper), and besides, we
        don't know yet whether the signature is valid. */
@@ -1352,7 +1394,7 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
 
     if (requireSignature && !haveSignature)
         throw Error(format("imported archive of `%1%' lacks a signature") % dstPath);
-    
+
     if (haveSignature) {
         string signature = readString(hashAndReadSource);
 
@@ -1364,7 +1406,7 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
             args.push_back("rsautl");
             args.push_back("-verify");
             args.push_back("-inkey");
-            args.push_back(nixConfDir + "/signing-key.pub");
+            args.push_back(settings.nixConfDir + "/signing-key.pub");
             args.push_back("-pubin");
             args.push_back("-in");
             args.push_back(sigFile);
@@ -1406,13 +1448,13 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
                     % unpacked % dstPath);
 
             canonicalisePathMetaData(dstPath);
-            
+
             /* !!! if we were clever, we could prevent the hashPath()
                here. */
             HashResult hash = hashPath(htSHA256, dstPath);
 
             optimisePath(dstPath); // FIXME: combine with hashPath()
-            
+
             ValidPathInfo info;
             info.path = dstPath;
             info.hash = hash.first;
@@ -1421,10 +1463,10 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
             info.deriver = deriver != "" && isValidPath(deriver) ? deriver : "";
             registerValidPath(info);
         }
-        
+
         outputLock.setDeletion(true);
     }
-    
+
     return dstPath;
 }
 
@@ -1472,14 +1514,14 @@ void LocalStore::verifyStore(bool checkContents)
 
     /* Acquire the global GC lock to prevent a garbage collection. */
     AutoCloseFD fdGCLock = openGCLock(ltWrite);
-    
-    Paths entries = readDirectory(nixStore);
+
+    Paths entries = readDirectory(settings.nixStore);
     PathSet store(entries.begin(), entries.end());
 
     /* Check whether all valid paths actually exist. */
     printMsg(lvlInfo, "checking path existence...");
 
-    PathSet validPaths2 = queryValidPaths(), validPaths, done;
+    PathSet validPaths2 = queryAllValidPaths(), validPaths, done;
 
     foreach (PathSet::iterator, i, validPaths2)
         verifyPath(*i, store, done, validPaths);
@@ -1501,7 +1543,7 @@ void LocalStore::verifyStore(bool checkContents)
                 /* Check the content hash (optionally - slow). */
                 printMsg(lvlTalkative, format("checking contents of `%1%'") % *i);
                 HashResult current = hashPath(info.hash.type, *i);
-                
+
                 if (info.hash != nullHash && info.hash != current.first) {
                     printMsg(lvlError, format("path `%1%' was modified! "
                             "expected hash `%2%', got `%3%'")
@@ -1516,18 +1558,18 @@ void LocalStore::verifyStore(bool checkContents)
                         info.hash = current.first;
                         update = true;
                     }
-                    
+
                     /* Fill in missing narSize fields (from old stores). */
                     if (info.narSize == 0) {
                         printMsg(lvlError, format("updating size field on `%1%' to %2%") % *i % current.second);
                         info.narSize = current.second;
-                        update = true;                        
+                        update = true;
                     }
 
                     if (update) updatePathInfo(info);
 
                 }
-            
+
             } catch (Error & e) {
                 /* It's possible that the path got GC'ed, so ignore
                    errors on invalid paths. */
@@ -1543,7 +1585,7 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
     PathSet & done, PathSet & validPaths)
 {
     checkInterrupt();
-    
+
     if (done.find(path) != done.end()) return;
     done.insert(path);
 
@@ -1570,10 +1612,10 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
             invalidatePath(path);
         } else
             printMsg(lvlError, format("path `%1%' disappeared, but it still has valid referrers!") % path);
-        
+
         return;
     }
-    
+
     validPaths.insert(path);
 }
 
@@ -1583,9 +1625,9 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
 PathSet LocalStore::queryValidPathsOld()
 {
     PathSet paths;
-    Strings entries = readDirectory(nixDBPath + "/info");
+    Strings entries = readDirectory(settings.nixDBPath + "/info");
     foreach (Strings::iterator, i, entries)
-        if (i->at(0) != '.') paths.insert(nixStore + "/" + *i);
+        if (i->at(0) != '.') paths.insert(settings.nixStore + "/" + *i);
     return paths;
 }
 
@@ -1597,7 +1639,7 @@ ValidPathInfo LocalStore::queryPathInfoOld(const Path & path)
 
     /* Read the info file. */
     string baseName = baseNameOf(path);
-    Path infoFile = (format("%1%/info/%2%") % nixDBPath % baseName).str();
+    Path infoFile = (format("%1%/info/%2%") % settings.nixDBPath % baseName).str();
     if (!pathExists(infoFile))
         throw Error(format("path `%1%' is not valid") % path);
     string info = readFile(infoFile);
@@ -1639,14 +1681,14 @@ void LocalStore::upgradeStore6()
     PathSet validPaths = queryValidPathsOld();
 
     SQLiteTxn txn(db);
-    
+
     foreach (PathSet::iterator, i, validPaths) {
         addValidPath(queryPathInfoOld(*i), false);
         std::cerr << ".";
     }
 
     std::cerr << "|";
-    
+
     foreach (PathSet::iterator, i, validPaths) {
         ValidPathInfo info = queryPathInfoOld(*i);
         unsigned long long referrer = queryValidPathId(*i);