diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2016-11-09T17·57+0100 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2016-11-09T17·57+0100 |
commit | 4b8f1b0ec066a5b994747b1afd050f5f62d857f6 (patch) | |
tree | a946094a9e4a3a56cfe713b01cd7d27104d56b03 | |
parent | 21c55ab3b54fc2db30ca53c572d24b38331f508c (diff) | |
parent | b99c6e0e2959e90ddda14d8b318e4c7b1a508674 (diff) |
Merge branch 'ssh-store' of https://github.com/shlevy/nix
-rw-r--r-- | src/libstore/binary-cache-store.cc | 7 | ||||
-rw-r--r-- | src/libstore/local-store.cc | 3 | ||||
-rw-r--r-- | src/libstore/remote-fs-accessor.cc | 57 | ||||
-rw-r--r-- | src/libstore/remote-fs-accessor.hh | 29 | ||||
-rw-r--r-- | src/libstore/remote-store.cc | 115 | ||||
-rw-r--r-- | src/libstore/remote-store.hh | 35 | ||||
-rw-r--r-- | src/libstore/ssh-store.cc | 130 | ||||
-rw-r--r-- | src/libstore/store-api.cc | 47 | ||||
-rw-r--r-- | src/libstore/store-api.hh | 14 | ||||
-rw-r--r-- | src/libstore/worker-protocol.hh | 4 | ||||
-rw-r--r-- | src/nix-daemon/nix-daemon.cc | 107 | ||||
-rw-r--r-- | src/nix/command.cc | 2 | ||||
-rw-r--r-- | src/nix/copy.cc | 4 | ||||
-rw-r--r-- | src/nix/sigs.cc | 2 | ||||
-rw-r--r-- | src/nix/verify.cc | 2 |
15 files changed, 466 insertions, 92 deletions
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc index 4125af118cf7..3e07a2aa2b60 100644 --- a/src/libstore/binary-cache-store.cc +++ b/src/libstore/binary-cache-store.cc @@ -6,9 +6,9 @@ #include "globals.hh" #include "nar-info.hh" #include "sync.hh" -#include "worker-protocol.hh" -#include "nar-accessor.hh" +#include "remote-fs-accessor.hh" #include "nar-info-disk-cache.hh" +#include "nar-accessor.hh" #include "json.hh" #include <chrono> @@ -379,8 +379,7 @@ Path BinaryCacheStore::addTextToStore(const string & name, const string & s, ref<FSAccessor> BinaryCacheStore::getFSAccessor() { - return make_ref<BinaryCacheStoreAccessor>(ref<BinaryCacheStore>( - std::dynamic_pointer_cast<BinaryCacheStore>(shared_from_this()))); + return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this())); } } diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index d3a641fd977b..612efde7bb8f 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -37,7 +37,8 @@ namespace nix { LocalStore::LocalStore(const Params & params) - : LocalFSStore(params) + : Store(params) + , LocalFSStore(params) , realStoreDir(get(params, "real", rootDir != "" ? rootDir + "/nix/store" : storeDir)) , dbDir(stateDir + "/db") , linksDir(realStoreDir + "/.links") diff --git a/src/libstore/remote-fs-accessor.cc b/src/libstore/remote-fs-accessor.cc new file mode 100644 index 000000000000..ca14057c2e28 --- /dev/null +++ b/src/libstore/remote-fs-accessor.cc @@ -0,0 +1,57 @@ +#include "remote-fs-accessor.hh" +#include "nar-accessor.hh" + +namespace nix { + + +RemoteFSAccessor::RemoteFSAccessor(ref<Store> store) + : store(store) +{ +} + +std::pair<ref<FSAccessor>, Path> RemoteFSAccessor::fetch(const Path & path_) +{ + auto path = canonPath(path_); + + auto storePath = store->toStorePath(path); + std::string restPath = std::string(path, storePath.size()); + + if (!store->isValidPath(storePath)) + throw InvalidPath(format("path ‘%1%’ is not a valid store path") % storePath); + + auto i = nars.find(storePath); + if (i != nars.end()) return {i->second, restPath}; + + StringSink sink; + store->narFromPath(storePath, sink); + + auto accessor = makeNarAccessor(sink.s); + nars.emplace(storePath, accessor); + return {accessor, restPath}; +} + +FSAccessor::Stat RemoteFSAccessor::stat(const Path & path) +{ + auto res = fetch(path); + return res.first->stat(res.second); +} + +StringSet RemoteFSAccessor::readDirectory(const Path & path) +{ + auto res = fetch(path); + return res.first->readDirectory(res.second); +} + +std::string RemoteFSAccessor::readFile(const Path & path) +{ + auto res = fetch(path); + return res.first->readFile(res.second); +} + +std::string RemoteFSAccessor::readLink(const Path & path) +{ + auto res = fetch(path); + return res.first->readLink(res.second); +} + +} diff --git a/src/libstore/remote-fs-accessor.hh b/src/libstore/remote-fs-accessor.hh new file mode 100644 index 000000000000..28f36c8296e1 --- /dev/null +++ b/src/libstore/remote-fs-accessor.hh @@ -0,0 +1,29 @@ +#pragma once + +#include "fs-accessor.hh" +#include "ref.hh" +#include "store-api.hh" + +namespace nix { + +class RemoteFSAccessor : public FSAccessor +{ + ref<Store> store; + + std::map<Path, ref<FSAccessor>> nars; + + std::pair<ref<FSAccessor>, Path> fetch(const Path & path_); +public: + + RemoteFSAccessor(ref<Store> store); + + Stat stat(const Path & path) override; + + StringSet readDirectory(const Path & path) override; + + std::string readFile(const Path & path) override; + + std::string readLink(const Path & path) override; +}; + +} diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index a4bf7b587083..77faa2f801f1 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -38,9 +38,9 @@ template<class T> T readStorePaths(Store & store, Source & from) template PathSet readStorePaths(Store & store, Source & from); - +/* TODO: Separate these store impls into different files, give them better names */ RemoteStore::RemoteStore(const Params & params, size_t maxConnections) - : LocalFSStore(params) + : Store(params) , connections(make_ref<Pool<Connection>>( maxConnections, [this]() { return openConnection(); }, @@ -50,13 +50,21 @@ RemoteStore::RemoteStore(const Params & params, size_t maxConnections) } -std::string RemoteStore::getUri() +UDSRemoteStore::UDSRemoteStore(const Params & params, size_t maxConnections) + : Store(params) + , LocalFSStore(params) + , RemoteStore(params, maxConnections) +{ +} + + +std::string UDSRemoteStore::getUri() { return "daemon"; } -ref<RemoteStore::Connection> RemoteStore::openConnection() +ref<RemoteStore::Connection> UDSRemoteStore::openConnection() { auto conn = make_ref<Connection>(); @@ -84,46 +92,52 @@ ref<RemoteStore::Connection> RemoteStore::openConnection() conn->from.fd = conn->fd.get(); conn->to.fd = conn->fd.get(); + initConnection(*conn); + + return conn; +} + + +void RemoteStore::initConnection(Connection & conn) +{ /* Send the magic greeting, check for the reply. */ try { - conn->to << WORKER_MAGIC_1; - conn->to.flush(); - unsigned int magic = readInt(conn->from); + conn.to << WORKER_MAGIC_1; + conn.to.flush(); + unsigned int magic = readInt(conn.from); if (magic != WORKER_MAGIC_2) throw Error("protocol mismatch"); - conn->daemonVersion = readInt(conn->from); - if (GET_PROTOCOL_MAJOR(conn->daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION)) + conn.daemonVersion = readInt(conn.from); + if (GET_PROTOCOL_MAJOR(conn.daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION)) throw Error("Nix daemon protocol version not supported"); - if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 10) + if (GET_PROTOCOL_MINOR(conn.daemonVersion) < 10) throw Error("the Nix daemon version is too old"); - conn->to << PROTOCOL_VERSION; + conn.to << PROTOCOL_VERSION; - if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 14) { + if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 14) { int cpu = settings.lockCPU ? lockToCurrentCPU() : -1; if (cpu != -1) - conn->to << 1 << cpu; + conn.to << 1 << cpu; else - conn->to << 0; + conn.to << 0; } - if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 11) - conn->to << false; + if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 11) + conn.to << false; - conn->processStderr(); + conn.processStderr(); } catch (Error & e) { throw Error(format("cannot start daemon worker: %1%") % e.msg()); } setOptions(conn); - - return conn; } -void RemoteStore::setOptions(ref<Connection> conn) +void RemoteStore::setOptions(Connection & conn) { - conn->to << wopSetOptions + conn.to << wopSetOptions << settings.keepFailed << settings.keepGoing << settings.tryFallback @@ -137,16 +151,16 @@ void RemoteStore::setOptions(ref<Connection> conn) << settings.buildCores << settings.useSubstitutes; - if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 12) { + if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 12) { Settings::SettingsMap overrides = settings.getOverrides(); if (overrides["ssh-auth-sock"] == "") overrides["ssh-auth-sock"] = getEnv("SSH_AUTH_SOCK"); - conn->to << overrides.size(); + conn.to << overrides.size(); for (auto & i : overrides) - conn->to << i.first << i.second; + conn.to << i.first << i.second; } - conn->processStderr(); + conn.processStderr(); } @@ -336,27 +350,39 @@ void RemoteStore::addToStore(const ValidPathInfo & info, const ref<std::string> bool repair, bool dontCheckSigs, std::shared_ptr<FSAccessor> accessor) { auto conn(connections->get()); - conn->to << wopImportPaths; - StringSink sink; - sink << 1 // == path follows - ; - assert(nar->size() % 8 == 0); - sink((unsigned char *) nar->data(), nar->size()); - sink - << exportMagic - << info.path - << info.references - << info.deriver - << 0 // == no legacy signature - << 0 // == no path follows - ; - - StringSource source(*sink.s); - conn->processStderr(0, &source); + if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 18) { + conn->to << wopImportPaths; + + StringSink sink; + sink << 1 // == path follows + ; + assert(nar->size() % 8 == 0); + sink((unsigned char *) nar->data(), nar->size()); + sink + << exportMagic + << info.path + << info.references + << info.deriver + << 0 // == no legacy signature + << 0 // == no path follows + ; + + StringSource source(*sink.s); + conn->processStderr(0, &source); + + auto importedPaths = readStorePaths<PathSet>(*this, conn->from); + assert(importedPaths.size() <= 1); + } - auto importedPaths = readStorePaths<PathSet>(*this, conn->from); - assert(importedPaths.size() <= 1); + else { + conn->to << wopAddToStoreNar + << info.path << info.deriver << printHash(info.narHash) + << info.references << info.registrationTime << info.narSize + << info.ultimate << info.sigs << *nar << repair << dontCheckSigs; + // FIXME: don't send nar as a string + conn->processStderr(); + } } @@ -553,7 +579,6 @@ RemoteStore::Connection::~Connection() { try { to.flush(); - fd = -1; } catch (...) { ignoreException(); } diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index b14ce4a97ff9..40f17da300d0 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -18,7 +18,7 @@ template<typename T> class Pool; /* FIXME: RemoteStore is a misnomer - should be something like DaemonStore. */ -class RemoteStore : public LocalFSStore +class RemoteStore : public virtual Store { public: @@ -26,8 +26,6 @@ public: /* Implementations of abstract store API methods. */ - std::string getUri() override; - bool isValidPathUncached(const Path & path) override; PathSet queryValidPaths(const PathSet & paths) override; @@ -87,25 +85,46 @@ public: void addSignatures(const Path & storePath, const StringSet & sigs) override; -private: +protected: struct Connection { - AutoCloseFD fd; FdSink to; FdSource from; unsigned int daemonVersion; - ~Connection(); + virtual ~Connection(); void processStderr(Sink * sink = 0, Source * source = 0); }; + virtual ref<Connection> openConnection() = 0; + + void initConnection(Connection & conn); + ref<Pool<Connection>> connections; - ref<Connection> openConnection(); +private: + + void setOptions(Connection & conn); +}; + +class UDSRemoteStore : public LocalFSStore, public RemoteStore +{ +public: + + UDSRemoteStore(const Params & params, size_t maxConnections = std::numeric_limits<size_t>::max()); + + std::string getUri() override; + +private: + + struct Connection : RemoteStore::Connection + { + AutoCloseFD fd; + }; - void setOptions(ref<Connection> conn); + ref<RemoteStore::Connection> openConnection() override; }; diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc new file mode 100644 index 000000000000..5166485226d9 --- /dev/null +++ b/src/libstore/ssh-store.cc @@ -0,0 +1,130 @@ +#include "store-api.hh" +#include "remote-store.hh" +#include "remote-fs-accessor.hh" +#include "archive.hh" +#include "worker-protocol.hh" +#include "pool.hh" + +namespace nix { + +class SSHStore : public RemoteStore +{ +public: + + SSHStore(string uri, const Params & params, size_t maxConnections = std::numeric_limits<size_t>::max()); + + std::string getUri() override; + + void narFromPath(const Path & path, Sink & sink) override; + + ref<FSAccessor> getFSAccessor() override; + +private: + + struct Connection : RemoteStore::Connection + { + Pid sshPid; + AutoCloseFD out; + AutoCloseFD in; + }; + + ref<RemoteStore::Connection> openConnection() override; + + AutoDelete tmpDir; + + Path socketPath; + + Pid sshMaster; + + string uri; + + Path key; +}; + +SSHStore::SSHStore(string uri, const Params & params, size_t maxConnections) + : Store(params) + , RemoteStore(params, maxConnections) + , tmpDir(createTempDir("", "nix", true, true, 0700)) + , socketPath((Path) tmpDir + "/ssh.sock") + , uri(std::move(uri)) + , key(get(params, "ssh-key", "")) +{ +} + +string SSHStore::getUri() +{ + return "ssh://" + uri; +} + +class ForwardSource : public Source +{ + Source & readSource; + Sink & writeSink; +public: + ForwardSource(Source & readSource, Sink & writeSink) : readSource(readSource), writeSink(writeSink) {} + size_t read(unsigned char * data, size_t len) override + { + auto res = readSource.read(data, len); + writeSink(data, len); + return res; + } +}; + +void SSHStore::narFromPath(const Path & path, Sink & sink) +{ + auto conn(connections->get()); + conn->to << wopNarFromPath << path; + conn->processStderr(); + ParseSink ps; + auto fwd = ForwardSource(conn->from, sink); + parseDump(ps, fwd); +} + +ref<FSAccessor> SSHStore::getFSAccessor() +{ + return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this())); +} + +ref<RemoteStore::Connection> SSHStore::openConnection() +{ + if ((pid_t) sshMaster == -1) { + sshMaster = startProcess([&]() { + if (key.empty()) + execlp("ssh", "ssh", "-N", "-M", "-S", socketPath.c_str(), uri.c_str(), NULL); + else + execlp("ssh", "ssh", "-N", "-M", "-S", socketPath.c_str(), "-i", key.c_str(), uri.c_str(), NULL); + throw SysError("starting ssh master"); + }); + } + + auto conn = make_ref<Connection>(); + Pipe in, out; + in.create(); + out.create(); + conn->sshPid = startProcess([&]() { + if (dup2(in.readSide.get(), STDIN_FILENO) == -1) + throw SysError("duping over STDIN"); + if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1) + throw SysError("duping over STDOUT"); + execlp("ssh", "ssh", "-S", socketPath.c_str(), uri.c_str(), "nix-daemon", "--stdio", NULL); + throw SysError("executing nix-daemon --stdio over ssh"); + }); + in.readSide = -1; + out.writeSide = -1; + conn->out = std::move(out.readSide); + conn->in = std::move(in.writeSide); + conn->to = FdSink(conn->in.get()); + conn->from = FdSource(conn->out.get()); + initConnection(*conn); + return conn; +} + +static RegisterStoreImplementation regStore([]( + const std::string & uri, const Store::Params & params) + -> std::shared_ptr<Store> +{ + if (std::string(uri, 0, 6) != "ssh://") return 0; + return std::make_shared<SSHStore>(uri.substr(6), params); +}); + +} diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index f365406cb961..f7f6c9696688 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -606,7 +606,7 @@ namespace nix { RegisterStoreImplementation::Implementations * RegisterStoreImplementation::implementations = 0; -ref<Store> openStoreAt(const std::string & uri_) +ref<Store> openStore(const std::string & uri_) { auto uri(uri_); Store::Params params; @@ -629,9 +629,22 @@ ref<Store> openStoreAt(const std::string & uri_) } -ref<Store> openStore() +StoreType getStoreType(const std::string & uri, const std::string & stateDir) { - return openStoreAt(getEnv("NIX_REMOTE")); + if (uri == "daemon") { + return tDaemon; + } else if (uri == "local") { + return tLocal; + } else if (uri == "") { + if (access(stateDir.c_str(), R_OK | W_OK) == 0) + return tLocal; + else if (pathExists(settings.nixDaemonSocketFile)) + return tDaemon; + else + return tLocal; + } else { + return tOther; + } } @@ -639,26 +652,14 @@ static RegisterStoreImplementation regStore([]( const std::string & uri, const Store::Params & params) -> std::shared_ptr<Store> { - enum { mDaemon, mLocal, mAuto } mode; - - if (uri == "daemon") mode = mDaemon; - else if (uri == "local") mode = mLocal; - else if (uri == "") mode = mAuto; - else return 0; - - if (mode == mAuto) { - auto stateDir = get(params, "state", settings.nixStateDir); - if (access(stateDir.c_str(), R_OK | W_OK) == 0) - mode = mLocal; - else if (pathExists(settings.nixDaemonSocketFile)) - mode = mDaemon; - else - mode = mLocal; + switch (getStoreType(uri, get(params, "state", settings.nixStateDir))) { + case tDaemon: + return std::shared_ptr<Store>(std::make_shared<UDSRemoteStore>(params)); + case tLocal: + return std::shared_ptr<Store>(std::make_shared<LocalStore>(params)); + default: + return nullptr; } - - return mode == mDaemon - ? std::shared_ptr<Store>(std::make_shared<RemoteStore>(params)) - : std::shared_ptr<Store>(std::make_shared<LocalStore>(params)); }); @@ -679,7 +680,7 @@ std::list<ref<Store>> getDefaultSubstituters() auto addStore = [&](const std::string & uri) { if (done.count(uri)) return; done.insert(uri); - state->stores.push_back(openStoreAt(uri)); + state->stores.push_back(openStore(uri)); }; for (auto uri : settings.get("substituters", Strings())) diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 3057106ec142..6762852cf30e 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -5,6 +5,7 @@ #include "crypto.hh" #include "lru-cache.hh" #include "sync.hh" +#include "globals.hh" #include <atomic> #include <limits> @@ -537,7 +538,7 @@ protected: }; -class LocalFSStore : public Store +class LocalFSStore : public virtual Store { public: const Path rootDir; @@ -604,12 +605,17 @@ void removeTempRoots(); If ‘uri’ is empty, it defaults to ‘direct’ or ‘daemon’ depending on whether the user has write access to the local Nix store/database. set to true *unless* you're going to collect garbage. */ -ref<Store> openStoreAt(const std::string & uri); +ref<Store> openStore(const std::string & uri = getEnv("NIX_REMOTE")); -/* Open the store indicated by the ‘NIX_REMOTE’ environment variable. */ -ref<Store> openStore(); +enum StoreType { + tDaemon, + tLocal, + tOther +}; + +StoreType getStoreType(const std::string & uri = getEnv("NIX_REMOTE"), const std::string & stateDir = settings.nixStateDir); /* Return the default substituter stores, defined by the ‘substituters’ option and various legacy options like diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh index f8cd7cc4be29..6a4ed47cc9fa 100644 --- a/src/libstore/worker-protocol.hh +++ b/src/libstore/worker-protocol.hh @@ -6,7 +6,7 @@ namespace nix { #define WORKER_MAGIC_1 0x6e697863 #define WORKER_MAGIC_2 0x6478696f -#define PROTOCOL_VERSION 0x111 +#define PROTOCOL_VERSION 0x112 #define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00) #define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff) @@ -46,6 +46,8 @@ typedef enum { wopVerifyStore = 35, wopBuildDerivation = 36, wopAddSignatures = 37, + wopNarFromPath = 38, + wopAddToStoreNar = 39 } WorkerOp; diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc index 0e4bcb525a37..c8fa81df13c8 100644 --- a/src/nix-daemon/nix-daemon.cc +++ b/src/nix-daemon/nix-daemon.cc @@ -22,6 +22,7 @@ #include <errno.h> #include <pwd.h> #include <grp.h> +#include <fcntl.h> #if __APPLE__ || __FreeBSD__ #include <sys/ucred.h> @@ -29,6 +30,25 @@ using namespace nix; +#ifndef __linux__ +#define SPLICE_F_MOVE 0 +static ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) +{ + /* We ignore most parameters, we just have them for conformance with the linux syscall */ + char buf[8192]; + auto read_count = read(fd_in, buf, sizeof(buf)); + if (read_count == -1) + return read_count; + auto write_count = decltype<read_count>(0); + while (write_count < read_count) { + auto res = write(fd_out, buf + write_count, read_count - write_count); + if (res == -1) + return res; + write_count += res; + } + return read_count; +} +#endif static FdSource from(STDIN_FILENO); static FdSink to(STDOUT_FILENO); @@ -556,6 +576,37 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe break; } + case wopNarFromPath: { + auto path = readStorePath(*store, from); + startWork(); + stopWork(); + dumpPath(path, to); + break; + } + + case wopAddToStoreNar: { + ValidPathInfo info; + info.path = readStorePath(*store, from); + info.deriver = readString(from); + if (!info.deriver.empty()) + store->assertStorePath(info.deriver); + info.narHash = parseHash(htSHA256, readString(from)); + info.references = readStorePaths<PathSet>(*store, from); + info.registrationTime = readInt(from); + info.narSize = readLongLong(from); + info.ultimate = readLongLong(from); + info.sigs = readStrings<StringSet>(from); + auto nar = make_ref<std::string>(readString(from)); + auto repair = readInt(from) ? true : false; + auto dontCheckSigs = readInt(from) ? true : false; + if (!trusted && dontCheckSigs) + dontCheckSigs = false; + startWork(); + store->addToStore(info, nar, repair, dontCheckSigs, nullptr); + stopWork(); + break; + } + default: throw Error(format("invalid operation %1%") % op); } @@ -885,6 +936,8 @@ int main(int argc, char * * argv) return handleExceptions(argv[0], [&]() { initNix(); + auto stdio = false; + parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--daemon") ; /* ignored for backwards compatibility */ @@ -892,10 +945,62 @@ int main(int argc, char * * argv) showManPage("nix-daemon"); else if (*arg == "--version") printVersion("nix-daemon"); + else if (*arg == "--stdio") + stdio = true; else return false; return true; }); - daemonLoop(argv); + if (stdio) { + if (getStoreType() == tDaemon) { + /* Forward on this connection to the real daemon */ + auto socketPath = settings.nixDaemonSocketFile; + auto s = socket(PF_UNIX, SOCK_STREAM, 0); + if (s == -1) + throw SysError("creating Unix domain socket"); + + auto socketDir = dirOf(socketPath); + if (chdir(socketDir.c_str()) == -1) + throw SysError(format("changing to socket directory ‘%1%’") % socketDir); + + auto socketName = baseNameOf(socketPath); + auto addr = sockaddr_un{}; + addr.sun_family = AF_UNIX; + if (socketName.size() + 1 >= sizeof(addr.sun_path)) + throw Error(format("socket name %1% is too long") % socketName); + strcpy(addr.sun_path, socketName.c_str()); + + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) == -1) + throw SysError(format("cannot connect to daemon at %1%") % socketPath); + + auto nfds = (s > STDIN_FILENO ? s : STDIN_FILENO) + 1; + while (true) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + FD_SET(STDIN_FILENO, &fds); + if (select(nfds, &fds, nullptr, nullptr, nullptr) == -1) + throw SysError("waiting for data from client or server"); + if (FD_ISSET(s, &fds)) { + auto res = splice(s, nullptr, STDOUT_FILENO, nullptr, SIZE_MAX, SPLICE_F_MOVE); + if (res == -1) + throw SysError("splicing data from daemon socket to stdout"); + else if (res == 0) + throw EndOfFile("unexpected EOF from daemon socket"); + } + if (FD_ISSET(STDIN_FILENO, &fds)) { + auto res = splice(STDIN_FILENO, nullptr, s, nullptr, SIZE_MAX, SPLICE_F_MOVE); + if (res == -1) + throw SysError("splicing data from stdin to daemon socket"); + else if (res == 0) + return; + } + } + } else { + processConnection(true); + } + } else { + daemonLoop(argv); + } }); } diff --git a/src/nix/command.cc b/src/nix/command.cc index 37534015b89f..fdf6ae6affaf 100644 --- a/src/nix/command.cc +++ b/src/nix/command.cc @@ -81,7 +81,7 @@ StoreCommand::StoreCommand() void StoreCommand::run() { - run(openStoreAt(storeUri)); + run(openStore(storeUri)); } StorePathsCommand::StorePathsCommand() diff --git a/src/nix/copy.cc b/src/nix/copy.cc index de306cbf91d9..e8317dc393fd 100644 --- a/src/nix/copy.cc +++ b/src/nix/copy.cc @@ -43,8 +43,8 @@ struct CmdCopy : StorePathsCommand if (srcUri.empty() && dstUri.empty()) throw UsageError("you must pass ‘--from’ and/or ‘--to’"); - ref<Store> srcStore = srcUri.empty() ? store : openStoreAt(srcUri); - ref<Store> dstStore = dstUri.empty() ? store : openStoreAt(dstUri); + ref<Store> srcStore = srcUri.empty() ? store : openStore(srcUri); + ref<Store> dstStore = dstUri.empty() ? store : openStore(dstUri); std::string copiedLabel = "copied"; diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc index 0ff1b9f7cea0..d8d8c0f53df0 100644 --- a/src/nix/sigs.cc +++ b/src/nix/sigs.cc @@ -35,7 +35,7 @@ struct CmdCopySigs : StorePathsCommand // FIXME: factor out commonality with MixVerify. std::vector<ref<Store>> substituters; for (auto & s : substituterUris) - substituters.push_back(openStoreAt(s)); + substituters.push_back(openStore(s)); ThreadPool pool; diff --git a/src/nix/verify.cc b/src/nix/verify.cc index 5314a42a46c7..2f8d02fa060e 100644 --- a/src/nix/verify.cc +++ b/src/nix/verify.cc @@ -52,7 +52,7 @@ struct CmdVerify : StorePathsCommand { std::vector<ref<Store>> substituters; for (auto & s : substituterUris) - substituters.push_back(openStoreAt(s)); + substituters.push_back(openStore(s)); auto publicKeys = getDefaultPublicKeys(); |