mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 08:43:55 -06:00
Merge remote branch 'qmp/for-anthony' into staging
This commit is contained in:
commit
48f57044e6
12 changed files with 1527 additions and 1192 deletions
366
monitor.c
366
monitor.c
|
@ -189,6 +189,9 @@ static QLIST_HEAD(mon_list, Monitor) mon_list;
|
|||
static const mon_cmd_t mon_cmds[];
|
||||
static const mon_cmd_t info_cmds[];
|
||||
|
||||
static const mon_cmd_t qmp_cmds[];
|
||||
static const mon_cmd_t qmp_query_cmds[];
|
||||
|
||||
Monitor *cur_mon;
|
||||
Monitor *default_mon;
|
||||
|
||||
|
@ -328,21 +331,16 @@ static int GCC_FMT_ATTR(2, 3) monitor_fprintf(FILE *stream,
|
|||
|
||||
static void monitor_user_noop(Monitor *mon, const QObject *data) { }
|
||||
|
||||
static inline int monitor_handler_ported(const mon_cmd_t *cmd)
|
||||
static inline int handler_is_qobject(const mon_cmd_t *cmd)
|
||||
{
|
||||
return cmd->user_print != NULL;
|
||||
}
|
||||
|
||||
static inline bool monitor_handler_is_async(const mon_cmd_t *cmd)
|
||||
static inline bool handler_is_async(const mon_cmd_t *cmd)
|
||||
{
|
||||
return cmd->flags & MONITOR_CMD_ASYNC;
|
||||
}
|
||||
|
||||
static inline bool monitor_cmd_user_only(const mon_cmd_t *cmd)
|
||||
{
|
||||
return (cmd->flags & MONITOR_CMD_USER_ONLY);
|
||||
}
|
||||
|
||||
static inline int monitor_has_error(const Monitor *mon)
|
||||
{
|
||||
return mon->error != NULL;
|
||||
|
@ -352,7 +350,10 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
|
|||
{
|
||||
QString *json;
|
||||
|
||||
json = qobject_to_json(data);
|
||||
if (mon->flags & MONITOR_USE_PRETTY)
|
||||
json = qobject_to_json_pretty(data);
|
||||
else
|
||||
json = qobject_to_json(data);
|
||||
assert(json != NULL);
|
||||
|
||||
qstring_append_chr(json, '\n');
|
||||
|
@ -634,13 +635,12 @@ static void user_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
static void do_info(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const mon_cmd_t *cmd;
|
||||
const char *item = qdict_get_try_str(qdict, "item");
|
||||
|
||||
if (!item) {
|
||||
assert(monitor_ctrl_mode(mon) == 0);
|
||||
goto help;
|
||||
}
|
||||
|
||||
|
@ -650,56 +650,27 @@ static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||
}
|
||||
|
||||
if (cmd->name == NULL) {
|
||||
if (monitor_ctrl_mode(mon)) {
|
||||
qerror_report(QERR_COMMAND_NOT_FOUND, item);
|
||||
return -1;
|
||||
}
|
||||
goto help;
|
||||
}
|
||||
|
||||
if (monitor_ctrl_mode(mon) && monitor_cmd_user_only(cmd)) {
|
||||
qerror_report(QERR_COMMAND_NOT_FOUND, item);
|
||||
return -1;
|
||||
}
|
||||
if (handler_is_async(cmd)) {
|
||||
user_async_info_handler(mon, cmd);
|
||||
} else if (handler_is_qobject(cmd)) {
|
||||
QObject *info_data = NULL;
|
||||
|
||||
if (monitor_handler_is_async(cmd)) {
|
||||
if (monitor_ctrl_mode(mon)) {
|
||||
qmp_async_info_handler(mon, cmd);
|
||||
} else {
|
||||
user_async_info_handler(mon, cmd);
|
||||
}
|
||||
/*
|
||||
* Indicate that this command is asynchronous and will not return any
|
||||
* data (not even empty). Instead, the data will be returned via a
|
||||
* completion callback.
|
||||
*/
|
||||
*ret_data = qobject_from_jsonf("{ '__mon_async': 'return' }");
|
||||
} else if (monitor_handler_ported(cmd)) {
|
||||
cmd->mhandler.info_new(mon, ret_data);
|
||||
|
||||
if (!monitor_ctrl_mode(mon)) {
|
||||
/*
|
||||
* User Protocol function is called here, Monitor Protocol is
|
||||
* handled by monitor_call_handler()
|
||||
*/
|
||||
if (*ret_data)
|
||||
cmd->user_print(mon, *ret_data);
|
||||
cmd->mhandler.info_new(mon, &info_data);
|
||||
if (info_data) {
|
||||
cmd->user_print(mon, info_data);
|
||||
qobject_decref(info_data);
|
||||
}
|
||||
} else {
|
||||
if (monitor_ctrl_mode(mon)) {
|
||||
/* handler not converted yet */
|
||||
qerror_report(QERR_COMMAND_NOT_FOUND, item);
|
||||
return -1;
|
||||
} else {
|
||||
cmd->mhandler.info(mon);
|
||||
}
|
||||
cmd->mhandler.info(mon);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return;
|
||||
|
||||
help:
|
||||
help_cmd(mon, "info");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_info_version_print(Monitor *mon, const QObject *data)
|
||||
|
@ -773,19 +744,14 @@ static void do_info_commands(Monitor *mon, QObject **ret_data)
|
|||
|
||||
cmd_list = qlist_new();
|
||||
|
||||
for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
|
||||
if (monitor_handler_ported(cmd) && !monitor_cmd_user_only(cmd) &&
|
||||
!compare_cmd(cmd->name, "info")) {
|
||||
qlist_append_obj(cmd_list, get_cmd_dict(cmd->name));
|
||||
}
|
||||
for (cmd = qmp_cmds; cmd->name != NULL; cmd++) {
|
||||
qlist_append_obj(cmd_list, get_cmd_dict(cmd->name));
|
||||
}
|
||||
|
||||
for (cmd = info_cmds; cmd->name != NULL; cmd++) {
|
||||
if (monitor_handler_ported(cmd) && !monitor_cmd_user_only(cmd)) {
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "query-%s", cmd->name);
|
||||
qlist_append_obj(cmd_list, get_cmd_dict(buf));
|
||||
}
|
||||
for (cmd = qmp_query_cmds; cmd->name != NULL; cmd++) {
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "query-%s", cmd->name);
|
||||
qlist_append_obj(cmd_list, get_cmd_dict(buf));
|
||||
}
|
||||
|
||||
*ret_data = QOBJECT(cmd_list);
|
||||
|
@ -2367,11 +2333,11 @@ int monitor_get_fd(Monitor *mon, const char *fdname)
|
|||
}
|
||||
|
||||
static const mon_cmd_t mon_cmds[] = {
|
||||
#include "qemu-monitor.h"
|
||||
#include "hmp-commands.h"
|
||||
{ NULL, NULL, },
|
||||
};
|
||||
|
||||
/* Please update qemu-monitor.hx when adding or changing commands */
|
||||
/* Please update hmp-commands.hx when adding or changing commands */
|
||||
static const mon_cmd_t info_cmds[] = {
|
||||
{
|
||||
.name = "version",
|
||||
|
@ -2381,14 +2347,6 @@ static const mon_cmd_t info_cmds[] = {
|
|||
.user_print = do_info_version_print,
|
||||
.mhandler.info_new = do_info_version,
|
||||
},
|
||||
{
|
||||
.name = "commands",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "list QMP available commands",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.info_new = do_info_commands,
|
||||
},
|
||||
{
|
||||
.name = "network",
|
||||
.args_type = "",
|
||||
|
@ -2663,6 +2621,136 @@ static const mon_cmd_t info_cmds[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const mon_cmd_t qmp_cmds[] = {
|
||||
#include "qmp-commands.h"
|
||||
{ /* NULL */ },
|
||||
};
|
||||
|
||||
static const mon_cmd_t qmp_query_cmds[] = {
|
||||
{
|
||||
.name = "version",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the version of QEMU",
|
||||
.user_print = do_info_version_print,
|
||||
.mhandler.info_new = do_info_version,
|
||||
},
|
||||
{
|
||||
.name = "commands",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "list QMP available commands",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.info_new = do_info_commands,
|
||||
},
|
||||
{
|
||||
.name = "chardev",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the character devices",
|
||||
.user_print = qemu_chr_info_print,
|
||||
.mhandler.info_new = qemu_chr_info,
|
||||
},
|
||||
{
|
||||
.name = "block",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the block devices",
|
||||
.user_print = bdrv_info_print,
|
||||
.mhandler.info_new = bdrv_info,
|
||||
},
|
||||
{
|
||||
.name = "blockstats",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show block device statistics",
|
||||
.user_print = bdrv_stats_print,
|
||||
.mhandler.info_new = bdrv_info_stats,
|
||||
},
|
||||
{
|
||||
.name = "cpus",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show infos for each CPU",
|
||||
.user_print = monitor_print_cpus,
|
||||
.mhandler.info_new = do_info_cpus,
|
||||
},
|
||||
{
|
||||
.name = "pci",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show PCI info",
|
||||
.user_print = do_pci_info_print,
|
||||
.mhandler.info_new = do_pci_info,
|
||||
},
|
||||
{
|
||||
.name = "kvm",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show KVM information",
|
||||
.user_print = do_info_kvm_print,
|
||||
.mhandler.info_new = do_info_kvm,
|
||||
},
|
||||
{
|
||||
.name = "status",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the current VM status (running|paused)",
|
||||
.user_print = do_info_status_print,
|
||||
.mhandler.info_new = do_info_status,
|
||||
},
|
||||
{
|
||||
.name = "mice",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show which guest mouse is receiving events",
|
||||
.user_print = do_info_mice_print,
|
||||
.mhandler.info_new = do_info_mice,
|
||||
},
|
||||
{
|
||||
.name = "vnc",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the vnc server status",
|
||||
.user_print = do_info_vnc_print,
|
||||
.mhandler.info_new = do_info_vnc,
|
||||
},
|
||||
{
|
||||
.name = "name",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the current VM name",
|
||||
.user_print = do_info_name_print,
|
||||
.mhandler.info_new = do_info_name,
|
||||
},
|
||||
{
|
||||
.name = "uuid",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the current VM UUID",
|
||||
.user_print = do_info_uuid_print,
|
||||
.mhandler.info_new = do_info_uuid,
|
||||
},
|
||||
{
|
||||
.name = "migrate",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show migration status",
|
||||
.user_print = do_info_migrate_print,
|
||||
.mhandler.info_new = do_info_migrate,
|
||||
},
|
||||
{
|
||||
.name = "balloon",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show balloon information",
|
||||
.user_print = monitor_print_balloon,
|
||||
.mhandler.info_async = do_info_balloon,
|
||||
.flags = MONITOR_CMD_ASYNC,
|
||||
},
|
||||
{ /* NULL */ },
|
||||
};
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
static const char *pch;
|
||||
|
@ -3369,11 +3457,12 @@ static int is_valid_option(const char *c, const char *typestr)
|
|||
return (typestr != NULL);
|
||||
}
|
||||
|
||||
static const mon_cmd_t *monitor_find_command(const char *cmdname)
|
||||
static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
|
||||
const char *cmdname)
|
||||
{
|
||||
const mon_cmd_t *cmd;
|
||||
|
||||
for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
|
||||
for (cmd = disp_table; cmd->name != NULL; cmd++) {
|
||||
if (compare_cmd(cmdname, cmd->name)) {
|
||||
return cmd;
|
||||
}
|
||||
|
@ -3382,6 +3471,21 @@ static const mon_cmd_t *monitor_find_command(const char *cmdname)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static const mon_cmd_t *monitor_find_command(const char *cmdname)
|
||||
{
|
||||
return search_dispatch_table(mon_cmds, cmdname);
|
||||
}
|
||||
|
||||
static const mon_cmd_t *qmp_find_query_cmd(const char *info_item)
|
||||
{
|
||||
return search_dispatch_table(qmp_query_cmds, info_item);
|
||||
}
|
||||
|
||||
static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
|
||||
{
|
||||
return search_dispatch_table(qmp_cmds, cmdname);
|
||||
}
|
||||
|
||||
static const mon_cmd_t *monitor_parse_command(Monitor *mon,
|
||||
const char *cmdline,
|
||||
QDict *qdict)
|
||||
|
@ -3730,15 +3834,6 @@ void monitor_set_error(Monitor *mon, QError *qerror)
|
|||
}
|
||||
}
|
||||
|
||||
static int is_async_return(const QObject *data)
|
||||
{
|
||||
if (data && qobject_type(data) == QTYPE_QDICT) {
|
||||
return qdict_haskey(qobject_to_qdict(data), "__mon_async");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
|
||||
{
|
||||
if (monitor_ctrl_mode(mon)) {
|
||||
|
@ -3786,37 +3881,6 @@ static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
|
|||
}
|
||||
}
|
||||
|
||||
static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd,
|
||||
const QDict *params)
|
||||
{
|
||||
int ret;
|
||||
QObject *data = NULL;
|
||||
|
||||
mon_print_count_init(mon);
|
||||
|
||||
ret = cmd->mhandler.cmd_new(mon, params, &data);
|
||||
handler_audit(mon, cmd, ret);
|
||||
|
||||
if (is_async_return(data)) {
|
||||
/*
|
||||
* Asynchronous commands have no initial return data but they can
|
||||
* generate errors. Data is returned via the async completion handler.
|
||||
*/
|
||||
if (monitor_ctrl_mode(mon) && monitor_has_error(mon)) {
|
||||
monitor_protocol_emitter(mon, NULL);
|
||||
}
|
||||
} else if (monitor_ctrl_mode(mon)) {
|
||||
/* Monitor Protocol */
|
||||
monitor_protocol_emitter(mon, data);
|
||||
} else {
|
||||
/* User Protocol */
|
||||
if (data)
|
||||
cmd->user_print(mon, data);
|
||||
}
|
||||
|
||||
qobject_decref(data);
|
||||
}
|
||||
|
||||
static void handle_user_command(Monitor *mon, const char *cmdline)
|
||||
{
|
||||
QDict *qdict;
|
||||
|
@ -3828,10 +3892,18 @@ static void handle_user_command(Monitor *mon, const char *cmdline)
|
|||
if (!cmd)
|
||||
goto out;
|
||||
|
||||
if (monitor_handler_is_async(cmd)) {
|
||||
if (handler_is_async(cmd)) {
|
||||
user_async_cmd_handler(mon, cmd, qdict);
|
||||
} else if (monitor_handler_ported(cmd)) {
|
||||
monitor_call_handler(mon, cmd, qdict);
|
||||
} else if (handler_is_qobject(cmd)) {
|
||||
QObject *data = NULL;
|
||||
|
||||
/* XXX: ignores the error code */
|
||||
cmd->mhandler.cmd_new(mon, qdict, &data);
|
||||
assert(!monitor_has_error(mon));
|
||||
if (data) {
|
||||
cmd->user_print(mon, data);
|
||||
qobject_decref(data);
|
||||
}
|
||||
} else {
|
||||
cmd->mhandler.cmd(mon, qdict);
|
||||
}
|
||||
|
@ -4321,6 +4393,38 @@ static QDict *qmp_check_input_obj(QObject *input_obj)
|
|||
return input_dict;
|
||||
}
|
||||
|
||||
static void qmp_call_query_cmd(Monitor *mon, const mon_cmd_t *cmd)
|
||||
{
|
||||
QObject *ret_data = NULL;
|
||||
|
||||
if (handler_is_async(cmd)) {
|
||||
qmp_async_info_handler(mon, cmd);
|
||||
if (monitor_has_error(mon)) {
|
||||
monitor_protocol_emitter(mon, NULL);
|
||||
}
|
||||
} else {
|
||||
cmd->mhandler.info_new(mon, &ret_data);
|
||||
if (ret_data) {
|
||||
monitor_protocol_emitter(mon, ret_data);
|
||||
qobject_decref(ret_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd,
|
||||
const QDict *params)
|
||||
{
|
||||
int ret;
|
||||
QObject *data = NULL;
|
||||
|
||||
mon_print_count_init(mon);
|
||||
|
||||
ret = cmd->mhandler.cmd_new(mon, params, &data);
|
||||
handler_audit(mon, cmd, ret);
|
||||
monitor_protocol_emitter(mon, data);
|
||||
qobject_decref(data);
|
||||
}
|
||||
|
||||
static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
||||
{
|
||||
int err;
|
||||
|
@ -4328,8 +4432,9 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
|||
QDict *input, *args;
|
||||
const mon_cmd_t *cmd;
|
||||
Monitor *mon = cur_mon;
|
||||
const char *cmd_name, *info_item;
|
||||
const char *cmd_name, *query_cmd;
|
||||
|
||||
query_cmd = NULL;
|
||||
args = input = NULL;
|
||||
|
||||
obj = json_parser_parse(tokens, NULL);
|
||||
|
@ -4354,24 +4459,15 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: We need this special case until we get info handlers
|
||||
* converted into 'query-' commands
|
||||
*/
|
||||
if (compare_cmd(cmd_name, "info")) {
|
||||
if (strstart(cmd_name, "query-", &query_cmd)) {
|
||||
cmd = qmp_find_query_cmd(query_cmd);
|
||||
} else {
|
||||
cmd = qmp_find_cmd(cmd_name);
|
||||
}
|
||||
|
||||
if (!cmd) {
|
||||
qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
|
||||
goto err_out;
|
||||
} else if (strstart(cmd_name, "query-", &info_item)) {
|
||||
cmd = monitor_find_command("info");
|
||||
qdict_put_obj(input, "arguments",
|
||||
qobject_from_jsonf("{ 'item': %s }", info_item));
|
||||
} else {
|
||||
cmd = monitor_find_command(cmd_name);
|
||||
if (!cmd || !monitor_handler_ported(cmd)
|
||||
|| monitor_cmd_user_only(cmd)) {
|
||||
qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
obj = qdict_get(input, "arguments");
|
||||
|
@ -4387,14 +4483,16 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
if (monitor_handler_is_async(cmd)) {
|
||||
if (query_cmd) {
|
||||
qmp_call_query_cmd(mon, cmd);
|
||||
} else if (handler_is_async(cmd)) {
|
||||
err = qmp_async_cmd_handler(mon, cmd, args);
|
||||
if (err) {
|
||||
/* emit the error response */
|
||||
goto err_out;
|
||||
}
|
||||
} else {
|
||||
monitor_call_handler(mon, cmd, args);
|
||||
qmp_call_cmd(mon, cmd, args);
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue