While the 'complete' command is meant to be hidden and used only for
the completion script, there's nothing preventing it being used in all
virsh modes.
This poses a problem as the command tries to close 'stdin' to avoid the
possibility that an auth callback would want to read the password.
In interactive mode this immediately terminates virsh and in
non-interactive mode it attempts to close it multiple times if you use
virsh in batch mode.
Fix the issues by using virOnce() to close it exactly once and do so
only in non-interactive mode.
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
tools/vsh.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/tools/vsh.c b/tools/vsh.c
index d6c05c46e6..8719875413 100644
--- a/tools/vsh.c
+++ b/tools/vsh.c
@@ -3401,11 +3401,25 @@ const vshCmdInfo info_complete = {
#ifdef WITH_READLINE
+
+static virOnceControl vshCmdCompleteCloseStdinOnce = VIR_ONCE_CONTROL_INITIALIZER;
+
+static void
+vshCmdCompleteCloseStdin(void)
+{
+ /* In non-interactive mode which is how the 'complete' command is intended
+ * to be used we need to ensure that any authentication callback will not
+ * attempt to read any input which would break the completion */
+ int stdin_fileno = STDIN_FILENO;
+
+ VIR_FORCE_CLOSE(stdin_fileno);
+}
+
+
bool
cmdComplete(vshControl *ctl, const vshCmd *cmd)
{
const vshClientHooks *hooks = ctl->hooks;
- int stdin_fileno = STDIN_FILENO;
const char *arg = "";
const vshCmdOpt *opt = NULL;
g_auto(GStrv) matches = NULL;
@@ -3418,7 +3432,10 @@ cmdComplete(vshControl *ctl, const vshCmd *cmd)
/* This command is flagged VSH_CMD_FLAG_NOCONNECT because we
* need to prevent auth hooks reading any input. Therefore, we
* have to close stdin and then connect ourselves. */
- VIR_FORCE_CLOSE(stdin_fileno);
+ if (!ctl->imode) {
+ if (virOnce(&vshCmdCompleteCloseStdinOnce, vshCmdCompleteCloseStdin) < 0)
+ return false;
+ }
if (!(hooks && hooks->connHandler && hooks->connHandler(ctl)))
return false;
--
2.44.0