Quit netconf-cli if `ssh` crashes
Before this, if the our ssh process crashed, we wouldn't know until we
pressed issued a command. This patch adds a waiter/watcher thread which
issues "enter" when the ssh process crashes and that escapes
replxx::Replxx::input. Then cli gracefully exits.
Issue: https://tree.taiga.io/project/jktjkt-netconf-cli/issue/195
Change-Id: I931987626d2dbba0e488987dff15cca22481edfb
diff --git a/src/cli.cpp b/src/cli.cpp
index 4f4328a..3118d94 100644
--- a/src/cli.cpp
+++ b/src/cli.cpp
@@ -5,6 +5,7 @@
* Written by Václav Kubernát <kubervac@fit.cvut.cz>
*
*/
+#include <atomic>
#include <docopt.h>
#include <iostream>
#include <optional>
@@ -63,6 +64,16 @@
#include "cli-netconf.hpp"
#include "netconf_access.hpp"
#define PROGRAM_NAME "netconf-access"
+// FIXME: this should be replaced by C++20 std::jthread at some point
+struct PoorMansJThread {
+ ~PoorMansJThread()
+ {
+ if (thread.joinable()) {
+ thread.join();
+ }
+ }
+ std::thread thread;
+};
#else
#error "Unknown CLI backend"
#endif
@@ -78,6 +89,10 @@
true);
WritableOps writableOps = WritableOps::No;
+ using replxx::Replxx;
+ Replxx lineEditor;
+ std::atomic<int> backendReturnCode = 0;
+
#if defined(SYSREPO_CLI)
auto datastoreType = Datastore::Running;
if (const auto& ds = args["-d"]) {
@@ -143,10 +158,21 @@
}
SshProcess process;
+ PoorMansJThread processWatcher;
std::shared_ptr<NetconfAccess> datastore;
try {
process = sshProcess(args.at("<host>").asString(), args.at("-p").asString());
+ processWatcher.thread = std::thread([&process, &lineEditor, &backendReturnCode] () {
+ process.process.wait();
+ backendReturnCode = process.process.exit_code();
+ // CTRL-U clears from the cursor to the start of the line
+ // CTRL-K clears from the cursor to the end of the line
+ // CTRL-D send EOF
+ lineEditor.emulate_key_press(replxx::Replxx::KEY::control('U'));
+ lineEditor.emulate_key_press(replxx::Replxx::KEY::control('K'));
+ lineEditor.emulate_key_press(replxx::Replxx::KEY::control('D'));
+ });
datastore = std::make_shared<NetconfAccess>(process.std_out.native_source(), process.std_in.native_sink());
} catch (std::runtime_error& ex) {
std::cerr << "SSH connection failed: " << ex.what() << "\n";
@@ -170,10 +196,6 @@
auto dataQuery = std::make_shared<DataQuery>(*datastore);
Parser parser(datastore->schema(), writableOps, dataQuery);
- using replxx::Replxx;
-
- Replxx lineEditor;
-
lineEditor.bind_key(Replxx::KEY::meta(Replxx::KEY::BACKSPACE), [&lineEditor](const auto& code) {
return lineEditor.invoke(Replxx::ACTION::KILL_TO_BEGINING_OF_WORD, code);
});
@@ -204,7 +226,7 @@
lineEditor.history_load(historyFile.value());
}
- while (true) {
+ while (backendReturnCode == 0) {
auto line = lineEditor.input(parser.currentNode() + "> ");
if (!line) {
// If user pressed CTRL-C to abort the line, errno gets set to EAGAIN.
@@ -242,5 +264,5 @@
lineEditor.history_save(historyFile.value());
}
- return 0;
+ return backendReturnCode;
}