* Added a command to verify the consistency of the database.

This commit is contained in:
Eelco Dolstra 2003-03-21 15:53:35 +00:00
parent fa51d6fcd9
commit 2e59698b78

View file

@ -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.