nix-store --verify: Add an option ‘--repair’ to repair all missing/corrupt paths

Also, return a non-zero exit code if errors remain after
verifying/repairing.
This commit is contained in:
Eelco Dolstra 2012-10-02 15:04:59 -04:00
parent 9958bd6992
commit 8e3a7bd712
4 changed files with 42 additions and 11 deletions

View file

@ -773,6 +773,7 @@ $ nix-store --add ./foo.c
<command>nix-store</command> <command>nix-store</command>
<arg choice='plain'><option>--verify</option></arg> <arg choice='plain'><option>--verify</option></arg>
<arg><option>--check-contents</option></arg> <arg><option>--check-contents</option></arg>
<arg><option>--repair</option></arg>
</cmdsynopsis> </cmdsynopsis>
</refsection> </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 the Nix store or database being modified by non-Nix tools, or of bugs
in Nix itself.</para> in Nix itself.</para>
<para>There is one option: <para>This operation has the following options:
<variablelist> <variablelist>
@ -800,6 +801,16 @@ in Nix itself.</para>
</varlistentry> </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> </variablelist>
</para> </para>

View file

@ -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...")); printMsg(lvlError, format("reading the Nix store..."));
bool errors = false;
/* Acquire the global GC lock to prevent a garbage collection. */ /* Acquire the global GC lock to prevent a garbage collection. */
AutoCloseFD fdGCLock = openGCLock(ltWrite); AutoCloseFD fdGCLock = openGCLock(ltWrite);
@ -1560,7 +1562,7 @@ void LocalStore::verifyStore(bool checkContents)
PathSet validPaths2 = queryAllValidPaths(), validPaths, done; PathSet validPaths2 = queryAllValidPaths(), validPaths, done;
foreach (PathSet::iterator, i, validPaths2) 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 /* Release the GC lock so that checking content hashes (which can
take ages) doesn't block the GC or builds. */ 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! " printMsg(lvlError, format("path `%1%' was modified! "
"expected hash `%2%', got `%3%'") "expected hash `%2%', got `%3%'")
% *i % printHash(info.hash) % printHash(current.first)); % *i % printHash(info.hash) % printHash(current.first));
if (repair) repairPath(*i); else errors = true;
} else { } else {
bool update = false; bool update = false;
@ -1611,14 +1614,17 @@ void LocalStore::verifyStore(bool checkContents)
errors on invalid paths. */ errors on invalid paths. */
if (isValidPath(*i)) throw; if (isValidPath(*i)) throw;
printMsg(lvlError, format("warning: %1%") % e.msg()); printMsg(lvlError, format("warning: %1%") % e.msg());
errors = true;
} }
} }
} }
return errors;
} }
void LocalStore::verifyPath(const Path & path, const PathSet & store, void LocalStore::verifyPath(const Path & path, const PathSet & store,
PathSet & done, PathSet & validPaths) PathSet & done, PathSet & validPaths, bool repair, bool & errors)
{ {
checkInterrupt(); checkInterrupt();
@ -1638,7 +1644,7 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
PathSet referrers; queryReferrers(path, referrers); PathSet referrers; queryReferrers(path, referrers);
foreach (PathSet::iterator, i, referrers) foreach (PathSet::iterator, i, referrers)
if (*i != path) { if (*i != path) {
verifyPath(*i, store, done, validPaths); verifyPath(*i, store, done, validPaths, repair, errors);
if (validPaths.find(*i) != validPaths.end()) if (validPaths.find(*i) != validPaths.end())
canInvalidate = false; canInvalidate = false;
} }
@ -1646,8 +1652,17 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
if (canInvalidate) { if (canInvalidate) {
printMsg(lvlError, format("path `%1%' disappeared, removing from database...") % path); printMsg(lvlError, format("path `%1%' disappeared, removing from database...") % path);
invalidatePath(path); invalidatePath(path);
} else } else {
printMsg(lvlError, format("path `%1%' disappeared, but it still has valid referrers!") % path); 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; return;
} }

View file

@ -171,8 +171,9 @@ public:
/* Optimise a single store path. */ /* Optimise a single store path. */
void optimisePath(const Path & path); void optimisePath(const Path & path);
/* Check the integrity of the Nix store. */ /* Check the integrity of the Nix store. Returns true if errors
void verifyStore(bool checkContents); remain. */
bool verifyStore(bool checkContents, bool repair);
/* Register the validity of a path, i.e., that `path' exists, that /* 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 the paths referenced by it exists, and in the case of an output
@ -250,7 +251,7 @@ private:
void invalidatePathChecked(const Path & path); void invalidatePathChecked(const Path & path);
void verifyPath(const Path & path, const PathSet & store, 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); void updatePathInfo(const ValidPathInfo & info);

View file

@ -703,13 +703,18 @@ static void opVerify(Strings opFlags, Strings opArgs)
throw UsageError("no arguments expected"); throw UsageError("no arguments expected");
bool checkContents = false; bool checkContents = false;
bool repair = false;
for (Strings::iterator i = opFlags.begin(); for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i) i != opFlags.end(); ++i)
if (*i == "--check-contents") checkContents = true; if (*i == "--check-contents") checkContents = true;
else if (*i == "--repair") repair = true;
else throw UsageError(format("unknown flag `%1%'") % *i); 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) { foreach (Strings::iterator, i, opArgs) {
Path path = followLinksToStorePath(*i); Path path = followLinksToStorePath(*i);
printMsg(lvlTalkative, format("repairing path `%1%'...") % path);
ensureLocalStore().repairPath(path); ensureLocalStore().repairPath(path);
} }
} }