diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/db.cc | 116 | ||||
-rw-r--r-- | src/db.hh | 26 | ||||
-rw-r--r-- | src/nix.cc | 142 | ||||
-rw-r--r-- | src/util.cc | 94 | ||||
-rw-r--r-- | src/util.hh | 100 |
6 files changed, 276 insertions, 210 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 31fad89258..ffbaaeb830 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,11 +1,11 @@ bin_PROGRAMS = nix fix -nix_SOURCES = nix.cc md5.c -nix_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall +CXXFLAGS = -DSYSTEM=\"@host@\" -Wall + +nix_SOURCES = nix.cc db.cc util.cc md5.c nix_LDADD = -ldb_cxx-4 -lATerm -fix_SOURCES = fix.cc md5.c -fix_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall +fix_SOURCES = fix.cc util.cc md5.c fix_LDADD = -lATerm install-data-local: diff --git a/src/db.cc b/src/db.cc new file mode 100644 index 0000000000..e9f3a0f9e3 --- /dev/null +++ b/src/db.cc @@ -0,0 +1,116 @@ +#include "db.hh" +#include "util.hh" + +#include <db_cxx.h> + + +/* Wrapper classes that ensures that the database is closed upon + object destruction. */ +class Db2 : public Db +{ +public: + Db2(DbEnv *env, u_int32_t flags) : Db(env, flags) { } + ~Db2() { close(0); } +}; + + +class DbcClose +{ + Dbc * cursor; +public: + DbcClose(Dbc * c) : cursor(c) { } + ~DbcClose() { cursor->close(); } +}; + + +static auto_ptr<Db2> openDB(const string & filename, const string & dbname, + bool readonly) +{ + auto_ptr<Db2> db(new Db2(0, 0)); + + db->open(filename.c_str(), dbname.c_str(), + DB_HASH, readonly ? DB_RDONLY : DB_CREATE, 0666); + + return db; +} + + +static void rethrow(DbException & e) +{ + throw Error(e.what()); +} + + +void createDB(const string & filename, const string & dbname) +{ + try { + openDB(filename, dbname, false); + } catch (DbException e) { rethrow(e); } +} + + +bool queryDB(const string & filename, const string & dbname, + const string & key, string & data) +{ + try { + + int err; + auto_ptr<Db2> db = openDB(filename, dbname, true); + + Dbt kt((void *) key.c_str(), key.length()); + Dbt dt; + + err = db->get(0, &kt, &dt, 0); + if (err) return false; + + data = string((char *) dt.get_data(), dt.get_size()); + + } catch (DbException e) { rethrow(e); } + + return true; +} + + +void setDB(const string & filename, const string & dbname, + const string & key, const string & data) +{ + try { + auto_ptr<Db2> db = openDB(filename, dbname, false); + Dbt kt((void *) key.c_str(), key.length()); + Dbt dt((void *) data.c_str(), data.length()); + db->put(0, &kt, &dt, 0); + } catch (DbException e) { rethrow(e); } +} + + +void delDB(const string & filename, const string & dbname, + const string & key) +{ + try { + auto_ptr<Db2> db = openDB(filename, dbname, false); + Dbt kt((void *) key.c_str(), key.length()); + db->del(0, &kt, 0); + } catch (DbException e) { rethrow(e); } +} + + +void enumDB(const string & filename, const string & dbname, + DBPairs & contents) +{ + try { + + auto_ptr<Db2> db = openDB(filename, 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)); + } + + } catch (DbException e) { rethrow(e); } +} diff --git a/src/db.hh b/src/db.hh new file mode 100644 index 0000000000..0054dbec13 --- /dev/null +++ b/src/db.hh @@ -0,0 +1,26 @@ +#ifndef __DB_H +#define __DB_H + +#include <string> +#include <list> + +using namespace std; + +typedef pair<string, string> DBPair; +typedef list<DBPair> DBPairs; + +void createDB(const string & filename, const string & dbname); + +bool queryDB(const string & filename, const string & dbname, + const string & key, string & data); + +void setDB(const string & filename, const string & dbname, + const string & key, const string & data); + +void delDB(const string & filename, const string & dbname, + const string & key); + +void enumDB(const string & filename, const string & dbname, + DBPairs & contents); + +#endif /* !__DB_H */ diff --git a/src/nix.cc b/src/nix.cc index 38643e3d69..5904bf82d5 100644 --- a/src/nix.cc +++ b/src/nix.cc @@ -11,13 +11,12 @@ #include <sys/types.h> #include <sys/wait.h> -#include <db_cxx.h> - extern "C" { #include <aterm1.h> } #include "util.hh" +#include "db.hh" using namespace std; @@ -30,91 +29,7 @@ static string dbNetSources = "netsources"; static string nixSourcesDir; - - -/* Wrapper classes that ensures that the database is closed upon - object destruction. */ -class Db2 : public Db -{ -public: - Db2(DbEnv *env, u_int32_t flags) : Db(env, flags) { } - ~Db2() { close(0); } -}; - - -class DbcClose -{ - Dbc * cursor; -public: - DbcClose(Dbc * c) : cursor(c) { } - ~DbcClose() { cursor->close(); } -}; - - -auto_ptr<Db2> openDB(const string & dbname, bool readonly) -{ - auto_ptr<Db2> db(new Db2(0, 0)); - - db->open((nixHomeDir + "/var/nix/pkginfo.db").c_str(), dbname.c_str(), - DB_HASH, readonly ? DB_RDONLY : DB_CREATE, 0666); - - return db; -} - - -bool queryDB(const string & dbname, const string & key, string & data) -{ - int err; - auto_ptr<Db2> db = openDB(dbname, true); - - Dbt kt((void *) key.c_str(), key.length()); - Dbt dt; - - err = db->get(0, &kt, &dt, 0); - if (err) return false; - - data = string((char *) dt.get_data(), dt.get_size()); - - return true; -} - - -void setDB(const string & dbname, const string & key, const string & data) -{ - auto_ptr<Db2> db = openDB(dbname, false); - Dbt kt((void *) key.c_str(), key.length()); - Dbt dt((void *) data.c_str(), data.length()); - db->put(0, &kt, &dt, 0); -} - - -void delDB(const string & dbname, const string & key) -{ - auto_ptr<Db2> db = openDB(dbname, false); - Dbt kt((void *) key.c_str(), key.length()); - db->del(0, &kt, 0); -} - - -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)); - } -} +static string nixDB; /* Download object referenced by the given URL into the sources @@ -150,7 +65,7 @@ string getFile(string hash) string fn, url; - if (queryDB(dbRefs, hash, fn)) { + if (queryDB(nixDB, dbRefs, hash, fn)) { /* Verify that the file hasn't changed. !!! race */ if (hashFile(fn) != hash) @@ -163,7 +78,7 @@ string getFile(string hash) throw Error("consistency problem: file fetched from " + url + " should have hash " + hash + ", but it doesn't"); - if (!queryDB(dbNetSources, hash, url)) + if (!queryDB(nixDB, dbNetSources, hash, url)) throw Error("a file with hash " + hash + " is requested, " "but it is not known to exist locally or on the network"); @@ -171,7 +86,7 @@ string getFile(string hash) fn = fetchURL(url); - setDB(dbRefs, hash, fn); + setDB(nixDB, dbRefs, hash, fn); } } @@ -332,7 +247,7 @@ void installPkg(string hash) /* Try to use a prebuilt. */ string prebuiltHash, prebuiltFile; - if (queryDB(dbPrebuilts, hash, prebuiltHash)) { + if (queryDB(nixDB, dbPrebuilts, hash, prebuiltHash)) { try { prebuiltFile = getFile(prebuiltHash); @@ -398,7 +313,7 @@ build: throw; } - setDB(dbInstPkgs, hash, path); + setDB(nixDB, dbInstPkgs, hash, path); } @@ -406,7 +321,7 @@ string getPkg(string hash) { string path; checkHash(hash); - while (!queryDB(dbInstPkgs, hash, path)) + while (!queryDB(nixDB, dbInstPkgs, hash, path)) installPkg(hash); return path; } @@ -470,9 +385,9 @@ void delPkg(string hash) { string path; checkHash(hash); - if (queryDB(dbInstPkgs, hash, path)) { + if (queryDB(nixDB, dbInstPkgs, hash, path)) { int res = system(("chmod -R +w " + path + " && rm -rf " + path).c_str()); // !!! escaping - delDB(dbInstPkgs, hash); // not a bug ??? + delDB(nixDB, dbInstPkgs, hash); // not a bug ??? if (WEXITSTATUS(res) != 0) cerr << "errors deleting " + path + ", ignoring" << endl; } @@ -509,7 +424,7 @@ void registerPrebuilt(string pkgHash, string prebuiltHash) { checkHash(pkgHash); checkHash(prebuiltHash); - setDB(dbPrebuilts, pkgHash, prebuiltHash); + setDB(nixDB, dbPrebuilts, pkgHash, prebuiltHash); } @@ -517,7 +432,7 @@ string registerFile(string filename) { filename = absPath(filename); string hash = hashFile(filename); - setDB(dbRefs, hash, filename); + setDB(nixDB, dbRefs, hash, filename); return hash; } @@ -525,7 +440,7 @@ string registerFile(string filename) void registerURL(string hash, string url) { checkHash(hash); - setDB(dbNetSources, hash, url); + setDB(nixDB, dbNetSources, hash, url); /* !!! currently we allow only one network source per hash */ } @@ -535,18 +450,18 @@ void registerInstalledPkg(string hash, string path) { checkHash(hash); if (path == "") - delDB(dbInstPkgs, hash); + delDB(nixDB, dbInstPkgs, hash); else - setDB(dbInstPkgs, hash, path); + setDB(nixDB, dbInstPkgs, hash, path); } void initDB() { - openDB(dbRefs, false); - openDB(dbInstPkgs, false); - openDB(dbPrebuilts, false); - openDB(dbNetSources, false); + createDB(nixDB, dbRefs); + createDB(nixDB, dbInstPkgs); + createDB(nixDB, dbPrebuilts); + createDB(nixDB, dbNetSources); } @@ -555,7 +470,7 @@ void verifyDB() /* Check that all file references are still valid. */ DBPairs fileRefs; - enumDB(dbRefs, fileRefs); + enumDB(nixDB, dbRefs, fileRefs); for (DBPairs::iterator it = fileRefs.begin(); it != fileRefs.end(); it++) @@ -563,18 +478,18 @@ void verifyDB() try { if (hashFile(it->second) != it->first) { cerr << "file " << it->second << " has changed\n"; - delDB(dbRefs, it->first); + delDB(nixDB, dbRefs, it->first); } } catch (BadRefError e) { /* !!! better error check */ cerr << "file " << it->second << " has disappeared\n"; - delDB(dbRefs, it->first); + delDB(nixDB, dbRefs, it->first); } } /* Check that all installed packages are still there. */ DBPairs instPkgs; - enumDB(dbInstPkgs, instPkgs); + enumDB(nixDB, dbInstPkgs, instPkgs); for (DBPairs::iterator it = instPkgs.begin(); it != instPkgs.end(); it++) @@ -582,7 +497,7 @@ void verifyDB() struct stat st; if (stat(it->second.c_str(), &st) == -1) { cerr << "package " << it->first << " has disappeared\n"; - delDB(dbInstPkgs, it->first); + delDB(nixDB, dbInstPkgs, it->first); } } @@ -595,7 +510,7 @@ void listInstalledPkgs() { DBPairs instPkgs; - enumDB(dbInstPkgs, instPkgs); + enumDB(nixDB, dbInstPkgs, instPkgs); for (DBPairs::iterator it = instPkgs.begin(); it != instPkgs.end(); it++) @@ -777,6 +692,7 @@ void run(Strings::iterator argCur, Strings::iterator argEnd) if (homeDir) nixHomeDir = homeDir; nixSourcesDir = nixHomeDir + "/var/nix/sources"; + nixDB = nixHomeDir + "/var/nix/pkginfo.db"; /* Parse the global flags. */ for ( ; argCur != argEnd; argCur++) { @@ -856,11 +772,7 @@ int main(int argc, char * * argv) argCur++; try { - try { - run(argCur, argEnd); - } catch (DbException e) { - throw Error(e.what()); - } + run(argCur, argEnd); } catch (UsageError & e) { cerr << "error: " << e.what() << endl << "Try `nix -h' for more information.\n"; diff --git a/src/util.cc b/src/util.cc new file mode 100644 index 0000000000..4b7bbac3dd --- /dev/null +++ b/src/util.cc @@ -0,0 +1,94 @@ +#include "util.hh" + + +string thisSystem = SYSTEM; +string nixHomeDir = "/nix"; +string nixHomeDirEnvVar = "NIX"; + + + +string absPath(string filename, string dir) +{ + if (filename[0] != '/') { + if (dir == "") { + char buf[PATH_MAX]; + if (!getcwd(buf, sizeof(buf))) + throw Error("cannot get cwd"); + dir = buf; + } + filename = dir + "/" + filename; + /* !!! canonicalise */ + char resolved[PATH_MAX]; + if (!realpath(filename.c_str(), resolved)) + throw Error("cannot canonicalise path " + filename); + filename = resolved; + } + return filename; +} + + +static string printHash(unsigned char * buf) +{ + ostringstream str; + for (int i = 0; i < 16; i++) { + str.fill('0'); + str.width(2); + str << hex << (int) buf[i]; + } + return str.str(); +} + + +/* Verify that a reference is valid (that is, is a MD5 hash code). */ +bool isHash(const string & s) +{ + if (s.length() != 32) return false; + for (int i = 0; i < 32; i++) { + char c = s[i]; + if (!((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'f'))) + return false; + } + return true; +} + + +void checkHash(const string & s) +{ + if (!isHash(s)) throw BadRefError("invalid reference: " + s); +} + + +/* Compute the MD5 hash of a file. */ +string hashFile(string filename) +{ + unsigned char hash[16]; + FILE * file = fopen(filename.c_str(), "rb"); + if (!file) + throw BadRefError("file `" + filename + "' does not exist"); + int err = md5_stream(file, hash); + fclose(file); + if (err) throw BadRefError("cannot hash file"); + return printHash(hash); +} + + + +/* Return the directory part of the given path, i.e., everything + before the final `/'. */ +string dirOf(string s) +{ + unsigned int pos = s.rfind('/'); + if (pos == string::npos) throw Error("invalid file name"); + return string(s, 0, pos); +} + + +/* Return the base name of the given path, i.e., everything following + the final `/'. */ +string baseNameOf(string s) +{ + unsigned int pos = s.rfind('/'); + if (pos == string::npos) throw Error("invalid file name"); + return string(s, pos + 1); +} diff --git a/src/util.hh b/src/util.hh index 9b3f212de3..2c09efc4d8 100644 --- a/src/util.hh +++ b/src/util.hh @@ -39,104 +39,22 @@ public: typedef vector<string> Strings; -/* !!! the following shouldn't be here; abuse of the preprocessor */ - - /* The canonical system name, as returned by config.guess. */ -static string thisSystem = SYSTEM; +extern string thisSystem; /* The prefix of the Nix installation, and the environment variable that can be used to override the default. */ -static string nixHomeDir = "/nix"; -static string nixHomeDirEnvVar = "NIX"; - - -string absPath(string filename, string dir = "") -{ - if (filename[0] != '/') { - if (dir == "") { - char buf[PATH_MAX]; - if (!getcwd(buf, sizeof(buf))) - throw Error("cannot get cwd"); - dir = buf; - } - filename = dir + "/" + filename; - /* !!! canonicalise */ - char resolved[PATH_MAX]; - if (!realpath(filename.c_str(), resolved)) - throw Error("cannot canonicalise path " + filename); - filename = resolved; - } - return filename; -} - - -string printHash(unsigned char * buf) -{ - ostringstream str; - for (int i = 0; i < 16; i++) { - str.fill('0'); - str.width(2); - str << hex << (int) buf[i]; - } - return str.str(); -} - - -/* Verify that a reference is valid (that is, is a MD5 hash code). */ -bool isHash(const string & s) -{ - if (s.length() != 32) return false; - for (int i = 0; i < 32; i++) { - char c = s[i]; - if (!((c >= '0' && c <= '9') || - (c >= 'a' && c <= 'f'))) - return false; - } - return true; -} - - -void checkHash(const string & s) -{ - if (!isHash(s)) throw BadRefError("invalid reference: " + s); -} - - -/* Compute the MD5 hash of a file. */ -string hashFile(string filename) -{ - unsigned char hash[16]; - FILE * file = fopen(filename.c_str(), "rb"); - if (!file) - throw BadRefError("file `" + filename + "' does not exist"); - int err = md5_stream(file, hash); - fclose(file); - if (err) throw BadRefError("cannot hash file"); - return printHash(hash); -} +extern string nixHomeDir; +extern string nixHomeDirEnvVar; - -/* Return the directory part of the given path, i.e., everything - before the final `/'. */ -string dirOf(string s) -{ - unsigned int pos = s.rfind('/'); - if (pos == string::npos) throw Error("invalid file name"); - return string(s, 0, pos); -} - - -/* Return the base name of the given path, i.e., everything following - the final `/'. */ -string baseNameOf(string s) -{ - unsigned int pos = s.rfind('/'); - if (pos == string::npos) throw Error("invalid file name"); - return string(s, pos + 1); -} +string absPath(string filename, string dir = ""); +bool isHash(const string & s); +void checkHash(const string & s); +string hashFile(string filename); +string dirOf(string s); +string baseNameOf(string s); #endif /* !__UTIL_H */ |