Instead of using an echo for '-qmp stdio' we use a readline mode. The readline mode adds a history for users which is useful. Tab completion is disabled for now.
Signed-off-by: Pavel Hrdina <phrd...@redhat.com> --- monitor.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- vl.c | 3 ++ 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/monitor.c b/monitor.c index 12a6fe2..3631ef8 100644 --- a/monitor.c +++ b/monitor.c @@ -206,6 +206,8 @@ static const mon_cmd_t qmp_cmds[]; Monitor *cur_mon; Monitor *default_mon; +static void monitor_stdio_control_command_cb(Monitor *mon, const char *cmdline, + void *opaque); static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque); @@ -214,6 +216,11 @@ static inline int qmp_cmd_mode(const Monitor *mon) return (mon->mc ? mon->mc->command_mode : 0); } +static inline int monitor_readline_mode(const Monitor *mon) +{ + return (mon->flags & MONITOR_USE_READLINE); +} + /* Return true if in control mode, false otherwise */ static inline int monitor_ctrl_mode(const Monitor *mon) { @@ -226,6 +233,16 @@ int monitor_cur_is_qmp(void) return cur_mon && monitor_ctrl_mode(cur_mon); } +static void monitor_control_read_command(Monitor *mon, int show_prompt) +{ + if (!mon->rs) + return; + + readline_start(mon->rs, "", 0, monitor_stdio_control_command_cb, NULL); + if (show_prompt) + readline_show_prompt(mon->rs); +} + void monitor_read_command(Monitor *mon, int show_prompt) { if (!mon->rs) @@ -287,7 +304,7 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) mon_print_count_inc(mon); - if (monitor_ctrl_mode(mon)) { + if (monitor_ctrl_mode(mon) && !monitor_readline_mode(mon)) { return; } @@ -3975,6 +3992,11 @@ static const char *next_arg_type(const char *typestr) return (p != NULL ? ++p : typestr); } +static void monitor_control_find_completion(const char *cmdline) +{ + /* TODO: to be implemented */ +} + static void monitor_find_completion(const char *cmdline) { const char *cmdname; @@ -4431,10 +4453,23 @@ out: static void monitor_control_read(void *opaque, const uint8_t *buf, int size) { Monitor *old_mon = cur_mon; + int i; cur_mon = opaque; - json_message_parser_feed(&cur_mon->mc->parser, (const char *) buf, size); + if (monitor_readline_mode(cur_mon)) { + if (cur_mon->rs) { + for (i = 0; i < size; i++) + readline_handle_byte(cur_mon->rs, buf[i]); + } else { + if (size == 0 || buf[size - 1] != 0) + monitor_printf(cur_mon, "corrupted command\n"); + else + json_message_parser_feed(&cur_mon->mc->parser, (const char *) buf, size); + } + } else { + json_message_parser_feed(&cur_mon->mc->parser, (const char *) buf, size); + } cur_mon = old_mon; } @@ -4459,6 +4494,13 @@ static void monitor_read(void *opaque, const uint8_t *buf, int size) cur_mon = old_mon; } +static void monitor_stdio_control_command_cb(Monitor *mon, const char *cmdline, void *opaque) +{ + monitor_suspend(mon); + json_message_parser_feed(&mon->mc->parser, cmdline, strlen(cmdline)); + monitor_resume(mon); +} + static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque) { monitor_suspend(mon); @@ -4499,7 +4541,41 @@ static void monitor_control_event(void *opaque, int event) Monitor *mon = opaque; switch (event) { + case CHR_EVENT_MUX_IN: + if (!monitor_readline_mode(mon)) + break; + mon->mux_out = 0; + if (mon->reset_seen) { + readline_restart(mon->rs); + monitor_resume(mon); + monitor_flush(mon); + } else { + mon->suspend_cnt = 0; + } + break; + + case CHR_EVENT_MUX_OUT: + if (!monitor_readline_mode(mon)) + break; + if (mon->reset_seen) { + if (mon->suspend_cnt == 0) { + monitor_printf(mon, "\n"); + } + monitor_flush(mon); + monitor_suspend(mon); + } else { + mon->suspend_cnt++; + } + mon->mux_out = 1; + break; + case CHR_EVENT_OPENED: + if (monitor_readline_mode(mon)) { + mon->reset_seen = 1; + if (!mon->mux_out) { + readline_show_prompt(mon->rs); + } + } mon->mc->command_mode = 0; json_message_parser_init(&mon->mc->parser, handle_qmp_command); data = get_qmp_greeting(); @@ -4594,9 +4670,14 @@ void monitor_init(CharDriverState *chr, int flags) mon->chr = chr; mon->flags = flags; - if (flags & MONITOR_USE_READLINE) { - mon->rs = readline_init(mon, monitor_find_completion); - monitor_read_command(mon, 0); + if (monitor_readline_mode(mon)) { + if (monitor_ctrl_mode(mon)) { + mon->rs = readline_init(mon, monitor_control_find_completion); + monitor_control_read_command(mon, 0); + } else { + mon->rs = readline_init(mon, monitor_find_completion); + monitor_read_command(mon, 0); + } } if (monitor_ctrl_mode(mon)) { @@ -4604,7 +4685,6 @@ void monitor_init(CharDriverState *chr, int flags) /* Control mode requires special handlers */ qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read, monitor_control_event, mon); - qemu_chr_fe_set_echo(chr, true); } else { qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, monitor_event, mon); diff --git a/vl.c b/vl.c index 23ab3a3..5e9c130 100644 --- a/vl.c +++ b/vl.c @@ -1894,6 +1894,9 @@ static int mon_init_func(QemuOpts *opts, void *opaque) exit(1); } + if ((flags & MONITOR_USE_CONTROL) && strcmp(chr->filename, "stdio") == 0) + flags |= MONITOR_USE_READLINE; + monitor_init(chr, flags); return 0; } -- 1.7.7.6