From 61cdb0b0576017a636eabb6899aac097bb7718c0 Mon Sep 17 00:00:00 2001
From: Alexander Bantyev <balsoft@balsoft.ru>
Date: Tue, 16 May 2023 16:48:04 +0400
Subject: [PATCH] Fix ControlMaster behaviour

---
 src/libstore/ssh.cc | 23 ++++++++++++++++-------
 src/libstore/ssh.hh |  1 +
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc
index 6f6deda51..fae99d75b 100644
--- a/src/libstore/ssh.cc
+++ b/src/libstore/ssh.cc
@@ -41,6 +41,11 @@ void SSHMaster::addCommonSSHOpts(Strings & args)
     args.push_back("-oLocalCommand=echo started");
 }
 
+bool SSHMaster::isMasterRunning() {
+    auto res = runProgram(RunOptions {.program = "ssh", .args = {"-O", "check", host}, .mergeStderrToStdout = true});
+    return res.first == 0;
+}
+
 std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string & command)
 {
     Path socketPath = startMaster();
@@ -97,7 +102,7 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
 
     // Wait for the SSH connection to be established,
     // So that we don't overwrite the password prompt with our progress bar.
-    if (!fakeSSH && !useMaster) {
+    if (!fakeSSH && !useMaster && !isMasterRunning()) {
         std::string reply;
         try {
             reply = readLine(out.readSide.get());
@@ -133,6 +138,8 @@ Path SSHMaster::startMaster()
     logger->pause();
     Finally cleanup = [&]() { logger->resume(); };
 
+    bool wasMasterRunning = isMasterRunning();
+
     state->sshMaster = startProcess([&]() {
         restoreProcessContext();
 
@@ -152,13 +159,15 @@ Path SSHMaster::startMaster()
 
     out.writeSide = -1;
 
-    std::string reply;
-    try {
-        reply = readLine(out.readSide.get());
-    } catch (EndOfFile & e) { }
+    if (!wasMasterRunning) {
+        std::string reply;
+        try {
+            reply = readLine(out.readSide.get());
+        } catch (EndOfFile & e) { }
 
-    if (reply != "started")
-        throw Error("failed to start SSH master connection to '%s'", host);
+        if (reply != "started")
+            throw Error("failed to start SSH master connection to '%s'", host);
+    }
 
     return state->socketPath;
 }
diff --git a/src/libstore/ssh.hh b/src/libstore/ssh.hh
index c86a8a986..94b952af9 100644
--- a/src/libstore/ssh.hh
+++ b/src/libstore/ssh.hh
@@ -28,6 +28,7 @@ private:
     Sync<State> state_;
 
     void addCommonSSHOpts(Strings & args);
+    bool isMasterRunning();
 
 public: