summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÍñigo Huguet <ihuguet@redhat.com>2023-07-17 10:56:35 +0200
committerÍñigo Huguet <ihuguet@redhat.com>2023-07-17 12:58:07 +0200
commitd414265ab17c54f7b5bc27a55536ca99c77ee80a (patch)
treeca9d72c481b31827f908e24d2212f9d6b9159ed3
parent5490604084589b5387601b5821f86b76d8497001 (diff)
nmcli: fix endless loop with --offline --ask
If --offline and --ask were used at the same time, and endless loop showing the readline's prompt but without waiting for user's input happened. This was because when using --offline, all arguments are parsed and resolved before running the g_main_loop. In nmc_readline_helper it was checked that the main loop is running, so if g_main_loop_quit is called we can stop waiting for user's input. Fix this bug by continue polling for user input if the main loop is running or if we are in offline mode. Cancelling the user input is still possible both in normal and offline mode with Ctrl+C or Ctrl+D. Added a test case to verify that this still works after future changes.
-rw-r--r--src/nmcli/common.c5
-rwxr-xr-xsrc/tests/client/test-client.py56
2 files changed, 57 insertions, 4 deletions
diff --git a/src/nmcli/common.c b/src/nmcli/common.c
index 01fe9a375f..2e8ded7e44 100644
--- a/src/nmcli/common.c
+++ b/src/nmcli/common.c
@@ -880,7 +880,8 @@ read_again:
rl_got_line = FALSE;
rl_callback_handler_install(prompt, readline_cb);
- while (!rl_got_line && g_main_loop_is_running(loop) && !nmc_seen_sigint())
+ while (!rl_got_line && (g_main_loop_is_running(loop) || nmc_config->offline)
+ && !nmc_seen_sigint())
g_main_context_iteration(NULL, TRUE);
/* If Ctrl-C was detected, complete the line */
@@ -909,7 +910,7 @@ read_again:
}
} else if (!rl_string) {
/* Ctrl-D, exit */
- if (g_main_loop_is_running(loop))
+ if (g_main_loop_is_running(loop) || nmc_config->offline)
nmc_exit();
}
diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py
index 391c14d1c3..b618fb9703 100755
--- a/src/tests/client/test-client.py
+++ b/src/tests/client/test-client.py
@@ -703,11 +703,14 @@ class Util:
return typ(pexp, valgrind_log)
@staticmethod
- def cmd_call_pexpect_nmcli(args):
+ def cmd_call_pexpect_nmcli(args, extra_env={}):
+ extra_env = extra_env.copy()
+ extra_env.update({"NO_COLOR": "1"})
+
return Util.cmd_call_pexpect(
ENV_NM_TEST_CLIENT_NMCLI_PATH,
args,
- {"NO_COLOR": "1"},
+ extra_env,
)
@@ -2160,6 +2163,55 @@ class TestNmcli(unittest.TestCase):
@Util.skip_without_pexpect
@nm_test
+ def test_ask_offline(self):
+ # Make sure we're not using D-Bus
+ no_dbus_env = {
+ "DBUS_SYSTEM_BUS_ADDRESS": "very:invalid",
+ "DBUS_SESSION_BUS_ADDRESS": "very:invalid",
+ }
+
+ nmc = Util.cmd_call_pexpect_nmcli(
+ ["--offline", "--ask", "c", "add"], extra_env=no_dbus_env
+ )
+ nmc.pexp.expect("Connection type:")
+ nmc.pexp.sendline("ethernet")
+ nmc.pexp.expect("Interface name:")
+ nmc.pexp.sendline("eth0")
+ nmc.pexp.expect("There are 3 optional settings for Wired Ethernet.")
+ nmc.pexp.expect("Do you want to provide them\? \(yes/no\) \[yes]")
+ nmc.pexp.sendline("no")
+ nmc.pexp.expect("There are 2 optional settings for IPv4 protocol.")
+ nmc.pexp.expect("Do you want to provide them\? \(yes/no\) \[yes]")
+ nmc.pexp.sendline("no")
+ nmc.pexp.expect("There are 2 optional settings for IPv6 protocol.")
+ nmc.pexp.expect("Do you want to provide them\? \(yes/no\) \[yes]")
+ nmc.pexp.sendline("no")
+ nmc.pexp.expect("There are 4 optional settings for Proxy.")
+ nmc.pexp.expect("Do you want to provide them\? \(yes/no\) \[yes]")
+ nmc.pexp.sendline("no")
+ nmc.pexp.expect(
+ "\[connection\]\r\n"
+ + "id=ethernet\r\n"
+ + "uuid=.*\r\n"
+ + "type=ethernet\r\n"
+ + "interface-name=eth0\r\n"
+ + "\r\n"
+ + "\[ethernet\]\r\n"
+ + "\r\n"
+ + "\[ipv4\]\r\n"
+ + "method=auto\r\n"
+ + "\r\n"
+ + "\[ipv6\]\r\n"
+ + "addr-gen-mode=default\r\n"
+ + "method=auto\r\n"
+ + "\r\n"
+ + "\[proxy\]\r\n"
+ )
+ nmc.pexp.expect(pexpect.EOF)
+ Util.valgrind_check_log(nmc.valgrind_log, "test_ask_offline")
+
+ @Util.skip_without_pexpect
+ @nm_test
def test_monitor(self):
def start_mon(self):
nmc = Util.cmd_call_pexpect_nmcli(["monitor"])