#include "qapi/qmp/qjson.h"
#include "qapi/qmp/json-streamer.h"
#include "qapi/qmp/json-parser.h"
-#include <qom/object_interfaces.h>
+#include "qom/object_interfaces.h"
#include "cpu.h"
#include "trace.h"
#include "trace/control.h"
#include "sysemu/block-backend.h"
#include "sysemu/qtest.h"
#include "qemu/cutils.h"
-
-/* for hmp_info_irq/pic */
-#if defined(TARGET_SPARC)
-#include "hw/sparc/sun4m.h"
-#endif
-#include "hw/lm32/lm32_pic.h"
+#include "qapi/qmp/dispatch.h"
#if defined(TARGET_S390X)
#include "hw/s390x/storage-keys.h"
const char *args_type;
const char *params;
const char *help;
- union {
- void (*cmd)(Monitor *mon, const QDict *qdict);
- void (*cmd_new)(QDict *params, QObject **ret_data, Error **errp);
- } mhandler;
- /* @sub_table is a list of 2nd level of commands. If it do not exist,
- * mhandler should be used. If it exist, sub_table[?].mhandler should be
- * used, and mhandler of 1st level plays the role of help function.
+ void (*cmd)(Monitor *mon, const QDict *qdict);
+ /* @sub_table is a list of 2nd level of commands. If it does not exist,
+ * cmd should be used. If it exists, sub_table[?].cmd should be
+ * used, and cmd of 1st level plays the role of help function.
*/
struct mon_cmd_t *sub_table;
void (*command_completion)(ReadLineState *rs, int nb_args, const char *str);
};
typedef struct {
- QObject *id;
JSONMessageParser parser;
/*
* When a client connects, we're in capabilities negotiation mode.
} MonitorQAPIEventConf;
struct Monitor {
- CharDriverState *chr;
+ CharBackend chr;
int reset_seen;
int flags;
int suspend_cnt;
static mon_cmd_t mon_cmds[];
static mon_cmd_t info_cmds[];
-static const mon_cmd_t qmp_cmds[];
-
Monitor *cur_mon;
static QEMUClockType event_clock_type = QEMU_CLOCK_REALTIME;
len = qstring_get_length(mon->outbuf);
if (len && !mon->mux_out) {
- rc = qemu_chr_fe_write(mon->chr, (const uint8_t *) buf, len);
+ rc = qemu_chr_fe_write(&mon->chr, (const uint8_t *) buf, len);
if ((rc < 0 && errno != EAGAIN) || (rc == len)) {
/* all flushed or error */
QDECREF(mon->outbuf);
mon->outbuf = tmp;
}
if (mon->out_watch == 0) {
- mon->out_watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT|G_IO_HUP,
- monitor_unblocked, mon);
+ mon->out_watch =
+ qemu_chr_fe_add_watch(&mon->chr, G_IO_OUT | G_IO_HUP,
+ monitor_unblocked, mon);
}
}
}
QDECREF(json);
}
-static QDict *build_qmp_error_dict(Error *err)
-{
- QObject *obj;
-
- obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %s } }",
- QapiErrorClass_lookup[error_get_class(err)],
- error_get_pretty(err));
-
- return qobject_to_qdict(obj);
-}
-
-static void monitor_protocol_emitter(Monitor *mon, QObject *data,
- Error *err)
-{
- QDict *qmp;
-
- trace_monitor_protocol_emitter(mon);
-
- if (!err) {
- /* success response */
- qmp = qdict_new();
- if (data) {
- qobject_incref(data);
- qdict_put_obj(qmp, "return", data);
- } else {
- /* return an empty QDict by default */
- qdict_put(qmp, "return", qdict_new());
- }
- } else {
- /* error response */
- qmp = build_qmp_error_dict(err);
- }
-
- if (mon->qmp.id) {
- qdict_put_obj(qmp, "id", mon->qmp.id);
- mon->qmp.id = NULL;
- }
-
- monitor_json_emitter(mon, QOBJECT(qmp));
- QDECREF(qmp);
-}
-
-
static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
/* Limit guest-triggerable events to 1 per second */
[QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS },
qmp_event_set_func_emit(monitor_qapi_event_queue);
}
-static void qmp_capabilities(QDict *params, QObject **ret_data, Error **errp)
+void qmp_qmp_capabilities(Error **errp)
{
cur_mon->qmp.in_command_mode = true;
}
static void monitor_data_destroy(Monitor *mon)
{
+ qemu_chr_fe_deinit(&mon->chr);
+ if (monitor_is_qmp(mon)) {
+ json_message_parser_destroy(&mon->qmp.parser);
+ }
+ g_free(mon->rs);
QDECREF(mon->outbuf);
qemu_mutex_destroy(&mon->out_lock);
}
{
const char *tp_name = qdict_get_str(qdict, "name");
bool new_state = qdict_get_bool(qdict, "option");
+ bool has_vcpu = qdict_haskey(qdict, "vcpu");
+ int vcpu = qdict_get_try_int(qdict, "vcpu", 0);
Error *local_err = NULL;
- qmp_trace_event_set_state(tp_name, new_state, true, true, &local_err);
+ if (vcpu < 0) {
+ monitor_printf(mon, "argument vcpu must be positive");
+ return;
+ }
+
+ qmp_trace_event_set_state(tp_name, new_state, true, true, has_vcpu, vcpu, &local_err);
if (local_err) {
error_report_err(local_err);
}
help_cmd(mon, "info");
}
-CommandInfoList *qmp_query_commands(Error **errp)
+static void query_commands_cb(QmpCommand *cmd, void *opaque)
{
- CommandInfoList *info, *cmd_list = NULL;
- const mon_cmd_t *cmd;
+ CommandInfoList *info, **list = opaque;
- for (cmd = qmp_cmds; cmd->name != NULL; cmd++) {
- info = g_malloc0(sizeof(*info));
- info->value = g_malloc0(sizeof(*info->value));
- info->value->name = g_strdup(cmd->name);
-
- info->next = cmd_list;
- cmd_list = info;
+ if (!cmd->enabled) {
+ return;
}
- return cmd_list;
+ info = g_malloc0(sizeof(*info));
+ info->value = g_malloc0(sizeof(*info->value));
+ info->value->name = g_strdup(cmd->name);
+ info->next = *list;
+ *list = info;
+}
+
+CommandInfoList *qmp_query_commands(Error **errp)
+{
+ CommandInfoList *list = NULL;
+
+ qmp_for_each_command(query_commands_cb, &list);
+
+ return list;
}
EventInfoList *qmp_query_events(Error **errp)
* directly into QObject instead of first parsing it with
* visit_type_SchemaInfoList() into a SchemaInfoList, then marshal it
* to QObject with generated output marshallers, every time. Instead,
- * we do it in test-qmp-input-visitor.c, just to make sure
+ * we do it in test-qobject-input-visitor.c, just to make sure
* qapi-introspect.py's output actually conforms to the schema.
*/
static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
*ret_data = qobject_from_json(qmp_schema_json);
}
+/*
+ * We used to define commands in qmp-commands.hx in addition to the
+ * QAPI schema. This permitted defining some of them only in certain
+ * configurations. query-commands has always reflected that (good,
+ * because it lets QMP clients figure out what's actually available),
+ * while query-qmp-schema never did (not so good). This function is a
+ * hack to keep the configuration-specific commands defined exactly as
+ * before, even though qmp-commands.hx is gone.
+ *
+ * FIXME Educate the QAPI schema on configuration-specific commands,
+ * and drop this hack.
+ */
+static void qmp_unregister_commands_hack(void)
+{
+#ifndef CONFIG_SPICE
+ qmp_unregister_command("query-spice");
+#endif
+#ifndef TARGET_I386
+ qmp_unregister_command("rtc-reset-reinjection");
+#endif
+#ifndef TARGET_S390X
+ qmp_unregister_command("dump-skeys");
+#endif
+#ifndef TARGET_ARM
+ qmp_unregister_command("query-gic-capabilities");
+#endif
+#if !defined(TARGET_S390X)
+ qmp_unregister_command("query-cpu-model-expansion");
+ qmp_unregister_command("query-cpu-model-baseline");
+ qmp_unregister_command("query-cpu-model-comparison");
+#endif
+#if !defined(TARGET_PPC) && !defined(TARGET_ARM) && !defined(TARGET_I386) \
+ && !defined(TARGET_S390X)
+ qmp_unregister_command("query-cpu-definitions");
+#endif
+}
+
+static void qmp_init_marshal(void)
+{
+ qmp_register_command("query-qmp-schema", qmp_query_qmp_schema,
+ QCO_NO_OPTIONS);
+ qmp_register_command("device_add", qmp_device_add,
+ QCO_NO_OPTIONS);
+ qmp_register_command("netdev_add", qmp_netdev_add,
+ QCO_NO_OPTIONS);
+
+ /* call it after the rest of qapi_init() */
+ register_module_init(qmp_unregister_commands_hack, MODULE_INIT_QAPI);
+}
+
+qapi_init(qmp_init_marshal);
+
/* set the current CPU defined by the user */
int monitor_set_cpu(int cpu_index)
{
CPUState *mon_get_cpu(void)
{
if (!cur_mon->mon_cpu) {
- monitor_set_cpu(0);
+ monitor_set_cpu(first_cpu->cpu_index);
}
cpu_synchronize_state(cur_mon->mon_cpu);
return cur_mon->mon_cpu;
static void hmp_info_trace_events(Monitor *mon, const QDict *qdict)
{
- TraceEventInfoList *events = qmp_trace_event_get_state("*", NULL);
+ const char *name = qdict_get_try_str(qdict, "name");
+ bool has_vcpu = qdict_haskey(qdict, "vcpu");
+ int vcpu = qdict_get_try_int(qdict, "vcpu", 0);
+ TraceEventInfoList *events;
TraceEventInfoList *elem;
+ Error *local_err = NULL;
+
+ if (name == NULL) {
+ name = "*";
+ }
+ if (vcpu < 0) {
+ monitor_printf(mon, "argument vcpu must be positive");
+ return;
+ }
+
+ events = qmp_trace_event_get_state(name, has_vcpu, vcpu, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return;
+ }
for (elem = events; elem != NULL; elem = elem->next) {
monitor_printf(mon, "%s : state %u\n",
mon_fd_t *monfd;
int fd;
- fd = qemu_chr_fe_get_msgfd(cur_mon->chr);
+ fd = qemu_chr_fe_get_msgfd(&cur_mon->chr);
if (fd == -1) {
error_setg(errp, QERR_FD_NOT_SUPPLIED);
return;
Monitor *mon = cur_mon;
AddfdInfo *fdinfo;
- fd = qemu_chr_fe_get_msgfd(mon->chr);
+ fd = qemu_chr_fe_get_msgfd(&mon->chr);
if (fd == -1) {
error_setg(errp, QERR_FD_NOT_SUPPLIED);
goto error;
{ NULL, NULL, },
};
-static const mon_cmd_t qmp_cmds[] = {
-#include "qmp-commands-old.h"
- { /* NULL */ },
-};
-
/*******************************************************************/
static const char *pch;
return NULL;
}
-static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
-{
- return search_dispatch_table(qmp_cmds, cmdname);
-}
-
/*
* Parse command name from @cmdp according to command table @table.
* If blank, return NULL.
return;
}
- cmd->mhandler.cmd(mon, qdict);
+ cmd->cmd(mon, qdict);
QDECREF(qdict);
}
}
len = strlen(str);
readline_set_completion_index(rs, len);
- for (i = 0; NetClientOptionsKind_lookup[i]; i++) {
- add_completion_option(rs, str, NetClientOptionsKind_lookup[i]);
+ for (i = 0; NetClientDriver_lookup[i]; i++) {
+ add_completion_option(rs, str, NetClientDriver_lookup[i]);
}
}
NetClientState *ncs[MAX_QUEUE_NUM];
int count, i;
count = qemu_find_net_clients_except(NULL, ncs,
- NET_CLIENT_OPTIONS_KIND_NONE,
+ NET_CLIENT_DRIVER_NONE,
MAX_QUEUE_NUM);
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
const char *name = ncs[i]->name;
len = strlen(str);
readline_set_completion_index(rs, len);
- count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_OPTIONS_KIND_NIC,
+ count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC,
MAX_QUEUE_NUM);
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
QemuOpts *opts;
}
}
+void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ size_t len;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ if (nb_args == 2) {
+ TraceEventIter iter;
+ TraceEvent *ev;
+ char *pattern = g_strdup_printf("%s*", str);
+ trace_event_iter_init(&iter, pattern);
+ while ((ev = trace_event_iter_next(&iter)) != NULL) {
+ readline_add_completion(rs, trace_event_get_name(ev));
+ }
+ g_free(pattern);
+ }
+}
+
void trace_event_completion(ReadLineState *rs, int nb_args, const char *str)
{
size_t len;
len = strlen(str);
readline_set_completion_index(rs, len);
if (nb_args == 2) {
- TraceEventID id;
- for (id = 0; id < trace_event_count(); id++) {
- const char *event_name = trace_event_get_name(trace_event_id(id));
- if (!strncmp(str, event_name, len)) {
- readline_add_completion(rs, event_name);
- }
+ TraceEventIter iter;
+ TraceEvent *ev;
+ char *pattern = g_strdup_printf("%s*", str);
+ trace_event_iter_init(&iter, pattern);
+ while ((ev = trace_event_iter_next(&iter)) != NULL) {
+ readline_add_completion(rs, trace_event_get_name(ev));
}
+ g_free(pattern);
} else if (nb_args == 3) {
add_completion_option(rs, str, "on");
add_completion_option(rs, str, "off");
readline_set_completion_index(rs, len);
if (nb_args == 2) {
count = qemu_find_net_clients_except(NULL, ncs,
- NET_CLIENT_OPTIONS_KIND_NONE,
+ NET_CLIENT_DRIVER_NONE,
MAX_QUEUE_NUM);
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
int id;
return;
} else if (nb_args == 3) {
count = qemu_find_net_clients_except(NULL, ncs,
- NET_CLIENT_OPTIONS_KIND_NIC,
+ NET_CLIENT_DRIVER_NIC,
MAX_QUEUE_NUM);
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
int id;
const char *name;
- if (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT ||
+ if (ncs[i]->info->type == NET_CLIENT_DRIVER_HUBPORT ||
net_hub_id_for_client(ncs[i], &id)) {
continue;
}
return (mon->suspend_cnt == 0) ? 1 : 0;
}
-static bool invalid_qmp_mode(const Monitor *mon, const mon_cmd_t *cmd,
+static bool invalid_qmp_mode(const Monitor *mon, const char *cmd,
Error **errp)
{
- bool is_cap = cmd->mhandler.cmd_new == qmp_capabilities;
+ bool is_cap = g_str_equal(cmd, "qmp_capabilities");
if (is_cap && mon->qmp.in_command_mode) {
error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
"Capabilities negotiation is already complete, command "
- "'%s' ignored", cmd->name);
+ "'%s' ignored", cmd);
return true;
}
if (!is_cap && !mon->qmp.in_command_mode) {
error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
"Expecting capabilities negotiation with "
- "'qmp_capabilities' before command '%s'", cmd->name);
+ "'qmp_capabilities' before command '%s'", cmd);
return true;
}
return false;
}
-/*
- * Argument validation rules:
- *
- * 1. The argument must exist in cmd_args qdict
- * 2. The argument type must be the expected one
- *
- * Special case: If the argument doesn't exist in cmd_args and
- * the QMP_ACCEPT_UNKNOWNS flag is set, then the
- * checking is skipped for it.
- */
-static void check_client_args_type(const QDict *client_args,
- const QDict *cmd_args, int flags,
- Error **errp)
-{
- const QDictEntry *ent;
-
- for (ent = qdict_first(client_args); ent;ent = qdict_next(client_args,ent)){
- QObject *obj;
- QString *arg_type;
- const QObject *client_arg = qdict_entry_value(ent);
- const char *client_arg_name = qdict_entry_key(ent);
-
- obj = qdict_get(cmd_args, client_arg_name);
- if (!obj) {
- if (flags & QMP_ACCEPT_UNKNOWNS) {
- /* handler accepts unknowns */
- continue;
- }
- /* client arg doesn't exist */
- error_setg(errp, QERR_INVALID_PARAMETER, client_arg_name);
- return;
- }
-
- arg_type = qobject_to_qstring(obj);
- assert(arg_type != NULL);
-
- /* check if argument's type is correct */
- switch (qstring_get_str(arg_type)[0]) {
- case 'F':
- case 'B':
- case 's':
- if (qobject_type(client_arg) != QTYPE_QSTRING) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- client_arg_name, "string");
- return;
- }
- break;
- case 'i':
- case 'l':
- case 'M':
- case 'o':
- if (qobject_type(client_arg) != QTYPE_QINT) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- client_arg_name, "int");
- return;
- }
- break;
- case 'T':
- if (qobject_type(client_arg) != QTYPE_QINT &&
- qobject_type(client_arg) != QTYPE_QFLOAT) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- client_arg_name, "number");
- return;
- }
- break;
- case 'b':
- case '-':
- if (qobject_type(client_arg) != QTYPE_QBOOL) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- client_arg_name, "bool");
- return;
- }
- break;
- case 'O':
- assert(flags & QMP_ACCEPT_UNKNOWNS);
- break;
- case 'q':
- /* Any QObject can be passed. */
- break;
- case '/':
- case '.':
- /*
- * These types are not supported by QMP and thus are not
- * handled here. Fall through.
- */
- default:
- abort();
- }
- }
-}
-
-/*
- * - Check if the client has passed all mandatory args
- * - Set special flags for argument validation
- */
-static void check_mandatory_args(const QDict *cmd_args,
- const QDict *client_args, int *flags,
- Error **errp)
-{
- const QDictEntry *ent;
-
- for (ent = qdict_first(cmd_args); ent; ent = qdict_next(cmd_args, ent)) {
- const char *cmd_arg_name = qdict_entry_key(ent);
- QString *type = qobject_to_qstring(qdict_entry_value(ent));
- assert(type != NULL);
-
- if (qstring_get_str(type)[0] == 'O') {
- assert((*flags & QMP_ACCEPT_UNKNOWNS) == 0);
- *flags |= QMP_ACCEPT_UNKNOWNS;
- } else if (qstring_get_str(type)[0] != '-' &&
- qstring_get_str(type)[1] != '?' &&
- !qdict_haskey(client_args, cmd_arg_name)) {
- error_setg(errp, QERR_MISSING_PARAMETER, cmd_arg_name);
- return;
- }
- }
-}
-
-static QDict *qdict_from_args_type(const char *args_type)
-{
- int i;
- QDict *qdict;
- QString *key, *type, *cur_qs;
-
- assert(args_type != NULL);
-
- qdict = qdict_new();
-
- if (args_type == NULL || args_type[0] == '\0') {
- /* no args, empty qdict */
- goto out;
- }
-
- key = qstring_new();
- type = qstring_new();
-
- cur_qs = key;
-
- for (i = 0;; i++) {
- switch (args_type[i]) {
- case ',':
- case '\0':
- qdict_put(qdict, qstring_get_str(key), type);
- QDECREF(key);
- if (args_type[i] == '\0') {
- goto out;
- }
- type = qstring_new(); /* qdict has ref */
- cur_qs = key = qstring_new();
- break;
- case ':':
- cur_qs = type;
- break;
- default:
- qstring_append_chr(cur_qs, args_type[i]);
- break;
- }
- }
-
-out:
- return qdict;
-}
-
-/*
- * Client argument checking rules:
- *
- * 1. Client must provide all mandatory arguments
- * 2. Each argument provided by the client must be expected
- * 3. Each argument provided by the client must have the type expected
- * by the command
- */
-static void qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args,
- Error **errp)
-{
- Error *err = NULL;
- int flags;
- QDict *cmd_args;
-
- cmd_args = qdict_from_args_type(cmd->args_type);
-
- flags = 0;
- check_mandatory_args(cmd_args, client_args, &flags, &err);
- if (err) {
- goto out;
- }
-
- check_client_args_type(client_args, cmd_args, flags, &err);
-
-out:
- error_propagate(errp, err);
- QDECREF(cmd_args);
-}
-
/*
* Input object checking rules
*
static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
{
- Error *local_err = NULL;
- QObject *obj, *data;
- QDict *input, *args;
- const mon_cmd_t *cmd;
+ QObject *req, *rsp = NULL, *id = NULL;
+ QDict *qdict = NULL;
const char *cmd_name;
Monitor *mon = cur_mon;
+ Error *err = NULL;
- args = input = NULL;
- data = NULL;
-
- obj = json_parser_parse(tokens, NULL);
- if (!obj) {
- // FIXME: should be triggered in json_parser_parse()
- error_setg(&local_err, QERR_JSON_PARSING);
+ req = json_parser_parse_err(tokens, NULL, &err);
+ if (err || !req || qobject_type(req) != QTYPE_QDICT) {
+ if (!err) {
+ error_setg(&err, QERR_JSON_PARSING);
+ }
goto err_out;
}
- input = qmp_check_input_obj(obj, &local_err);
- if (!input) {
- qobject_decref(obj);
+ qdict = qmp_check_input_obj(req, &err);
+ if (!qdict) {
goto err_out;
}
- mon->qmp.id = qdict_get(input, "id");
- qobject_incref(mon->qmp.id);
+ id = qdict_get(qdict, "id");
+ qobject_incref(id);
+ qdict_del(qdict, "id");
- cmd_name = qdict_get_str(input, "execute");
+ cmd_name = qdict_get_str(qdict, "execute");
trace_handle_qmp_command(mon, cmd_name);
- cmd = qmp_find_cmd(cmd_name);
- if (!cmd) {
- error_set(&local_err, ERROR_CLASS_COMMAND_NOT_FOUND,
- "The command %s has not been found", cmd_name);
- goto err_out;
- }
- if (invalid_qmp_mode(mon, cmd, &local_err)) {
+
+ if (invalid_qmp_mode(mon, cmd_name, &err)) {
goto err_out;
}
- obj = qdict_get(input, "arguments");
- if (!obj) {
- args = qdict_new();
- } else {
- args = qobject_to_qdict(obj);
- QINCREF(args);
- }
+ rsp = qmp_dispatch(req);
- qmp_check_client_args(cmd, args, &local_err);
- if (local_err) {
- goto err_out;
+err_out:
+ if (err) {
+ qdict = qdict_new();
+ qdict_put_obj(qdict, "error", qmp_build_error_object(err));
+ error_free(err);
+ rsp = QOBJECT(qdict);
}
- cmd->mhandler.cmd_new(args, &data, &local_err);
+ if (rsp) {
+ if (id) {
+ qdict_put_obj(qobject_to_qdict(rsp), "id", id);
+ id = NULL;
+ }
-err_out:
- monitor_protocol_emitter(mon, data, local_err);
- qobject_decref(data);
- error_free(local_err);
- QDECREF(input);
- QDECREF(args);
+ monitor_json_emitter(mon, rsp);
+ }
+
+ qobject_decref(id);
+ qobject_decref(rsp);
+ qobject_decref(req);
}
static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
QObject *ver = NULL;
qmp_marshal_query_version(NULL, &ver, NULL);
- return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver);
+
+ return qobject_from_jsonf("{'QMP': {'version': %p, 'capabilities': []}}",
+ ver);
}
static void monitor_qmp_event(void *opaque, int event)
qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd);
}
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 8
- * End:
- */
-
/* These functions just adapt the readline interface in a typesafe way. We
* could cast function pointers but that discards compiler checks.
*/
mon = g_malloc(sizeof(*mon));
monitor_data_init(mon);
- mon->chr = chr;
+ qemu_chr_fe_init(&mon->chr, chr, &error_abort);
mon->flags = flags;
if (flags & MONITOR_USE_READLINE) {
mon->rs = readline_init(monitor_readline_printf,
}
if (monitor_is_qmp(mon)) {
- qemu_chr_add_handlers(chr, monitor_can_read, monitor_qmp_read,
- monitor_qmp_event, mon);
- qemu_chr_fe_set_echo(chr, true);
+ qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
+ monitor_qmp_event, mon, NULL, true);
+ qemu_chr_fe_set_echo(&mon->chr, true);
json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
} else {
- qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
- monitor_event, mon);
+ qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
+ monitor_event, mon, NULL, true);
}
qemu_mutex_lock(&monitor_lock);
qemu_mutex_unlock(&monitor_lock);
}
+void monitor_cleanup(void)
+{
+ Monitor *mon, *next;
+
+ qemu_mutex_lock(&monitor_lock);
+ QLIST_FOREACH_SAFE(mon, &mon_list, entry, next) {
+ QLIST_REMOVE(mon, entry);
+ monitor_data_destroy(mon);
+ g_free(mon);
+ }
+ qemu_mutex_unlock(&monitor_lock);
+}
+
static void bdrv_password_cb(void *opaque, const char *password,
void *readline_opaque)
{