* Added a command to verify the consistency of the database.
This commit is contained in:
parent
fa51d6fcd9
commit
2e59698b78
115
src/nix.cc
115
src/nix.cc
|
@ -48,21 +48,29 @@ public:
|
||||||
UsageError(string _err) : Error(_err) { };
|
UsageError(string _err) : Error(_err) { };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BadRefError : public Error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BadRefError(string _err) : Error(_err) { };
|
||||||
|
};
|
||||||
|
|
||||||
/* Wrapper class that ensures that the database is closed upon
|
|
||||||
|
/* Wrapper classes that ensures that the database is closed upon
|
||||||
object destruction. */
|
object destruction. */
|
||||||
class Db2 : public Db
|
class Db2 : public Db
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Db2(DbEnv *env, u_int32_t flags)
|
Db2(DbEnv *env, u_int32_t flags) : Db(env, flags) { }
|
||||||
: Db(env, flags)
|
~Db2() { close(0); }
|
||||||
{
|
};
|
||||||
}
|
|
||||||
|
|
||||||
~Db2()
|
|
||||||
{
|
class DbcClose
|
||||||
close(0);
|
{
|
||||||
}
|
Dbc * cursor;
|
||||||
|
public:
|
||||||
|
DbcClose(Dbc * c) : cursor(c) { }
|
||||||
|
~DbcClose() { cursor->close(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,17 +121,38 @@ void delDB(const string & dbname, const string & key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef pair<string, string> DBPair;
|
||||||
|
typedef list<DBPair> DBPairs;
|
||||||
|
|
||||||
|
|
||||||
|
void enumDB(const string & dbname, DBPairs & contents)
|
||||||
|
{
|
||||||
|
auto_ptr<Db2> db = openDB(dbname, false);
|
||||||
|
|
||||||
|
Dbc * cursor;
|
||||||
|
db->cursor(0, &cursor, 0);
|
||||||
|
DbcClose cursorCloser(cursor);
|
||||||
|
|
||||||
|
Dbt kt, dt;
|
||||||
|
while (cursor->get(&kt, &dt, DB_NEXT) != DB_NOTFOUND) {
|
||||||
|
string key((char *) kt.get_data(), kt.get_size());
|
||||||
|
string data((char *) dt.get_data(), dt.get_size());
|
||||||
|
contents.push_back(DBPair(key, data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Verify that a reference is valid (that is, is a MD5 hash code). */
|
/* Verify that a reference is valid (that is, is a MD5 hash code). */
|
||||||
void checkRef(const string & s)
|
void checkRef(const string & s)
|
||||||
{
|
{
|
||||||
string err = "invalid reference: " + s;
|
string err = "invalid reference: " + s;
|
||||||
if (s.length() != 32)
|
if (s.length() != 32)
|
||||||
throw Error(err);
|
throw BadRefError(err);
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i < 32; i++) {
|
||||||
char c = s[i];
|
char c = s[i];
|
||||||
if (!((c >= '0' && c <= '9') ||
|
if (!((c >= '0' && c <= '9') ||
|
||||||
(c >= 'a' && c <= 'f')))
|
(c >= 'a' && c <= 'f')))
|
||||||
throw Error(err);
|
throw BadRefError(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,11 +162,11 @@ string makeRef(string filename)
|
||||||
{
|
{
|
||||||
char hash[33];
|
char hash[33];
|
||||||
|
|
||||||
FILE * pipe = popen(("md5sum " + filename).c_str(), "r");
|
FILE * pipe = popen(("md5sum " + filename + " 2> /dev/null").c_str(), "r");
|
||||||
if (!pipe) throw Error("cannot execute md5sum");
|
if (!pipe) throw BadRefError("cannot execute md5sum");
|
||||||
|
|
||||||
if (fread(hash, 32, 1, pipe) != 1)
|
if (fread(hash, 32, 1, pipe) != 1)
|
||||||
throw Error("cannot read hash from md5sum");
|
throw BadRefError("cannot read hash from md5sum");
|
||||||
hash[32] = 0;
|
hash[32] = 0;
|
||||||
|
|
||||||
pclose(pipe);
|
pclose(pipe);
|
||||||
|
@ -369,8 +398,48 @@ void initDB()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void verifyDB()
|
||||||
|
{
|
||||||
|
/* Check that all file references are still valid. */
|
||||||
|
DBPairs fileRefs;
|
||||||
|
|
||||||
|
enumDB(dbRefs, fileRefs);
|
||||||
|
|
||||||
|
for (DBPairs::iterator it = fileRefs.begin();
|
||||||
|
it != fileRefs.end(); it++)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (makeRef(it->second) != it->first)
|
||||||
|
delDB(dbRefs, it->first);
|
||||||
|
} catch (BadRefError e) { /* !!! better error check */
|
||||||
|
cerr << "file " << it->second << " has disappeared\n";
|
||||||
|
delDB(dbRefs, it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that all installed packages are still there. */
|
||||||
|
DBPairs instPkgs;
|
||||||
|
|
||||||
|
enumDB(dbInstPkgs, instPkgs);
|
||||||
|
|
||||||
|
for (DBPairs::iterator it = instPkgs.begin();
|
||||||
|
it != instPkgs.end(); it++)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
if (stat(it->second.c_str(), &st) == -1) {
|
||||||
|
cerr << "package " << it->first << " has disappeared\n";
|
||||||
|
delDB(dbInstPkgs, it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: check that all directories in pkgHome are installed
|
||||||
|
packages. */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void run(int argc, char * * argv)
|
void run(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
|
UsageError argcError("wrong number of arguments");
|
||||||
string cmd;
|
string cmd;
|
||||||
|
|
||||||
if (argc < 1)
|
if (argc < 1)
|
||||||
|
@ -380,21 +449,20 @@ void run(int argc, char * * argv)
|
||||||
argc--, argv++;
|
argc--, argv++;
|
||||||
|
|
||||||
if (cmd == "init") {
|
if (cmd == "init") {
|
||||||
if (argc != 0)
|
if (argc != 0) throw argcError;
|
||||||
throw UsageError("wrong number of arguments");
|
|
||||||
initDB();
|
initDB();
|
||||||
|
} else if (cmd == "verify") {
|
||||||
|
if (argc != 0) throw argcError;
|
||||||
|
verifyDB();
|
||||||
} else if (cmd == "getpkg") {
|
} else if (cmd == "getpkg") {
|
||||||
if (argc != 1)
|
if (argc != 1) throw argcError;
|
||||||
throw UsageError("wrong number of arguments");
|
|
||||||
string path = getPkg(argv[0]);
|
string path = getPkg(argv[0]);
|
||||||
cout << path << endl;
|
cout << path << endl;
|
||||||
} else if (cmd == "regfile") {
|
} else if (cmd == "regfile") {
|
||||||
if (argc != 1)
|
if (argc != 1) throw argcError;
|
||||||
throw UsageError("wrong number of arguments");
|
|
||||||
registerFile(argv[0]);
|
registerFile(argv[0]);
|
||||||
} else if (cmd == "reginst") {
|
} else if (cmd == "reginst") {
|
||||||
if (argc != 2)
|
if (argc != 2) throw argcError;
|
||||||
throw UsageError("wrong number of arguments");
|
|
||||||
registerInstalledPkg(argv[0], argv[1]);
|
registerInstalledPkg(argv[0], argv[1]);
|
||||||
} else
|
} else
|
||||||
throw UsageError("unknown command: " + string(cmd));
|
throw UsageError("unknown command: " + string(cmd));
|
||||||
|
@ -411,6 +479,9 @@ Subcommands:
|
||||||
init
|
init
|
||||||
Initialize the database.
|
Initialize the database.
|
||||||
|
|
||||||
|
verify
|
||||||
|
Removes stale entries from the database.
|
||||||
|
|
||||||
regfile FILENAME
|
regfile FILENAME
|
||||||
Register FILENAME keyed by its hash.
|
Register FILENAME keyed by its hash.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue