diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2014-02-14T10·42+0100 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2014-02-14T10·42+0100 |
commit | 61fd494d760d667649fa48665f9aa75ba88a1eb6 (patch) | |
tree | 2ce091b595c70f47af9eb50007fdcdcc0b032808 /src/download-via-ssh | |
parent | f9fc6acbf4eadd2d9018d3da14394fdfbddde5f6 (diff) | |
parent | f67f52751f21b2fe70b5a7352053f130eb6f0f59 (diff) |
Merge remote-tracking branch 'shlevy/ssh-substituter'
Diffstat (limited to 'src/download-via-ssh')
-rw-r--r-- | src/download-via-ssh/download-via-ssh.cc | 138 | ||||
-rw-r--r-- | src/download-via-ssh/local.mk | 11 |
2 files changed, 149 insertions, 0 deletions
diff --git a/src/download-via-ssh/download-via-ssh.cc b/src/download-via-ssh/download-via-ssh.cc new file mode 100644 index 000000000000..d85f1572f33e --- /dev/null +++ b/src/download-via-ssh/download-via-ssh.cc @@ -0,0 +1,138 @@ +#include "shared.hh" +#include "util.hh" +#include "serialise.hh" +#include "archive.hh" +#include "affinity.hh" +#include "globals.hh" +#include "serve-protocol.hh" + +#include <iostream> +#include <unistd.h> + +using namespace nix; + +// !!! TODO: +// * Respect more than the first host +// * use a database +// * show progress + +static std::pair<FdSink, FdSource> connect(string conn) { + Pipe to, from; + to.create(); + from.create(); + pid_t child = fork(); + switch (child) { + case -1: + throw SysError("unable to fork"); + case 0: + try { + restoreAffinity(); + if (dup2(to.readSide, STDIN_FILENO) == -1) + throw SysError("dupping stdin"); + if (dup2(from.writeSide, STDOUT_FILENO) == -1) + throw SysError("dupping stdout"); + execlp("ssh" + , "ssh" + , "-x" + , "-T" + , conn.c_str() + , "nix-store --serve" + , NULL); + throw SysError("executing ssh"); + } catch (std::exception & e) { + std::cerr << "error: " << e.what() << std::endl; + } + _exit(1); + } + // If child exits unexpectedly, we'll EPIPE or EOF early. + // If we exit unexpectedly, child will EPIPE or EOF early. + // So no need to keep track of it. + + return std::pair<FdSink, FdSource>(to.writeSide.borrow(), from.readSide.borrow()); +} + +static void substitute(std::pair<FdSink, FdSource> & pipes, Path storePath, Path destPath) { + writeInt(cmdSubstitute, pipes.first); + writeString(storePath, pipes.first); + pipes.first.flush(); + restorePath(destPath, pipes.second); + std::cout << std::endl; +} + +static void query(std::pair<FdSink, FdSource> & pipes) { + writeInt(cmdQuery, pipes.first); + for (string line; getline(std::cin, line);) { + Strings tokenized = tokenizeString<Strings>(line); + string cmd = tokenized.front(); + tokenized.pop_front(); + if (cmd == "have") { + writeInt(qCmdHave, pipes.first); + writeStrings(tokenized, pipes.first); + pipes.first.flush(); + PathSet paths = readStrings<PathSet>(pipes.second); + foreach (PathSet::iterator, i, paths) + std::cout << *i << std::endl; + } else if (cmd == "info") { + writeInt(qCmdInfo, pipes.first); + writeStrings(tokenized, pipes.first); + pipes.first.flush(); + for (Path path = readString(pipes.second); !path.empty(); path = readString(pipes.second)) { + std::cout << path << std::endl; + std::cout << readString(pipes.second) << std::endl; + PathSet references = readStrings<PathSet>(pipes.second); + std::cout << references.size() << std::endl; + foreach (PathSet::iterator, i, references) + std::cout << *i << std::endl; + std::cout << readLongLong(pipes.second) << std::endl; + std::cout << readLongLong(pipes.second) << std::endl; + } + } else + throw Error(format("unknown substituter query `%1%'") % cmd); + std::cout << std::endl; + } +} + +void run(Strings args) +{ + if (args.empty()) + throw UsageError("download-via-ssh requires an argument"); + + if (settings.sshSubstituterHosts.empty()) + return; + + std::cout << std::endl; + + std::pair<FdSink, FdSource> pipes = connect(settings.sshSubstituterHosts.front()); + + /* Exchange the greeting */ + writeInt(SERVE_MAGIC_1, pipes.first); + pipes.first.flush(); + unsigned int magic = readInt(pipes.second); + if (magic != SERVE_MAGIC_2) + throw Error("protocol mismatch"); + readInt(pipes.second); // Server version, unused for now + writeInt(SERVE_PROTOCOL_VERSION, pipes.first); + pipes.first.flush(); + + Strings::iterator i = args.begin(); + if (*i == "--query") + query(pipes); + else if (*i == "--substitute") + if (args.size() != 3) + throw UsageError("download-via-ssh: --substitute takes exactly two arguments"); + else { + Path storePath = *++i; + Path destPath = *++i; + substitute(pipes, storePath, destPath); + } + else + throw UsageError(format("download-via-ssh: unknown command `%1%'") % *i); +} + +void printHelp() +{ + std::cerr << "Usage: download-via-ssh --query|--substitute store-path dest-path" << std::endl; +} + + +string programId = "download-via-ssh"; diff --git a/src/download-via-ssh/local.mk b/src/download-via-ssh/local.mk new file mode 100644 index 000000000000..80f4c385acb3 --- /dev/null +++ b/src/download-via-ssh/local.mk @@ -0,0 +1,11 @@ +programs += download-via-ssh + +download-via-ssh_DIR := $(d) + +download-via-ssh_SOURCES := $(d)/download-via-ssh.cc + +download-via-ssh_INSTALL_DIR := $(libexecdir)/nix/substituters + +download-via-ssh_CXXFLAGS = -Isrc/nix-store + +download-via-ssh_LIBS = libmain libstore libutil libformat |