Merge remote branch 'qmp/for-anthony' into staging

This commit is contained in:
Anthony Liguori 2010-10-05 13:54:49 -05:00
commit 48f57044e6
12 changed files with 1527 additions and 1192 deletions

366
monitor.c
View file

@ -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;