From f2098725aa3ebdb4095bc1951c1c0680adbdecc7 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 24 Feb 2020 15:30:04 +0100 Subject: monitor: Create QAPIfied monitor_init() This adds a new QAPI-based monitor_init() function. The existing monitor_init_opts() is rewritten to simply put its QemuOpts parameter into a visitor and pass the resulting QAPI object to monitor_init(). This will cause some change in those error messages for the monitor options in the system emulator that are now generated by the visitor rather than explicitly checked in monitor_init_opts(). Signed-off-by: Kevin Wolf Message-Id: <20200224143008.13362-17-kwolf@redhat.com> Acked-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- monitor/monitor.c | 77 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 35 deletions(-) (limited to 'monitor/monitor.c') diff --git a/monitor/monitor.c b/monitor/monitor.c index c1a6c4460f..f8a6ef795b 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -25,7 +25,9 @@ #include "qemu/osdep.h" #include "monitor-internal.h" #include "qapi/error.h" +#include "qapi/opts-visitor.h" #include "qapi/qapi-emit-events.h" +#include "qapi/qapi-visit-control.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" #include "qemu/error-report.h" @@ -609,50 +611,55 @@ void monitor_init_globals_core(void) NULL); } -int monitor_init_opts(QemuOpts *opts, Error **errp) +int monitor_init(MonitorOptions *opts, Error **errp) { Chardev *chr; - bool qmp; - bool pretty = false; - const char *chardev; - const char *mode; - - mode = qemu_opt_get(opts, "mode"); - if (mode == NULL) { - mode = "readline"; - } - if (strcmp(mode, "readline") == 0) { - qmp = false; - } else if (strcmp(mode, "control") == 0) { - qmp = true; - } else { - error_setg(errp, "unknown monitor mode \"%s\"", mode); + + chr = qemu_chr_find(opts->chardev); + if (chr == NULL) { + error_setg(errp, "chardev \"%s\" not found", opts->chardev); return -1; } - if (!qmp && qemu_opt_get(opts, "pretty")) { - warn_report("'pretty' is deprecated for HMP monitors, it has no effect " - "and will be removed in future versions"); - } - if (qemu_opt_get_bool(opts, "pretty", 0)) { - pretty = true; + switch (opts->mode) { + case MONITOR_MODE_CONTROL: + monitor_init_qmp(chr, opts->pretty); + break; + case MONITOR_MODE_READLINE: + if (opts->pretty) { + warn_report("'pretty' is deprecated for HMP monitors, it has no " + "effect and will be removed in future versions"); + } + monitor_init_hmp(chr, true); + break; + default: + g_assert_not_reached(); } - chardev = qemu_opt_get(opts, "chardev"); - if (!chardev) { - error_report("chardev is required"); - exit(1); - } - chr = qemu_chr_find(chardev); - if (chr == NULL) { - error_setg(errp, "chardev \"%s\" not found", chardev); - return -1; + return 0; +} + +int monitor_init_opts(QemuOpts *opts, Error **errp) +{ + Visitor *v; + MonitorOptions *options; + Error *local_err = NULL; + + v = opts_visitor_new(opts); + visit_type_MonitorOptions(v, NULL, &options, &local_err); + visit_free(v); + + if (local_err) { + goto out; } - if (qmp) { - monitor_init_qmp(chr, pretty); - } else { - monitor_init_hmp(chr, true); + monitor_init(options, &local_err); + qapi_free_MonitorOptions(options); + +out: + if (local_err) { + error_propagate(errp, local_err); + return -1; } return 0; } -- cgit 1.4.1 From f27a9bb3e9c3bd822243f6fc1d921f1334e37acf Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 24 Feb 2020 15:30:05 +0100 Subject: qmp: Fail gracefully if chardev is already in use Trying to attach a QMP monitor to a chardev that is already in use results in a crash because monitor_init_qmp() passes &error_abort to qemu_chr_fe_init(): $ ./x86_64-softmmu/qemu-system-x86_64 --chardev stdio,id=foo --mon foo,mode=control --mon foo,mode=control Unexpected error in qemu_chr_fe_init() at chardev/char-fe.c:220: qemu-system-x86_64: --mon foo,mode=control: Device 'foo' is in use Abgebrochen (Speicherabzug geschrieben) Fix this by allowing monitor_init_qmp() to return an error and passing any error in qemu_chr_fe_init() to its caller instead of aborting. Signed-off-by: Kevin Wolf Message-Id: <20200224143008.13362-18-kwolf@redhat.com> Acked-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- include/monitor/monitor.h | 2 +- monitor/monitor.c | 7 ++++++- monitor/qmp.c | 11 +++++++---- stubs/monitor-core.c | 2 +- tests/test-util-sockets.c | 2 +- 5 files changed, 16 insertions(+), 8 deletions(-) (limited to 'monitor/monitor.c') diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index db1112552c..e55a3b57e0 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -17,7 +17,7 @@ bool monitor_cur_is_qmp(void); void monitor_init_globals(void); void monitor_init_globals_core(void); -void monitor_init_qmp(Chardev *chr, bool pretty); +void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp); void monitor_init_hmp(Chardev *chr, bool use_readline); int monitor_init(MonitorOptions *opts, Error **errp); int monitor_init_opts(QemuOpts *opts, Error **errp); diff --git a/monitor/monitor.c b/monitor/monitor.c index f8a6ef795b..00d287655e 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -614,6 +614,7 @@ void monitor_init_globals_core(void) int monitor_init(MonitorOptions *opts, Error **errp) { Chardev *chr; + Error *local_err = NULL; chr = qemu_chr_find(opts->chardev); if (chr == NULL) { @@ -623,7 +624,7 @@ int monitor_init(MonitorOptions *opts, Error **errp) switch (opts->mode) { case MONITOR_MODE_CONTROL: - monitor_init_qmp(chr, opts->pretty); + monitor_init_qmp(chr, opts->pretty, &local_err); break; case MONITOR_MODE_READLINE: if (opts->pretty) { @@ -636,6 +637,10 @@ int monitor_init(MonitorOptions *opts, Error **errp) g_assert_not_reached(); } + if (local_err) { + error_propagate(errp, local_err); + return -1; + } return 0; } diff --git a/monitor/qmp.c b/monitor/qmp.c index 8379c8f96e..f89e7daf27 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -395,10 +395,16 @@ static void monitor_qmp_setup_handlers_bh(void *opaque) monitor_list_append(&mon->common); } -void monitor_init_qmp(Chardev *chr, bool pretty) +void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) { MonitorQMP *mon = g_new0(MonitorQMP, 1); + if (!qemu_chr_fe_init(&mon->common.chr, chr, errp)) { + g_free(mon); + return; + } + qemu_chr_fe_set_echo(&mon->common.chr, true); + /* Note: we run QMP monitor in I/O thread when @chr supports that */ monitor_data_init(&mon->common, true, false, qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT)); @@ -408,9 +414,6 @@ void monitor_init_qmp(Chardev *chr, bool pretty) qemu_mutex_init(&mon->qmp_queue_lock); mon->qmp_requests = g_queue_new(); - qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); - qemu_chr_fe_set_echo(&mon->common.chr, true); - json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL); if (mon->common.use_io_thread) { /* diff --git a/stubs/monitor-core.c b/stubs/monitor-core.c index 403c00a6d0..6cff1c4e1d 100644 --- a/stubs/monitor-core.c +++ b/stubs/monitor-core.c @@ -5,7 +5,7 @@ __thread Monitor *cur_mon; -void monitor_init_qmp(Chardev *chr, bool pretty) +void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) { } diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c index 8ce55efe70..2edb4c539d 100644 --- a/tests/test-util-sockets.c +++ b/tests/test-util-sockets.c @@ -71,7 +71,7 @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) */ __thread Monitor *cur_mon; int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } -void monitor_init_qmp(Chardev *chr, bool pretty) {} +void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) {} void monitor_init_hmp(Chardev *chr, bool use_readline) {} -- cgit 1.4.1 From 8e9119a807df510f0d2ce4cdda3078166d6e99a7 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 24 Feb 2020 15:30:06 +0100 Subject: hmp: Fail gracefully if chardev is already in use Trying to attach a HMP monitor to a chardev that is already in use results in a crash because monitor_init_hmp() passes &error_abort to qemu_chr_fe_init(): $ ./x86_64-softmmu/qemu-system-x86_64 --chardev stdio,id=foo --mon foo --mon foo QEMU 4.2.50 monitor - type 'help' for more information (qemu) Unexpected error in qemu_chr_fe_init() at chardev/char-fe.c:220: qemu-system-x86_64: --mon foo: Device 'foo' is in use Abgebrochen (Speicherabzug geschrieben) Fix this by allowing monitor_init_hmp() to return an error and passing any error in qemu_chr_fe_init() to its caller instead of aborting. Signed-off-by: Kevin Wolf Message-Id: <20200224143008.13362-19-kwolf@redhat.com> Acked-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- chardev/char.c | 8 +++++++- gdbstub.c | 2 +- include/monitor/monitor.h | 2 +- monitor/hmp.c | 8 ++++++-- monitor/monitor.c | 2 +- stubs/monitor.c | 2 +- tests/test-util-sockets.c | 2 +- 7 files changed, 18 insertions(+), 8 deletions(-) (limited to 'monitor/monitor.c') diff --git a/chardev/char.c b/chardev/char.c index 87237568df..e77564060d 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -737,7 +737,13 @@ Chardev *qemu_chr_new_noreplay(const char *label, const char *filename, if (qemu_opt_get_bool(opts, "mux", 0)) { assert(permit_mux_mon); - monitor_init_hmp(chr, true); + monitor_init_hmp(chr, true, &err); + if (err) { + error_report_err(err); + object_unparent(OBJECT(chr)); + chr = NULL; + goto out; + } } out: diff --git a/gdbstub.c b/gdbstub.c index ce304ff482..22a2d630cd 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -3367,7 +3367,7 @@ int gdbserver_start(const char *device) /* Initialize a monitor terminal for gdb */ mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB, NULL, NULL, &error_abort); - monitor_init_hmp(mon_chr, false); + monitor_init_hmp(mon_chr, false, &error_abort); } else { qemu_chr_fe_deinit(&s->chr, true); mon_chr = s->mon_chr; diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index e55a3b57e0..ad823b9edb 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -18,7 +18,7 @@ bool monitor_cur_is_qmp(void); void monitor_init_globals(void); void monitor_init_globals_core(void); void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp); -void monitor_init_hmp(Chardev *chr, bool use_readline); +void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp); int monitor_init(MonitorOptions *opts, Error **errp); int monitor_init_opts(QemuOpts *opts, Error **errp); void monitor_cleanup(void); diff --git a/monitor/hmp.c b/monitor/hmp.c index 944fa9651e..d598dd02bb 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -1399,12 +1399,16 @@ static void monitor_readline_flush(void *opaque) monitor_flush(&mon->common); } -void monitor_init_hmp(Chardev *chr, bool use_readline) +void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp) { MonitorHMP *mon = g_new0(MonitorHMP, 1); + if (!qemu_chr_fe_init(&mon->common.chr, chr, errp)) { + g_free(mon); + return; + } + monitor_data_init(&mon->common, false, false, false); - qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); mon->use_readline = use_readline; if (mon->use_readline) { diff --git a/monitor/monitor.c b/monitor/monitor.c index 00d287655e..2282bf6780 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -631,7 +631,7 @@ int monitor_init(MonitorOptions *opts, Error **errp) warn_report("'pretty' is deprecated for HMP monitors, it has no " "effect and will be removed in future versions"); } - monitor_init_hmp(chr, true); + monitor_init_hmp(chr, true, &local_err); break; default: g_assert_not_reached(); diff --git a/stubs/monitor.c b/stubs/monitor.c index 9403f8e72c..20786ac4ff 100644 --- a/stubs/monitor.c +++ b/stubs/monitor.c @@ -9,7 +9,7 @@ int monitor_get_fd(Monitor *mon, const char *name, Error **errp) return -1; } -void monitor_init_hmp(Chardev *chr, bool use_readline) +void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp) { } diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c index 2edb4c539d..5fd947c7bf 100644 --- a/tests/test-util-sockets.c +++ b/tests/test-util-sockets.c @@ -72,7 +72,7 @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) __thread Monitor *cur_mon; int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) {} -void monitor_init_hmp(Chardev *chr, bool use_readline) {} +void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp) {} static void test_socket_fd_pass_name_good(void) -- cgit 1.4.1 From a2f411c4671b0b6cfe5f3b91b65d9bc8456e75ab Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 24 Feb 2020 15:30:07 +0100 Subject: monitor: Add allow_hmp parameter to monitor_init() Add a new parameter allow_hmp to monitor_init() so that the storage daemon can disable HMP. Signed-off-by: Kevin Wolf Message-Id: <20200224143008.13362-20-kwolf@redhat.com> Acked-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- include/monitor/monitor.h | 2 +- monitor/monitor.c | 12 ++++++++++-- qapi/control.json | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'monitor/monitor.c') diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index ad823b9edb..1018d754a6 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -19,7 +19,7 @@ void monitor_init_globals(void); void monitor_init_globals_core(void); void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp); void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp); -int monitor_init(MonitorOptions *opts, Error **errp); +int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp); int monitor_init_opts(QemuOpts *opts, Error **errp); void monitor_cleanup(void); diff --git a/monitor/monitor.c b/monitor/monitor.c index 2282bf6780..125494410a 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -611,7 +611,7 @@ void monitor_init_globals_core(void) NULL); } -int monitor_init(MonitorOptions *opts, Error **errp) +int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp) { Chardev *chr; Error *local_err = NULL; @@ -622,11 +622,19 @@ int monitor_init(MonitorOptions *opts, Error **errp) return -1; } + if (!opts->has_mode) { + opts->mode = allow_hmp ? MONITOR_MODE_READLINE : MONITOR_MODE_CONTROL; + } + switch (opts->mode) { case MONITOR_MODE_CONTROL: monitor_init_qmp(chr, opts->pretty, &local_err); break; case MONITOR_MODE_READLINE: + if (!allow_hmp) { + error_setg(errp, "Only QMP is supported"); + return -1; + } if (opts->pretty) { warn_report("'pretty' is deprecated for HMP monitors, it has no " "effect and will be removed in future versions"); @@ -658,7 +666,7 @@ int monitor_init_opts(QemuOpts *opts, Error **errp) goto out; } - monitor_init(options, &local_err); + monitor_init(options, true, &local_err); qapi_free_MonitorOptions(options); out: diff --git a/qapi/control.json b/qapi/control.json index 3ee086aec7..85b12fe0fb 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -237,7 +237,8 @@ # # @id: Name of the monitor # -# @mode: Selects the monitor mode (default: readline) +# @mode: Selects the monitor mode (default: readline in the system +# emulator, control in qemu-storage-daemon) # # @pretty: Enables pretty printing (QMP only) # -- cgit 1.4.1