From 1aca195e52d4fbf76908e6588b55ed8b5b25cfc8 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 20 Mar 2018 15:17:59 +0100 Subject: [PATCH] Hack to get SSH error messages from build-remote E.g. cannot build on 'ssh://mac1': cannot connect to 'mac1': bash: nix-store: command not found cannot build on 'ssh://mac2': cannot connect to 'mac2': Host key verification failed. cannot build on 'ssh://mac3': cannot connect to 'mac3': Received disconnect from 213... port 6001:2: Too many authentication failures Authentication failed. --- src/build-remote/build-remote.cc | 8 ++++++-- src/libstore/build.cc | 5 +++++ src/libutil/util.cc | 23 ++++++++++++++++++++--- src/libutil/util.hh | 4 ++-- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc index 6b294a4d2..9cd01bb61 100644 --- a/src/build-remote/build-remote.cc +++ b/src/build-remote/build-remote.cc @@ -191,8 +191,10 @@ int main (int argc, char * * argv) storeUri = bestMachine->storeUri; } catch (std::exception & e) { - printError("unable to open SSH connection to '%s': %s; trying other available machines...", - bestMachine->storeUri, e.what()); + auto msg = chomp(drainFD(5, false)); + printError("cannot build on '%s': %s%s", + bestMachine->storeUri, e.what(), + (msg.empty() ? "" : ": " + msg)); bestMachine->enabled = false; continue; } @@ -202,6 +204,8 @@ int main (int argc, char * * argv) } connected: + close(5); + std::cerr << "# accept\n" << storeUri << "\n"; auto inputs = readStrings(source); diff --git a/src/libstore/build.cc b/src/libstore/build.cc index b8613427e..5c548755c 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -652,6 +652,11 @@ HookInstance::HookInstance() if (dup2(builderOut.writeSide.get(), 4) == -1) throw SysError("dupping builder's stdout/stderr"); + /* Hack: pass the read side of that fd to allow build-remote + to read SSH error messages. */ + if (dup2(builderOut.readSide.get(), 5) == -1) + throw SysError("dupping builder's stdout/stderr"); + Strings args = { baseNameOf(settings.buildHook), std::to_string(verbosity), diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 764b4e442..ab2d097f8 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -567,21 +567,38 @@ void writeFull(int fd, const string & s, bool allowInterrupts) } -string drainFD(int fd) +string drainFD(int fd, bool block) { StringSink sink; - drainFD(fd, sink); + drainFD(fd, sink, block); return std::move(*sink.s); } -void drainFD(int fd, Sink & sink) +void drainFD(int fd, Sink & sink, bool block) { + int saved; + + Finally finally([&]() { + if (!block) { + if (fcntl(fd, F_SETFL, saved) == -1) + throw SysError("making file descriptor blocking"); + } + }); + + if (!block) { + saved = fcntl(fd, F_GETFL); + if (fcntl(fd, F_SETFL, saved | O_NONBLOCK) == -1) + throw SysError("making file descriptor non-blocking"); + } + std::vector buf(4096); while (1) { checkInterrupt(); ssize_t rd = read(fd, buf.data(), buf.size()); if (rd == -1) { + if (!block && (errno == EAGAIN || errno == EWOULDBLOCK)) + break; if (errno != EINTR) throw SysError("reading from file"); } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 85952535d..743d23861 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -151,9 +151,9 @@ MakeError(EndOfFile, Error) /* Read a file descriptor until EOF occurs. */ -string drainFD(int fd); +string drainFD(int fd, bool block = true); -void drainFD(int fd, Sink & sink); +void drainFD(int fd, Sink & sink, bool block = true); /* Automatic cleanup of resources. */