about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2004-10-25T14·38+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2004-10-25T14·38+0000
commitf4d44a002688262d33093494a7fea1bb11b97ac9 (patch)
tree9768179865220106bd1c0103361ded0967c059c8 /src
parent3ade3e7721df981614bbb2420baeb84e58085967 (diff)
* Allow certain operations to succeed even if we don't have write
  permission to the Nix store or database.  E.g., `nix-env -qa' will
  work, but `nix-env -qas' won't (the latter needs DB access).  The
  option `--readonly-mode' forces this mode; otherwise, it's only
  activated when the database cannot be opened.

Diffstat (limited to 'src')
-rw-r--r--src/libexpr/eval.hh4
-rw-r--r--src/libexpr/primops.cc16
-rw-r--r--src/libmain/shared.cc2
-rw-r--r--src/libstore/db.cc13
-rw-r--r--src/libstore/db.hh7
-rw-r--r--src/libstore/globals.cc2
-rw-r--r--src/libstore/globals.hh4
-rw-r--r--src/libstore/store.cc24
-rw-r--r--src/libstore/storeexpr.cc2
9 files changed, 58 insertions, 16 deletions
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index b51a5b07988c..8ea0aec06cf4 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 6588922c26b9..070ed1b54aa7 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 24f6ec4df92b..73388c96e8cd 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 f01cefd799cc..3b7bddaa26a0 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 bbeabfc7dfa4..d566fdad1e1c 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 44794d147a77..52f2a0a0bffa 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 7f88d5c53b27..beaa0acc9ff0 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 1f05b63a6cce..7dbf520d22c2 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 45b5af055a9b..29f271de884b 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));