diff options
-rw-r--r-- | src/libstore/local-store.cc | 22 | ||||
-rw-r--r-- | src/libstore/remote-store.cc | 23 | ||||
-rw-r--r-- | src/libstore/remote-store.hh | 4 | ||||
-rw-r--r-- | src/libstore/ssh-store.cc | 1 | ||||
-rw-r--r-- | src/libstore/store-api.cc | 53 | ||||
-rw-r--r-- | src/libstore/store-api.hh | 10 | ||||
-rw-r--r-- | src/nix-daemon/nix-daemon.cc | 37 | ||||
-rw-r--r-- | src/nix/doctor.cc | 4 | ||||
-rw-r--r-- | tests/local.mk | 1 | ||||
-rw-r--r-- | tests/ssh-relay.sh | 16 |
10 files changed, 83 insertions, 88 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index a79b2da44..84f8d7752 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -1533,5 +1533,27 @@ void LocalStore::createUser(const std::string & userName, uid_t userId) } } +static bool isNonUriPath(const std::string & spec) { + return + // is not a URL + spec.find("://") == std::string::npos + // Has at least one path separator, and so isn't a single word that + // might be special like "auto" + && spec.find("/") != std::string::npos; +} + +static RegisterStoreImplementation regStore([]( + const std::string & uri, const Store::Params & params) + -> std::shared_ptr<Store> +{ + Store::Params params2 = params; + if (uri == "local") { + } else if (isNonUriPath(uri)) { + params2["root"] = absPath(uri); + } else { + return nullptr; + } + return std::shared_ptr<Store>(std::make_shared<LocalStore>(params2)); +}); } diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index dc61951d3..d890042bb 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -96,7 +96,16 @@ RemoteStore::RemoteStore(const Params & params) : Store(params) , connections(make_ref<Pool<Connection>>( std::max(1, (int) maxConnections), - [this]() { return openConnectionWrapper(); }, + [this]() { + auto conn = openConnectionWrapper(); + try { + initConnection(*conn); + } catch (...) { + failed = true; + throw; + } + return conn; + }, [this](const ref<Connection> & r) { return r->to.good() @@ -179,8 +188,6 @@ ref<RemoteStore::Connection> UDSRemoteStore::openConnection() conn->startTime = std::chrono::steady_clock::now(); - initConnection(*conn); - return conn; } @@ -982,14 +989,18 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source * return nullptr; } -static std::string uriScheme = "unix://"; +static std::string_view uriScheme = "unix://"; static RegisterStoreImplementation regStore([]( const std::string & uri, const Store::Params & params) -> std::shared_ptr<Store> { - if (std::string(uri, 0, uriScheme.size()) != uriScheme) return 0; - return std::make_shared<UDSRemoteStore>(std::string(uri, uriScheme.size()), params); + if (hasPrefix(uri, uriScheme)) + return std::make_shared<UDSRemoteStore>(std::string(uri, uriScheme.size()), params); + else if (uri == "daemon") + return std::make_shared<UDSRemoteStore>(params); + else + return nullptr; }); } diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index 6f05f2197..eaeb68e57 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -102,8 +102,6 @@ public: void flushBadConnections(); -protected: - struct Connection { AutoCloseFD fd; @@ -119,6 +117,8 @@ protected: ref<Connection> openConnectionWrapper(); +protected: + virtual ref<Connection> openConnection() = 0; void initConnection(Connection & conn); diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc index 6cb97c1f1..046b5710a 100644 --- a/src/libstore/ssh-store.cc +++ b/src/libstore/ssh-store.cc @@ -72,7 +72,6 @@ ref<RemoteStore::Connection> SSHStore::openConnection() + (remoteStore.get() == "" ? "" : " --store " + shellEscape(remoteStore.get()))); conn->to = FdSink(conn->sshConn->in.get()); conn->from = FdSource(conn->sshConn->out.get()); - initConnection(*conn); return conn; } diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index a41441079..ba4459bbe 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -1046,51 +1046,24 @@ ref<Store> openStore(const std::string & uri_, throw Error("don't know how to open Nix store '%s'", uri); } -static bool isNonUriPath(const std::string & spec) { - return - // is not a URL - spec.find("://") == std::string::npos - // Has at least one path separator, and so isn't a single word that - // might be special like "auto" - && spec.find("/") != std::string::npos; -} - -StoreType getStoreType(const std::string & uri, const std::string & stateDir) -{ - if (uri == "daemon") { - return tDaemon; - } else if (uri == "local" || isNonUriPath(uri)) { - return tLocal; - } else if (uri == "" || uri == "auto") { - 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; - } -} - +// Specific prefixes are handled by the specific types of store, while here we +// handle the general cases not covered by the other ones. static RegisterStoreImplementation regStore([]( const std::string & uri, const Store::Params & params) -> std::shared_ptr<Store> { - switch (getStoreType(uri, get(params, "state").value_or(settings.nixStateDir))) { - case tDaemon: - return std::shared_ptr<Store>(std::make_shared<UDSRemoteStore>(params)); - case tLocal: { - Store::Params params2 = params; - if (isNonUriPath(uri)) { - params2["root"] = absPath(uri); - } - return std::shared_ptr<Store>(std::make_shared<LocalStore>(params2)); - } - default: - return nullptr; - } + auto stateDir = get(params, "state").value_or(settings.nixStateDir); + if (uri == "" || uri == "auto") { + if (access(stateDir.c_str(), R_OK | W_OK) == 0) + return std::make_shared<LocalStore>(params); + else if (pathExists(settings.nixDaemonSocketFile)) + return std::make_shared<UDSRemoteStore>(params); + else + return std::make_shared<LocalStore>(params); + } else { + return nullptr; + } }); diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 61aa3ba7e..52f0916f2 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -728,16 +728,6 @@ ref<Store> openStore(const std::string & uri = settings.storeUri.get(), const Store::Params & extraParams = Store::Params()); -enum StoreType { - tDaemon, - tLocal, - tOther -}; - - -StoreType getStoreType(const std::string & uri = settings.storeUri.get(), - const std::string & stateDir = settings.nixStateDir); - /* Return the default substituter stores, defined by the ‘substituters’ option and various legacy options. */ std::list<ref<Store>> getDefaultSubstituters(); diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc index cfa634a44..6e652ccbf 100644 --- a/src/nix-daemon/nix-daemon.cc +++ b/src/nix-daemon/nix-daemon.cc @@ -1,5 +1,6 @@ #include "shared.hh" #include "local-store.hh" +#include "remote-store.hh" #include "util.hh" #include "serialise.hh" #include "archive.hh" @@ -285,44 +286,28 @@ static int _main(int argc, char * * argv) initPlugins(); 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("changing to socket directory '%1%'", socketDir); - - auto socketName = std::string(baseNameOf(socketPath)); - auto addr = sockaddr_un{}; - addr.sun_family = AF_UNIX; - if (socketName.size() + 1 >= sizeof(addr.sun_path)) - throw Error("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("cannot connect to daemon at %1%", socketPath); - - auto nfds = (s > STDIN_FILENO ? s : STDIN_FILENO) + 1; + if (auto store = openUncachedStore().dynamic_pointer_cast<RemoteStore>()) { + auto conn = store->openConnectionWrapper(); + int from = conn->from.fd; + int to = conn->to.fd; + + auto nfds = std::max(from, STDIN_FILENO) + 1; while (true) { fd_set fds; FD_ZERO(&fds); - FD_SET(s, &fds); + FD_SET(from, &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, SSIZE_MAX, SPLICE_F_MOVE); + if (FD_ISSET(from, &fds)) { + auto res = splice(from, nullptr, STDOUT_FILENO, nullptr, SSIZE_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, SSIZE_MAX, SPLICE_F_MOVE); + auto res = splice(STDIN_FILENO, nullptr, to, nullptr, SSIZE_MAX, SPLICE_F_MOVE); if (res == -1) throw SysError("splicing data from stdin to daemon socket"); else if (res == 0) diff --git a/src/nix/doctor.cc b/src/nix/doctor.cc index 82e92cdd0..683e91446 100644 --- a/src/nix/doctor.cc +++ b/src/nix/doctor.cc @@ -49,9 +49,7 @@ struct CmdDoctor : StoreCommand { logger->log("Running checks against store uri: " + store->getUri()); - auto type = getStoreType(); - - if (type < tOther) { + if (store.dynamic_pointer_cast<LocalFSStore>()) { success &= checkNixInPath(); success &= checkProfileRoots(store); } diff --git a/tests/local.mk b/tests/local.mk index 53035da41..fd9438386 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -15,6 +15,7 @@ nix_tests = \ linux-sandbox.sh \ build-dry.sh \ build-remote-input-addressed.sh \ + ssh-relay.sh \ nar-access.sh \ structured-attrs.sh \ fetchGit.sh \ diff --git a/tests/ssh-relay.sh b/tests/ssh-relay.sh new file mode 100644 index 000000000..dce50974b --- /dev/null +++ b/tests/ssh-relay.sh @@ -0,0 +1,16 @@ +source common.sh + +echo foo > $TEST_ROOT/hello.sh + +ssh_localhost=ssh://localhost +remote_store=?remote-store=$ssh_localhost + +store=$ssh_localhost + +store+=$remote_store +store+=$remote_store +store+=$remote_store + +out=$(nix add-to-store --store "$store" $TEST_ROOT/hello.sh) + +[ foo = $(< $out) ] |