From d0f5719c2a2e5a0eea49dc072b26e7d161564bbb Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 5 Apr 2016 15:30:22 +0200 Subject: [PATCH] Add "nix copy-sigs" command This imports signatures from one store into another. E.g. $ nix copy-sigs -r /run/current-system -s https://cache.nixos.org/ imported 595 signatures --- src/libstore/binary-cache-store.hh | 3 + src/libstore/local-store.cc | 22 ++++- src/libstore/local-store.hh | 2 + src/libstore/remote-store.cc | 9 ++ src/libstore/remote-store.hh | 2 + src/libstore/store-api.hh | 4 + src/libstore/worker-protocol.hh | 1 + src/nix-daemon/nix-daemon.cc | 12 +++ src/nix/sigs.cc | 133 +++++++++++++++++++++++++++++ 9 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 src/nix/sigs.cc diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh index de6941561..0020f89ee 100644 --- a/src/libstore/binary-cache-store.hh +++ b/src/libstore/binary-cache-store.hh @@ -170,6 +170,9 @@ public: ref getFSAccessor() override; + void addSignatures(const Path & storePath, const StringSet & sigs) + { notImpl(); } + }; } diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 9b961b192..28e340af7 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -312,7 +312,7 @@ void LocalStore::openDB(bool create) stmtRegisterValidPath.create(db, "insert into ValidPaths (path, hash, registrationTime, deriver, narSize, ultimate) values (?, ?, ?, ?, ?, ?);"); stmtUpdatePathInfo.create(db, - "update ValidPaths set narSize = ?, hash = ?, ultimate = ? where path = ?;"); + "update ValidPaths set narSize = ?, hash = ?, ultimate = ?, sigs = ? where path = ?;"); stmtAddReference.create(db, "insert or replace into Refs (referrer, reference) values (?, ?);"); stmtQueryPathInfo.create(db, @@ -683,14 +683,14 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path) } -/* Update path info in the database. Currently only updates the - narSize field. */ +/* Update path info in the database. */ void LocalStore::updatePathInfo(const ValidPathInfo & info) { stmtUpdatePathInfo.use() (info.narSize, info.narSize != 0) ("sha256:" + printHash(info.narHash)) (info.ultimate ? 1 : 0, info.ultimate) + (concatStringsSep(" ", info.sigs), !info.sigs.empty()) (info.path) .exec(); } @@ -1694,4 +1694,20 @@ void LocalStore::vacuumDB() } +void LocalStore::addSignatures(const Path & storePath, const StringSet & sigs) +{ + retrySQLite([&]() { + SQLiteTxn txn(db); + + auto info = queryPathInfo(storePath); + + info.sigs.insert(sigs.begin(), sigs.end()); + + updatePathInfo(info); + + txn.commit(); + }); +} + + } diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index e90894277..ec8146e68 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -182,6 +182,8 @@ public: void setSubstituterEnv(); + void addSignatures(const Path & storePath, const StringSet & sigs) override; + private: Path schemaPath; diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 7893f2a4c..4d5d689dc 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -554,6 +554,15 @@ bool RemoteStore::verifyStore(bool checkContents, bool repair) } +void RemoteStore::addSignatures(const Path & storePath, const StringSet & sigs) +{ + auto conn(connections->get()); + conn->to << wopAddSignatures << storePath << sigs; + conn->processStderr(); + readInt(conn->from); +} + + RemoteStore::Connection::~Connection() { try { diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index 85c8292c7..cede4d332 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -93,6 +93,8 @@ public: bool verifyStore(bool checkContents, bool repair) override; + void addSignatures(const Path & storePath, const StringSet & sigs) override; + private: struct Connection diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 7c6e4c079..4ea360b9d 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -346,6 +346,10 @@ public: /* Return an object to access files in the Nix store. */ virtual ref getFSAccessor() = 0; + /* Add signatures to the specified store path. The signatures are + not verified. */ + virtual void addSignatures(const Path & storePath, const StringSet & sigs) = 0; + /* Utility functions. */ /* Read a derivation, after ensuring its existence through diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh index 4f60c3adc..c10598d5d 100644 --- a/src/libstore/worker-protocol.hh +++ b/src/libstore/worker-protocol.hh @@ -45,6 +45,7 @@ typedef enum { wopOptimiseStore = 34, wopVerifyStore = 35, wopBuildDerivation = 36, + wopAddSignatures = 37, } WorkerOp; diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc index 527f6bca9..439cd3dc0 100644 --- a/src/nix-daemon/nix-daemon.cc +++ b/src/nix-daemon/nix-daemon.cc @@ -543,6 +543,18 @@ static void performOp(ref store, bool trusted, unsigned int clientVe break; } + case wopAddSignatures: { + Path path = readStorePath(from); + StringSet sigs = readStrings(from); + startWork(); + if (!trusted) + throw Error("you are not privileged to add signatures"); + store->addSignatures(path, sigs); + stopWork(); + to << 1; + break; + } + default: throw Error(format("invalid operation %1%") % op); } diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc new file mode 100644 index 000000000..e3544a1fd --- /dev/null +++ b/src/nix/sigs.cc @@ -0,0 +1,133 @@ +#include "affinity.hh" // FIXME +#include "command.hh" +#include "progress-bar.hh" +#include "shared.hh" +#include "store-api.hh" +#include "thread-pool.hh" + +#include + +using namespace nix; + +struct CmdCopySigs : StorePathsCommand +{ + Strings substituterUris; + + CmdCopySigs() + { + mkFlag('s', "substituter", {"store-uri"}, "use signatures from specified store", 1, + [&](Strings ss) { substituterUris.push_back(ss.front()); }); + } + + std::string name() override + { + return "copy-sigs"; + } + + std::string description() override + { + return "copy path signatures from substituters (like binary caches)"; + } + + void run(ref store, Paths storePaths) override + { + restoreAffinity(); // FIXME + + if (substituterUris.empty()) + throw UsageError("you must specify at least one subtituter using ā€˜-sā€™"); + + // FIXME: factor out commonality with MixVerify. + std::vector> substituters; + for (auto & s : substituterUris) + substituters.push_back(openStoreAt(s)); + + ProgressBar progressBar; + + ThreadPool pool; + + std::atomic done{0}; + std::atomic added{0}; + + auto showProgress = [&]() { + return (format("[%d/%d done]") % done % storePaths.size()).str(); + }; + + progressBar.updateStatus(showProgress()); + + auto doPath = [&](const Path & storePath) { + auto activity(progressBar.startActivity(format("getting signatures for ā€˜%sā€™") % storePath)); + + checkInterrupt(); + + auto info = store->queryPathInfo(storePath); + + StringSet newSigs; + + for (auto & store2 : substituters) { + if (!store2->isValidPath(storePath)) continue; + auto info2 = store2->queryPathInfo(storePath); + + /* Don't import signatures that don't match this + binary. */ + if (info.narHash != info2.narHash || + info.narSize != info2.narSize || + info.references != info2.references) + continue; + + for (auto & sig : info2.sigs) + if (!info.sigs.count(sig)) + newSigs.insert(sig); + } + + if (!newSigs.empty()) { + store->addSignatures(storePath, newSigs); + added += newSigs.size(); + } + + done++; + progressBar.updateStatus(showProgress()); + }; + + for (auto & storePath : storePaths) + pool.enqueue(std::bind(doPath, storePath)); + + pool.process(); + + progressBar.done(); + + printMsg(lvlInfo, format("imported %d signatures") % added); + } +}; + +static RegisterCommand r1(make_ref()); + +struct CmdQueryPathSigs : StorePathsCommand +{ + CmdQueryPathSigs() + { + } + + std::string name() override + { + return "query-path-sigs"; + } + + std::string description() override + { + return "print store path signatures"; + } + + void run(ref store, Paths storePaths) override + { + for (auto & storePath : storePaths) { + auto info = store->queryPathInfo(storePath); + std::cout << storePath << " "; + if (info.ultimate) std::cout << "ultimate "; + for (auto & sig : info.sigs) + std::cout << sig << " "; + std::cout << "\n"; + } + } +}; + +static RegisterCommand r2(make_ref());