diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index b51a5b07988c55182edc8f8f856123e28feda17b..8ea0aec06cf468f92fd050a35707ad2849cfa7c3 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -8,7 +8,7 @@ #include "nixexpr.hh" -typedef map<Path, PathSet> DrvPaths; +typedef map<Path, PathSet> DrvRoots; typedef map<Path, Hash> DrvHashes; struct EvalState; @@ -22,7 +22,7 @@ struct EvalState { ATermMap normalForms; ATermMap primOps; - DrvPaths drvPaths; + DrvRoots drvRoots; DrvHashes drvHashes; /* normalised derivation hashes */ Expr blackHole; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 6588922c26b9657e6aa65b18deef7aa5293ce7e2..070ed1b54aa71ce3878e58f6a8ff0adee9de3c03 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -17,12 +17,12 @@ static Expr primImport(EvalState & state, const ATermVector & args) static PathSet storeExprRootsCached(EvalState & state, const Path & nePath) { - DrvPaths::iterator i = state.drvPaths.find(nePath); - if (i != state.drvPaths.end()) + DrvRoots::iterator i = state.drvRoots.find(nePath); + if (i != state.drvRoots.end()) return i->second; else { PathSet paths = storeExprRoots(nePath); - state.drvPaths[nePath] = paths; + state.drvRoots[nePath] = paths; return paths; } } @@ -61,6 +61,8 @@ static Path copyAtom(EvalState & state, const Path & srcPath) Path drvPath = writeTerm(unparseStoreExpr(ne), ""); state.drvHashes[drvPath] = drvHash; + state.drvRoots[drvPath] = ne.closure.roots; + printMsg(lvlChatty, format("copied `%1%' -> closure `%2%'") % srcPath % drvPath); return drvPath; @@ -111,8 +113,14 @@ static void processBinding(EvalState & state, Expr e, StoreExpr & ne, if (!a) throw Error("derivation hash missing"); Hash drvHash = parseHash(evalString(state, a)); - state.drvHashes[drvPath] = drvHash; + a = queryAttr(e, "outPath"); + if (!a) throw Error("output path missing"); + PathSet drvRoots; + drvRoots.insert(evalPath(state, a)); + state.drvHashes[drvPath] = drvHash; + state.drvRoots[drvPath] = drvRoots; + ss.push_back(addInput(state, drvPath, ne)); } else throw Error("invalid derivation attribute"); diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 24f6ec4df92bab2ee46f20dc5e26d2fae0b7b6cc..73388c96e8cd5fdb5ae9f5cb689c5524a9d4ec92 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -160,6 +160,8 @@ static void initAndRun(int argc, char * * argv) throw UsageError(format("`--max-jobs' requires a non-negative integer")); maxBuildJobs = n; } + else if (arg == "--readonly-mode") + readOnlyMode = true; else remaining.push_back(arg); } diff --git a/src/libstore/db.cc b/src/libstore/db.cc index f01cefd799cc699197fa22482f84e4e909a8606d..3b7bddaa26a0f6799b76c6aecb0024476396f9cf 100644 --- a/src/libstore/db.cc +++ b/src/libstore/db.cc @@ -1,6 +1,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <errno.h> #include <memory> @@ -81,12 +82,16 @@ void Transaction::moveTo(Transaction & t) void Database::requireEnv() { checkInterrupt(); - if (!env) throw Error("database environment not open"); + if (!env)throw Error("database environment is not open " + "(maybe you don't have sufficient permission?)"); } Db * Database::getDb(TableId table) { + if (table == 0) + throw Error("database table is not open " + "(maybe you don't have sufficient permission?)"); map<TableId, Db *>::iterator i = tables.find(table); if (i == tables.end()) throw Error("unknown table id"); @@ -210,7 +215,11 @@ void Database::open(const string & path) string accessorsPath = path + "/accessor_count"; fdAccessors = ::open(accessorsPath.c_str(), O_RDWR | O_CREAT, 0666); if (fdAccessors == -1) - throw SysError(format("opening file `%1%'") % accessorsPath); + if (errno == EACCES) + throw DbNoPermission( + format("permission denied to database in `%1%'") % accessorsPath); + else + throw SysError(format("opening file `%1%'") % accessorsPath); /* Open the lock file. */ string lockPath = path + "/access_lock"; diff --git a/src/libstore/db.hh b/src/libstore/db.hh index bbeabfc7dfa4fd9bd65d7b15e35dabf113d51f8f..d566fdad1e1cc92a76936a5a2d0c5155056c2fb8 100644 --- a/src/libstore/db.hh +++ b/src/libstore/db.hh @@ -87,4 +87,11 @@ public: }; +class DbNoPermission : public Error +{ +public: + DbNoPermission(const format & f) : Error(f) { }; +}; + + #endif /* !__DB_H */ diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 44794d147a7710af8666b6a8d2e3b4a6216ef1ef..52f2a0a0bffade227fd1da4b27500689c151f75e 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -15,3 +15,5 @@ bool tryFallback = false; Verbosity buildVerbosity = lvlInfo; unsigned int maxBuildJobs = 1; + +bool readOnlyMode = false; diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index 7f88d5c53b27cd3705b81a78d8bb32997e9bae99..beaa0acc9ff01e92b328fe7812ab063ab003699e 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -43,5 +43,9 @@ extern Verbosity buildVerbosity; /* Maximum number of parallel build jobs. 0 means unlimited. */ extern unsigned int maxBuildJobs; +/* Read-only mode. Don't copy stuff to the store, don't change the + database. */ +extern bool readOnlyMode; + #endif /* !__GLOBALS_H */ diff --git a/src/libstore/store.cc b/src/libstore/store.cc index 1f05b63a6cce8cb720c58e1be9d659d84bac4be6..7dbf520d22c29e97f1b04b7e61ea134d10adc9a7 100644 --- a/src/libstore/store.cc +++ b/src/libstore/store.cc @@ -21,7 +21,7 @@ static Database nixDB; The existence of a key $p$ indicates that path $p$ is valid (that is, produced by a succesful build). */ -static TableId dbValidPaths; +static TableId dbValidPaths = 0; /* dbSuccessors :: Path -> Path @@ -32,14 +32,14 @@ static TableId dbValidPaths; Note that a term $y$ is a successor of $x$ iff there exists a sequence of rewrite steps that rewrites $x$ into $y$. */ -static TableId dbSuccessors; +static TableId dbSuccessors = 0; /* dbSuccessorsRev :: Path -> [Path] The reverse mapping of dbSuccessors (i.e., it stores the predecessors of a Nix expression). */ -static TableId dbSuccessorsRev; +static TableId dbSuccessorsRev = 0; /* dbSubstitutes :: Path -> [(Path, Path, [string])] @@ -54,14 +54,14 @@ static TableId dbSuccessorsRev; substitute for that derivate. The substitute in this case might be a Nix expression that fetches the Nix archive. */ -static TableId dbSubstitutes; +static TableId dbSubstitutes = 0; /* dbSubstitutesRev :: Path -> [Path] The reverse mapping of dbSubstitutes; it maps store expressions back to the paths for which they are substitutes. */ -static TableId dbSubstitutesRev; +static TableId dbSubstitutesRev = 0; bool Substitute::operator == (const Substitute & sub) @@ -74,7 +74,14 @@ bool Substitute::operator == (const Substitute & sub) void openDB() { - nixDB.open(nixDBPath); + if (readOnlyMode) return; + try { + nixDB.open(nixDBPath); + } catch (DbNoPermission & e) { + printMsg(lvlTalkative, "cannot access Nix database; continuing anyway"); + readOnlyMode = true; + return; + } dbValidPaths = nixDB.openTable("validpaths"); dbSuccessors = nixDB.openTable("successors"); dbSuccessorsRev = nixDB.openTable("successors-rev"); @@ -433,7 +440,7 @@ Path addToStore(const Path & _srcPath) string baseName = baseNameOf(srcPath); Path dstPath = canonPath(nixStore + "/" + (string) h + "-" + baseName); - if (!isValidPath(dstPath)) { + if (!readOnlyMode && !isValidPath(dstPath)) { /* The first check above is an optimisation to prevent unnecessary lock acquisition. */ @@ -445,6 +452,9 @@ Path addToStore(const Path & _srcPath) if (!isValidPath(dstPath)) { if (pathExists(dstPath)) deletePath(dstPath); + + /* !!! race: srcPath might change between hashPath() and + here! */ copyPath(srcPath, dstPath); diff --git a/src/libstore/storeexpr.cc b/src/libstore/storeexpr.cc index 45b5af055a9b02f192418f39fbaab55461385f78..29f271de884bb496f07ad45e5f4a547d250dc6ef 100644 --- a/src/libstore/storeexpr.cc +++ b/src/libstore/storeexpr.cc @@ -17,7 +17,7 @@ Path writeTerm(ATerm t, const string & suffix) Path path = canonPath(nixStore + "/" + (string) h + suffix + ".store"); - if (!isValidPath(path)) { + if (!readOnlyMode && !isValidPath(path)) { char * s = ATwriteToString(t); if (!s) throw Error(format("cannot write aterm to `%1%'") % path); addTextToStore(path, string(s));