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

View file

@ -255,10 +255,10 @@ TEXIFLAG=$(if $(V),,--quiet)
qemu-options.texi: $(SRC_PATH)/qemu-options.hx qemu-options.texi: $(SRC_PATH)/qemu-options.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@") $(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
qemu-monitor.texi: $(SRC_PATH)/qemu-monitor.hx qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@") $(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
QMP/qmp-commands.txt: $(SRC_PATH)/qemu-monitor.hx QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -q < $< > $@," GEN $@") $(call quiet-command,sh $(SRC_PATH)/hxtool -q < $< > $@," GEN $@")
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx

View file

@ -309,7 +309,7 @@ obj-alpha-y = alpha_palcode.o
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
monitor.o: qemu-monitor.h monitor.o: hmp-commands.h qmp-commands.h
$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
@ -330,13 +330,16 @@ $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/feature_to_c.sh gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/feature_to_c.sh
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@") $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
qemu-monitor.h: $(SRC_PATH)/qemu-monitor.hx hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
qmp-commands.h: $(SRC_PATH)/qmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
clean: clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
rm -f *.d */*.d tcg/*.o ide/*.o rm -f *.d */*.d tcg/*.o ide/*.o
rm -f qemu-monitor.h gdbstub-xml.c rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c
install: all install: all
ifneq ($(PROGS),) ifneq ($(PROGS),)

View file

@ -82,10 +82,10 @@ doing any code change. This is so because:
2. Review can improve your interface. Letting that happen before 2. Review can improve your interface. Letting that happen before
you implement it can save you work. you implement it can save you work.
* The qmp-commands.txt file is generated from the qemu-monitor.hx one, which * The qmp-commands.txt file is generated from the qmp-commands.hx one, which
is the file that should be edited. is the file that should be edited.
Homepage Homepage
-------- --------
http://www.linux-kvm.org/page/MonitorProtocol http://wiki.qemu.org/QMP

1216
hmp-commands.hx Normal file

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,10 @@
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
/* Disable guest-provided stats by now (https://bugzilla.redhat.com/show_bug.cgi?id=623903) */
#define ENABLE_GUEST_STATS 0
typedef struct VirtIOBalloon typedef struct VirtIOBalloon
{ {
VirtIODevice vdev; VirtIODevice vdev;
@ -83,12 +87,14 @@ static QObject *get_stats_qobject(VirtIOBalloon *dev)
VIRTIO_BALLOON_PFN_SHIFT); VIRTIO_BALLOON_PFN_SHIFT);
stat_put(dict, "actual", actual); stat_put(dict, "actual", actual);
#if ENABLE_GUEST_STATS
stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]); stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]);
stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]); stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]);
stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]); stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]);
stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]); stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]);
stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]); stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]);
stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]); stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]);
#endif
return QOBJECT(dict); return QOBJECT(dict);
} }
@ -214,7 +220,7 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
} }
dev->stats_callback = cb; dev->stats_callback = cb;
dev->stats_opaque_callback_data = cb_data; dev->stats_opaque_callback_data = cb_data;
if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) { if (ENABLE_GUEST_STATS && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset); virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
virtio_notify(&dev->vdev, dev->svq); virtio_notify(&dev->vdev, dev->svq);
} else { } else {

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 mon_cmds[];
static const mon_cmd_t info_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 *cur_mon;
Monitor *default_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 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; 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; 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) static inline int monitor_has_error(const Monitor *mon)
{ {
return mon->error != NULL; return mon->error != NULL;
@ -352,7 +350,10 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
{ {
QString *json; 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); assert(json != NULL);
qstring_append_chr(json, '\n'); 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 mon_cmd_t *cmd;
const char *item = qdict_get_try_str(qdict, "item"); const char *item = qdict_get_try_str(qdict, "item");
if (!item) { if (!item) {
assert(monitor_ctrl_mode(mon) == 0);
goto help; goto help;
} }
@ -650,56 +650,27 @@ static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
} }
if (cmd->name == NULL) { if (cmd->name == NULL) {
if (monitor_ctrl_mode(mon)) {
qerror_report(QERR_COMMAND_NOT_FOUND, item);
return -1;
}
goto help; goto help;
} }
if (monitor_ctrl_mode(mon) && monitor_cmd_user_only(cmd)) { if (handler_is_async(cmd)) {
qerror_report(QERR_COMMAND_NOT_FOUND, item); user_async_info_handler(mon, cmd);
return -1; } else if (handler_is_qobject(cmd)) {
} QObject *info_data = NULL;
if (monitor_handler_is_async(cmd)) { cmd->mhandler.info_new(mon, &info_data);
if (monitor_ctrl_mode(mon)) { if (info_data) {
qmp_async_info_handler(mon, cmd); cmd->user_print(mon, info_data);
} else { qobject_decref(info_data);
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);
} }
} else { } else {
if (monitor_ctrl_mode(mon)) { cmd->mhandler.info(mon);
/* handler not converted yet */
qerror_report(QERR_COMMAND_NOT_FOUND, item);
return -1;
} else {
cmd->mhandler.info(mon);
}
} }
return 0; return;
help: help:
help_cmd(mon, "info"); help_cmd(mon, "info");
return 0;
} }
static void do_info_version_print(Monitor *mon, const QObject *data) 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(); cmd_list = qlist_new();
for (cmd = mon_cmds; cmd->name != NULL; cmd++) { for (cmd = qmp_cmds; cmd->name != NULL; cmd++) {
if (monitor_handler_ported(cmd) && !monitor_cmd_user_only(cmd) && qlist_append_obj(cmd_list, get_cmd_dict(cmd->name));
!compare_cmd(cmd->name, "info")) {
qlist_append_obj(cmd_list, get_cmd_dict(cmd->name));
}
} }
for (cmd = info_cmds; cmd->name != NULL; cmd++) { for (cmd = qmp_query_cmds; cmd->name != NULL; cmd++) {
if (monitor_handler_ported(cmd) && !monitor_cmd_user_only(cmd)) { char buf[128];
char buf[128]; snprintf(buf, sizeof(buf), "query-%s", cmd->name);
snprintf(buf, sizeof(buf), "query-%s", cmd->name); qlist_append_obj(cmd_list, get_cmd_dict(buf));
qlist_append_obj(cmd_list, get_cmd_dict(buf));
}
} }
*ret_data = QOBJECT(cmd_list); *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[] = { static const mon_cmd_t mon_cmds[] = {
#include "qemu-monitor.h" #include "hmp-commands.h"
{ NULL, NULL, }, { 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[] = { static const mon_cmd_t info_cmds[] = {
{ {
.name = "version", .name = "version",
@ -2381,14 +2347,6 @@ static const mon_cmd_t info_cmds[] = {
.user_print = do_info_version_print, .user_print = do_info_version_print,
.mhandler.info_new = do_info_version, .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", .name = "network",
.args_type = "", .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; static const char *pch;
@ -3369,11 +3457,12 @@ static int is_valid_option(const char *c, const char *typestr)
return (typestr != NULL); 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; 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)) { if (compare_cmd(cmdname, cmd->name)) {
return cmd; return cmd;
} }
@ -3382,6 +3471,21 @@ static const mon_cmd_t *monitor_find_command(const char *cmdname)
return NULL; 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, static const mon_cmd_t *monitor_parse_command(Monitor *mon,
const char *cmdline, const char *cmdline,
QDict *qdict) 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) static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
{ {
if (monitor_ctrl_mode(mon)) { 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) static void handle_user_command(Monitor *mon, const char *cmdline)
{ {
QDict *qdict; QDict *qdict;
@ -3828,10 +3892,18 @@ static void handle_user_command(Monitor *mon, const char *cmdline)
if (!cmd) if (!cmd)
goto out; goto out;
if (monitor_handler_is_async(cmd)) { if (handler_is_async(cmd)) {
user_async_cmd_handler(mon, cmd, qdict); user_async_cmd_handler(mon, cmd, qdict);
} else if (monitor_handler_ported(cmd)) { } else if (handler_is_qobject(cmd)) {
monitor_call_handler(mon, cmd, qdict); 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 { } else {
cmd->mhandler.cmd(mon, qdict); cmd->mhandler.cmd(mon, qdict);
} }
@ -4321,6 +4393,38 @@ static QDict *qmp_check_input_obj(QObject *input_obj)
return input_dict; 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) static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
{ {
int err; int err;
@ -4328,8 +4432,9 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
QDict *input, *args; QDict *input, *args;
const mon_cmd_t *cmd; const mon_cmd_t *cmd;
Monitor *mon = cur_mon; Monitor *mon = cur_mon;
const char *cmd_name, *info_item; const char *cmd_name, *query_cmd;
query_cmd = NULL;
args = input = NULL; args = input = NULL;
obj = json_parser_parse(tokens, NULL); obj = json_parser_parse(tokens, NULL);
@ -4354,24 +4459,15 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
goto err_out; goto err_out;
} }
/* if (strstart(cmd_name, "query-", &query_cmd)) {
* XXX: We need this special case until we get info handlers cmd = qmp_find_query_cmd(query_cmd);
* converted into 'query-' commands } else {
*/ cmd = qmp_find_cmd(cmd_name);
if (compare_cmd(cmd_name, "info")) { }
if (!cmd) {
qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
goto err_out; 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"); obj = qdict_get(input, "arguments");
@ -4387,14 +4483,16 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
goto err_out; 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); err = qmp_async_cmd_handler(mon, cmd, args);
if (err) { if (err) {
/* emit the error response */ /* emit the error response */
goto err_out; goto err_out;
} }
} else { } else {
monitor_call_handler(mon, cmd, args); qmp_call_cmd(mon, cmd, args);
} }
goto out; goto out;

View file

@ -14,10 +14,10 @@ extern Monitor *default_mon;
#define MONITOR_IS_DEFAULT 0x01 #define MONITOR_IS_DEFAULT 0x01
#define MONITOR_USE_READLINE 0x02 #define MONITOR_USE_READLINE 0x02
#define MONITOR_USE_CONTROL 0x04 #define MONITOR_USE_CONTROL 0x04
#define MONITOR_USE_PRETTY 0x08
/* flags for monitor commands */ /* flags for monitor commands */
#define MONITOR_CMD_ASYNC 0x0001 #define MONITOR_CMD_ASYNC 0x0001
#define MONITOR_CMD_USER_ONLY 0x0002
/* QMP events */ /* QMP events */
typedef enum MonitorEvent { typedef enum MonitorEvent {

View file

@ -283,6 +283,9 @@ static QemuOptsList qemu_mon_opts = {
},{ },{
.name = "default", .name = "default",
.type = QEMU_OPT_BOOL, .type = QEMU_OPT_BOOL,
},{
.name = "pretty",
.type = QEMU_OPT_BOOL,
}, },
{ /* end of list */ } { /* end of list */ }
}, },

55
qjson.c
View file

@ -72,43 +72,57 @@ QObject *qobject_from_jsonf(const char *string, ...)
typedef struct ToJsonIterState typedef struct ToJsonIterState
{ {
int indent;
int pretty;
int count; int count;
QString *str; QString *str;
} ToJsonIterState; } ToJsonIterState;
static void to_json(const QObject *obj, QString *str); static void to_json(const QObject *obj, QString *str, int pretty, int indent);
static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) static void to_json_dict_iter(const char *key, QObject *obj, void *opaque)
{ {
ToJsonIterState *s = opaque; ToJsonIterState *s = opaque;
QString *qkey; QString *qkey;
int j;
if (s->count) { if (s->count)
qstring_append(s->str, ", "); qstring_append(s->str, ", ");
if (s->pretty) {
qstring_append(s->str, "\n");
for (j = 0 ; j < s->indent ; j++)
qstring_append(s->str, " ");
} }
qkey = qstring_from_str(key); qkey = qstring_from_str(key);
to_json(QOBJECT(qkey), s->str); to_json(QOBJECT(qkey), s->str, s->pretty, s->indent);
QDECREF(qkey); QDECREF(qkey);
qstring_append(s->str, ": "); qstring_append(s->str, ": ");
to_json(obj, s->str); to_json(obj, s->str, s->pretty, s->indent);
s->count++; s->count++;
} }
static void to_json_list_iter(QObject *obj, void *opaque) static void to_json_list_iter(QObject *obj, void *opaque)
{ {
ToJsonIterState *s = opaque; ToJsonIterState *s = opaque;
int j;
if (s->count) { if (s->count)
qstring_append(s->str, ", "); qstring_append(s->str, ", ");
if (s->pretty) {
qstring_append(s->str, "\n");
for (j = 0 ; j < s->indent ; j++)
qstring_append(s->str, " ");
} }
to_json(obj, s->str); to_json(obj, s->str, s->pretty, s->indent);
s->count++; s->count++;
} }
static void to_json(const QObject *obj, QString *str) static void to_json(const QObject *obj, QString *str, int pretty, int indent)
{ {
switch (qobject_type(obj)) { switch (qobject_type(obj)) {
case QTYPE_QINT: { case QTYPE_QINT: {
@ -193,8 +207,16 @@ static void to_json(const QObject *obj, QString *str)
s.count = 0; s.count = 0;
s.str = str; s.str = str;
s.indent = indent + 1;
s.pretty = pretty;
qstring_append(str, "{"); qstring_append(str, "{");
qdict_iter(val, to_json_dict_iter, &s); qdict_iter(val, to_json_dict_iter, &s);
if (pretty) {
int j;
qstring_append(str, "\n");
for (j = 0 ; j < indent ; j++)
qstring_append(str, " ");
}
qstring_append(str, "}"); qstring_append(str, "}");
break; break;
} }
@ -204,8 +226,16 @@ static void to_json(const QObject *obj, QString *str)
s.count = 0; s.count = 0;
s.str = str; s.str = str;
s.indent = indent + 1;
s.pretty = pretty;
qstring_append(str, "["); qstring_append(str, "[");
qlist_iter(val, (void *)to_json_list_iter, &s); qlist_iter(val, (void *)to_json_list_iter, &s);
if (pretty) {
int j;
qstring_append(str, "\n");
for (j = 0 ; j < indent ; j++)
qstring_append(str, " ");
}
qstring_append(str, "]"); qstring_append(str, "]");
break; break;
} }
@ -249,7 +279,16 @@ QString *qobject_to_json(const QObject *obj)
{ {
QString *str = qstring_new(); QString *str = qstring_new();
to_json(obj, str); to_json(obj, str, 0, 0);
return str;
}
QString *qobject_to_json_pretty(const QObject *obj)
{
QString *str = qstring_new();
to_json(obj, str, 1, 0);
return str; return str;
} }

View file

@ -23,5 +23,6 @@ QObject *qobject_from_jsonf(const char *string, ...) GCC_FMT_ATTR(1, 2);
QObject *qobject_from_jsonv(const char *string, va_list *ap) GCC_FMT_ATTR(1, 0); QObject *qobject_from_jsonv(const char *string, va_list *ap) GCC_FMT_ATTR(1, 0);
QString *qobject_to_json(const QObject *obj); QString *qobject_to_json(const QObject *obj);
QString *qobject_to_json_pretty(const QObject *obj);
#endif /* QJSON_H */ #endif /* QJSON_H */

File diff suppressed because it is too large Load diff

3
vl.c
View file

@ -1562,6 +1562,9 @@ static int mon_init_func(QemuOpts *opts, void *opaque)
exit(1); exit(1);
} }
if (qemu_opt_get_bool(opts, "pretty", 0))
flags |= MONITOR_USE_PRETTY;
if (qemu_opt_get_bool(opts, "default", 0)) if (qemu_opt_get_bool(opts, "default", 0))
flags |= MONITOR_IS_DEFAULT; flags |= MONITOR_IS_DEFAULT;