about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/nix-store.xml13
-rw-r--r--src/libstore/local-store.cc25
-rw-r--r--src/libstore/local-store.hh7
-rw-r--r--src/nix-store/nix-store.cc8
4 files changed, 42 insertions, 11 deletions
diff --git a/doc/manual/nix-store.xml b/doc/manual/nix-store.xml
index 633dcd871ba7..719bfe097574 100644
--- a/doc/manual/nix-store.xml
+++ b/doc/manual/nix-store.xml
@@ -773,6 +773,7 @@ $ nix-store --add ./foo.c
     <command>nix-store</command>
     <arg choice='plain'><option>--verify</option></arg>
     <arg><option>--check-contents</option></arg>
+    <arg><option>--repair</option></arg>
   </cmdsynopsis>
 </refsection>
 
@@ -785,7 +786,7 @@ automatically repaired.  Inconsistencies are generally the result of
 the Nix store or database being modified by non-Nix tools, or of bugs
 in Nix itself.</para>
 
-<para>There is one option:
+<para>This operation has the following options:
 
 <variablelist>
 
@@ -800,6 +801,16 @@ in Nix itself.</para>
     
   </varlistentry>
   
+  <varlistentry><term><option>--repair</option></term>
+  
+    <listitem><para>If any valid path is missing from the store, or
+    (if <option>--check-contents</option> is given) the contents of a
+    valid path has been modified, then try to repair the path by
+    redownloading it.  See <command>nix-store --repair-path</command>
+    for details.</para></listitem>
+    
+  </varlistentry>
+  
 </variablelist>
 
 </para>
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 6882e9328b6e..e038cd4b29d3 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -1544,10 +1544,12 @@ void LocalStore::invalidatePathChecked(const Path & path)
 }
 
 
-void LocalStore::verifyStore(bool checkContents)
+bool LocalStore::verifyStore(bool checkContents, bool repair)
 {
     printMsg(lvlError, format("reading the Nix store..."));
 
+    bool errors = false;
+
     /* Acquire the global GC lock to prevent a garbage collection. */
     AutoCloseFD fdGCLock = openGCLock(ltWrite);
 
@@ -1560,7 +1562,7 @@ void LocalStore::verifyStore(bool checkContents)
     PathSet validPaths2 = queryAllValidPaths(), validPaths, done;
 
     foreach (PathSet::iterator, i, validPaths2)
-        verifyPath(*i, store, done, validPaths);
+        verifyPath(*i, store, done, validPaths, repair, errors);
 
     /* Release the GC lock so that checking content hashes (which can
        take ages) doesn't block the GC or builds. */
@@ -1584,6 +1586,7 @@ void LocalStore::verifyStore(bool checkContents)
                     printMsg(lvlError, format("path `%1%' was modified! "
                             "expected hash `%2%', got `%3%'")
                         % *i % printHash(info.hash) % printHash(current.first));
+                    if (repair) repairPath(*i); else errors = true;
                 } else {
 
                     bool update = false;
@@ -1611,14 +1614,17 @@ void LocalStore::verifyStore(bool checkContents)
                    errors on invalid paths. */
                 if (isValidPath(*i)) throw;
                 printMsg(lvlError, format("warning: %1%") % e.msg());
+                errors = true;
             }
         }
     }
+
+    return errors;
 }
 
 
 void LocalStore::verifyPath(const Path & path, const PathSet & store,
-    PathSet & done, PathSet & validPaths)
+    PathSet & done, PathSet & validPaths, bool repair, bool & errors)
 {
     checkInterrupt();
 
@@ -1638,7 +1644,7 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
         PathSet referrers; queryReferrers(path, referrers);
         foreach (PathSet::iterator, i, referrers)
             if (*i != path) {
-                verifyPath(*i, store, done, validPaths);
+                verifyPath(*i, store, done, validPaths, repair, errors);
                 if (validPaths.find(*i) != validPaths.end())
                     canInvalidate = false;
             }
@@ -1646,8 +1652,17 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
         if (canInvalidate) {
             printMsg(lvlError, format("path `%1%' disappeared, removing from database...") % path);
             invalidatePath(path);
-        } else
+        } else {
             printMsg(lvlError, format("path `%1%' disappeared, but it still has valid referrers!") % path);
+            if (repair)
+                try {
+                    repairPath(path);
+                } catch (Error & e) {
+                    printMsg(lvlError, format("warning: %1%") % e.msg());
+                    errors = true;
+                }
+            else errors = true;
+        }
 
         return;
     }
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 80db10de10d0..9f1c8280a8de 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -171,8 +171,9 @@ public:
     /* Optimise a single store path. */
     void optimisePath(const Path & path);
 
-    /* Check the integrity of the Nix store. */
-    void verifyStore(bool checkContents);
+    /* Check the integrity of the Nix store.  Returns true if errors
+       remain. */
+    bool verifyStore(bool checkContents, bool repair);
 
     /* Register the validity of a path, i.e., that `path' exists, that
        the paths referenced by it exists, and in the case of an output
@@ -250,7 +251,7 @@ private:
     void invalidatePathChecked(const Path & path);
 
     void verifyPath(const Path & path, const PathSet & store,
-        PathSet & done, PathSet & validPaths);
+        PathSet & done, PathSet & validPaths, bool repair, bool & errors);
 
     void updatePathInfo(const ValidPathInfo & info);
 
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index ce415ce4aeb1..0ed8b6d74b7c 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -703,13 +703,18 @@ static void opVerify(Strings opFlags, Strings opArgs)
         throw UsageError("no arguments expected");
 
     bool checkContents = false;
+    bool repair = false;
 
     for (Strings::iterator i = opFlags.begin();
          i != opFlags.end(); ++i)
         if (*i == "--check-contents") checkContents = true;
+        else if (*i == "--repair") repair = true;
         else throw UsageError(format("unknown flag `%1%'") % *i);
 
-    ensureLocalStore().verifyStore(checkContents);
+    if (ensureLocalStore().verifyStore(checkContents, repair)) {
+        printMsg(lvlError, "warning: not all errors were fixed");
+        exitCode = 1;
+    }
 }
 
 
@@ -743,7 +748,6 @@ static void opRepairPath(Strings opFlags, Strings opArgs)
 
     foreach (Strings::iterator, i, opArgs) {
         Path path = followLinksToStorePath(*i);
-        printMsg(lvlTalkative, format("repairing path `%1%'...") % path);
         ensureLocalStore().repairPath(path);
     }
 }