aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--balloon.c72
-rw-r--r--balloon.h6
-rw-r--r--block.c234
-rw-r--r--block.h5
-rw-r--r--block_int.h4
-rw-r--r--console.h9
-rw-r--r--cpus.c45
-rw-r--r--error.c3
-rw-r--r--hmp-commands.hx3
-rw-r--r--hmp.c407
-rw-r--r--hmp.h10
-rw-r--r--hw/pci-stub.c15
-rw-r--r--hw/pci.c322
-rw-r--r--hw/pci.h4
-rw-r--r--hw/virtio-balloon.c78
-rw-r--r--input.c64
-rw-r--r--migration.c82
-rw-r--r--monitor.c313
-rw-r--r--monitor.h2
-rw-r--r--qapi-schema.json616
-rw-r--r--qerror.c4
-rw-r--r--qmp-commands.hx60
-rw-r--r--qmp.c27
-rw-r--r--scripts/qapi-commands.py4
-rw-r--r--ui/spice-core.c139
-rw-r--r--ui/vnc.c135
-rw-r--r--vl.c2
27 files changed, 1611 insertions, 1054 deletions
diff --git a/balloon.c b/balloon.c
index a2133db..e1cd5fa 100644
--- a/balloon.c
+++ b/balloon.c
@@ -25,12 +25,11 @@
*/
#include "monitor.h"
-#include "qjson.h"
-#include "qint.h"
#include "cpu-common.h"
#include "kvm.h"
#include "balloon.h"
#include "trace.h"
+#include "qmp-commands.h"
static QEMUBalloonEvent *balloon_event_fn;
static QEMUBalloonStatus *balloon_stat_fn;
@@ -72,76 +71,33 @@ static int qemu_balloon(ram_addr_t target)
return 1;
}
-static int qemu_balloon_status(MonitorCompletion cb, void *opaque)
+static int qemu_balloon_status(BalloonInfo *info)
{
if (!balloon_stat_fn) {
return 0;
}
- balloon_stat_fn(balloon_opaque, cb, opaque);
+ balloon_stat_fn(balloon_opaque, info);
return 1;
}
-static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
+BalloonInfo *qmp_query_balloon(Error **errp)
{
- Monitor *mon = opaque;
-
- if (strcmp(key, "actual")) {
- monitor_printf(mon, ",%s=%" PRId64, key,
- qint_get_int(qobject_to_qint(obj)));
- }
-}
-
-void monitor_print_balloon(Monitor *mon, const QObject *data)
-{
- QDict *qdict;
-
- qdict = qobject_to_qdict(data);
- if (!qdict_haskey(qdict, "actual")) {
- return;
- }
- monitor_printf(mon, "balloon: actual=%" PRId64,
- qdict_get_int(qdict, "actual") >> 20);
- qdict_iter(qdict, print_balloon_stat, mon);
- monitor_printf(mon, "\n");
-}
-
-/**
- * do_info_balloon(): Balloon information
- *
- * Make an asynchronous request for balloon info. When the request completes
- * a QDict will be returned according to the following specification:
- *
- * - "actual": current balloon value in bytes
- * The following fields may or may not be present:
- * - "mem_swapped_in": Amount of memory swapped in (bytes)
- * - "mem_swapped_out": Amount of memory swapped out (bytes)
- * - "major_page_faults": Number of major faults
- * - "minor_page_faults": Number of minor faults
- * - "free_mem": Total amount of free and unused memory (bytes)
- * - "total_mem": Total amount of available memory (bytes)
- *
- * Example:
- *
- * { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0,
- * "major_page_faults": 142, "minor_page_faults": 239245,
- * "free_mem": 1014185984, "total_mem": 1044668416 }
- */
-int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
-{
- int ret;
+ BalloonInfo *info;
if (kvm_enabled() && !kvm_has_sync_mmu()) {
- qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
- return -1;
+ error_set(errp, QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
+ return NULL;
}
- ret = qemu_balloon_status(cb, opaque);
- if (!ret) {
- qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
- return -1;
+ info = g_malloc0(sizeof(*info));
+
+ if (qemu_balloon_status(info) == 0) {
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, "balloon");
+ qapi_free_BalloonInfo(info);
+ return NULL;
}
- return 0;
+ return info;
}
/**
diff --git a/balloon.h b/balloon.h
index f59e288..b36abea 100644
--- a/balloon.h
+++ b/balloon.h
@@ -15,17 +15,15 @@
#define _QEMU_BALLOON_H
#include "monitor.h"
+#include "qapi-types.h"
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
-typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
- void *cb_data);
+typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
QEMUBalloonStatus *stat_func, void *opaque);
void qemu_remove_balloon_handler(void *opaque);
-void monitor_print_balloon(Monitor *mon, const QObject *data);
-int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
int do_balloon(Monitor *mon, const QDict *params,
MonitorCompletion cb, void *opaque);
diff --git a/block.c b/block.c
index 70aab63..b5c1544 100644
--- a/block.c
+++ b/block.c
@@ -27,8 +27,9 @@
#include "monitor.h"
#include "block_int.h"
#include "module.h"
-#include "qemu-objects.h"
+#include "qjson.h"
#include "qemu-coroutine.h"
+#include "qmp-commands.h"
#ifdef CONFIG_BSD
#include <sys/types.h>
@@ -1824,195 +1825,105 @@ void bdrv_mon_event(const BlockDriverState *bdrv,
qobject_decref(data);
}
-static void bdrv_print_dict(QObject *obj, void *opaque)
+BlockInfoList *qmp_query_block(Error **errp)
{
- QDict *bs_dict;
- Monitor *mon = opaque;
-
- bs_dict = qobject_to_qdict(obj);
-
- monitor_printf(mon, "%s: removable=%d",
- qdict_get_str(bs_dict, "device"),
- qdict_get_bool(bs_dict, "removable"));
-
- if (qdict_get_bool(bs_dict, "removable")) {
- monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
- monitor_printf(mon, " tray-open=%d",
- qdict_get_bool(bs_dict, "tray-open"));
- }
-
- if (qdict_haskey(bs_dict, "io-status")) {
- monitor_printf(mon, " io-status=%s", qdict_get_str(bs_dict, "io-status"));
- }
-
- if (qdict_haskey(bs_dict, "inserted")) {
- QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
-
- monitor_printf(mon, " file=");
- monitor_print_filename(mon, qdict_get_str(qdict, "file"));
- if (qdict_haskey(qdict, "backing_file")) {
- monitor_printf(mon, " backing_file=");
- monitor_print_filename(mon, qdict_get_str(qdict, "backing_file"));
- }
- monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
- qdict_get_bool(qdict, "ro"),
- qdict_get_str(qdict, "drv"),
- qdict_get_bool(qdict, "encrypted"));
- } else {
- monitor_printf(mon, " [not inserted]");
- }
-
- monitor_printf(mon, "\n");
-}
-
-void bdrv_info_print(Monitor *mon, const QObject *data)
-{
- qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon);
-}
-
-static const char *const io_status_name[BDRV_IOS_MAX] = {
- [BDRV_IOS_OK] = "ok",
- [BDRV_IOS_FAILED] = "failed",
- [BDRV_IOS_ENOSPC] = "nospace",
-};
-
-void bdrv_info(Monitor *mon, QObject **ret_data)
-{
- QList *bs_list;
+ BlockInfoList *head = NULL, *cur_item = NULL;
BlockDriverState *bs;
- bs_list = qlist_new();
-
QTAILQ_FOREACH(bs, &bdrv_states, list) {
- QObject *bs_obj;
- QDict *bs_dict;
+ BlockInfoList *info = g_malloc0(sizeof(*info));
- bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', "
- "'removable': %i, 'locked': %i }",
- bs->device_name,
- bdrv_dev_has_removable_media(bs),
- bdrv_dev_is_medium_locked(bs));
- bs_dict = qobject_to_qdict(bs_obj);
+ info->value = g_malloc0(sizeof(*info->value));
+ info->value->device = g_strdup(bs->device_name);
+ info->value->type = g_strdup("unknown");
+ info->value->locked = bdrv_dev_is_medium_locked(bs);
+ info->value->removable = bdrv_dev_has_removable_media(bs);
if (bdrv_dev_has_removable_media(bs)) {
- qdict_put(bs_dict, "tray-open",
- qbool_from_int(bdrv_dev_is_tray_open(bs)));
+ info->value->has_tray_open = true;
+ info->value->tray_open = bdrv_dev_is_tray_open(bs);
}
if (bdrv_iostatus_is_enabled(bs)) {
- qdict_put(bs_dict, "io-status",
- qstring_from_str(io_status_name[bs->iostatus]));
+ info->value->has_io_status = true;
+ info->value->io_status = bs->iostatus;
}
if (bs->drv) {
- QObject *obj;
-
- obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
- "'encrypted': %i }",
- bs->filename, bs->read_only,
- bs->drv->format_name,
- bdrv_is_encrypted(bs));
- if (bs->backing_file[0] != '\0') {
- QDict *qdict = qobject_to_qdict(obj);
- qdict_put(qdict, "backing_file",
- qstring_from_str(bs->backing_file));
+ info->value->has_inserted = true;
+ info->value->inserted = g_malloc0(sizeof(*info->value->inserted));
+ info->value->inserted->file = g_strdup(bs->filename);
+ info->value->inserted->ro = bs->read_only;
+ info->value->inserted->drv = g_strdup(bs->drv->format_name);
+ info->value->inserted->encrypted = bs->encrypted;
+ if (bs->backing_file[0]) {
+ info->value->inserted->has_backing_file = true;
+ info->value->inserted->backing_file = g_strdup(bs->backing_file);
}
+ }
- qdict_put_obj(bs_dict, "inserted", obj);
+ /* XXX: waiting for the qapi to support GSList */
+ if (!cur_item) {
+ head = cur_item = info;
+ } else {
+ cur_item->next = info;
+ cur_item = info;
}
- qlist_append_obj(bs_list, bs_obj);
}
- *ret_data = QOBJECT(bs_list);
-}
-
-static void bdrv_stats_iter(QObject *data, void *opaque)
-{
- QDict *qdict;
- Monitor *mon = opaque;
-
- qdict = qobject_to_qdict(data);
- monitor_printf(mon, "%s:", qdict_get_str(qdict, "device"));
-
- qdict = qobject_to_qdict(qdict_get(qdict, "stats"));
- monitor_printf(mon, " rd_bytes=%" PRId64
- " wr_bytes=%" PRId64
- " rd_operations=%" PRId64
- " wr_operations=%" PRId64
- " flush_operations=%" PRId64
- " wr_total_time_ns=%" PRId64
- " rd_total_time_ns=%" PRId64
- " flush_total_time_ns=%" PRId64
- "\n",
- qdict_get_int(qdict, "rd_bytes"),
- qdict_get_int(qdict, "wr_bytes"),
- qdict_get_int(qdict, "rd_operations"),
- qdict_get_int(qdict, "wr_operations"),
- qdict_get_int(qdict, "flush_operations"),
- qdict_get_int(qdict, "wr_total_time_ns"),
- qdict_get_int(qdict, "rd_total_time_ns"),
- qdict_get_int(qdict, "flush_total_time_ns"));
+ return head;
}
-void bdrv_stats_print(Monitor *mon, const QObject *data)
+/* Consider exposing this as a full fledged QMP command */
+static BlockStats *qmp_query_blockstat(const BlockDriverState *bs, Error **errp)
{
- qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon);
-}
+ BlockStats *s;
-static QObject* bdrv_info_stats_bs(BlockDriverState *bs)
-{
- QObject *res;
- QDict *dict;
+ s = g_malloc0(sizeof(*s));
- res = qobject_from_jsonf("{ 'stats': {"
- "'rd_bytes': %" PRId64 ","
- "'wr_bytes': %" PRId64 ","
- "'rd_operations': %" PRId64 ","
- "'wr_operations': %" PRId64 ","
- "'wr_highest_offset': %" PRId64 ","
- "'flush_operations': %" PRId64 ","
- "'wr_total_time_ns': %" PRId64 ","
- "'rd_total_time_ns': %" PRId64 ","
- "'flush_total_time_ns': %" PRId64
- "} }",
- bs->nr_bytes[BDRV_ACCT_READ],
- bs->nr_bytes[BDRV_ACCT_WRITE],
- bs->nr_ops[BDRV_ACCT_READ],
- bs->nr_ops[BDRV_ACCT_WRITE],
- bs->wr_highest_sector *
- (uint64_t)BDRV_SECTOR_SIZE,
- bs->nr_ops[BDRV_ACCT_FLUSH],
- bs->total_time_ns[BDRV_ACCT_WRITE],
- bs->total_time_ns[BDRV_ACCT_READ],
- bs->total_time_ns[BDRV_ACCT_FLUSH]);
- dict = qobject_to_qdict(res);
-
- if (*bs->device_name) {
- qdict_put(dict, "device", qstring_from_str(bs->device_name));
+ if (bs->device_name[0]) {
+ s->has_device = true;
+ s->device = g_strdup(bs->device_name);
}
+ s->stats = g_malloc0(sizeof(*s->stats));
+ s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ];
+ s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE];
+ s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ];
+ s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE];
+ s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE;
+ s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH];
+ s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE];
+ s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ];
+ s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH];
+
if (bs->file) {
- QObject *parent = bdrv_info_stats_bs(bs->file);
- qdict_put_obj(dict, "parent", parent);
+ s->has_parent = true;
+ s->parent = qmp_query_blockstat(bs->file, NULL);
}
- return res;
+ return s;
}
-void bdrv_info_stats(Monitor *mon, QObject **ret_data)
+BlockStatsList *qmp_query_blockstats(Error **errp)
{
- QObject *obj;
- QList *devices;
+ BlockStatsList *head = NULL, *cur_item = NULL;
BlockDriverState *bs;
- devices = qlist_new();
-
QTAILQ_FOREACH(bs, &bdrv_states, list) {
- obj = bdrv_info_stats_bs(bs);
- qlist_append_obj(devices, obj);
+ BlockStatsList *info = g_malloc0(sizeof(*info));
+ info->value = qmp_query_blockstat(bs, NULL);
+
+ /* XXX: waiting for the qapi to support GSList */
+ if (!cur_item) {
+ head = cur_item = info;
+ } else {
+ cur_item->next = info;
+ cur_item = info;
+ }
}
- *ret_data = QOBJECT(devices);
+ return head;
}
const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
@@ -3139,14 +3050,15 @@ int bdrv_in_use(BlockDriverState *bs)
void bdrv_iostatus_enable(BlockDriverState *bs)
{
- bs->iostatus = BDRV_IOS_OK;
+ bs->iostatus_enabled = true;
+ bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
}
/* The I/O status is only enabled if the drive explicitly
* enables it _and_ the VM is configured to stop on errors */
bool bdrv_iostatus_is_enabled(const BlockDriverState *bs)
{
- return (bs->iostatus != BDRV_IOS_INVAL &&
+ return (bs->iostatus_enabled &&
(bs->on_write_error == BLOCK_ERR_STOP_ENOSPC ||
bs->on_write_error == BLOCK_ERR_STOP_ANY ||
bs->on_read_error == BLOCK_ERR_STOP_ANY));
@@ -3154,13 +3066,13 @@ bool bdrv_iostatus_is_enabled(const BlockDriverState *bs)
void bdrv_iostatus_disable(BlockDriverState *bs)
{
- bs->iostatus = BDRV_IOS_INVAL;
+ bs->iostatus_enabled = false;
}
void bdrv_iostatus_reset(BlockDriverState *bs)
{
if (bdrv_iostatus_is_enabled(bs)) {
- bs->iostatus = BDRV_IOS_OK;
+ bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
}
}
@@ -3169,9 +3081,11 @@ void bdrv_iostatus_reset(BlockDriverState *bs)
possible to implement this without device models being involved */
void bdrv_iostatus_set_err(BlockDriverState *bs, int error)
{
- if (bdrv_iostatus_is_enabled(bs) && bs->iostatus == BDRV_IOS_OK) {
+ if (bdrv_iostatus_is_enabled(bs) &&
+ bs->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
assert(error >= 0);
- bs->iostatus = error == ENOSPC ? BDRV_IOS_ENOSPC : BDRV_IOS_FAILED;
+ bs->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
+ BLOCK_DEVICE_IO_STATUS_FAILED;
}
}
diff --git a/block.h b/block.h
index 5a042c9..38cd748 100644
--- a/block.h
+++ b/block.h
@@ -77,11 +77,6 @@ typedef enum {
BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
} BlockMonEventAction;
-typedef enum {
- BDRV_IOS_INVAL, BDRV_IOS_OK, BDRV_IOS_FAILED, BDRV_IOS_ENOSPC,
- BDRV_IOS_MAX
-} BlockIOStatus;
-
void bdrv_iostatus_enable(BlockDriverState *bs);
void bdrv_iostatus_reset(BlockDriverState *bs);
void bdrv_iostatus_disable(BlockDriverState *bs);
diff --git a/block_int.h b/block_int.h
index dac00f5..f4547f6 100644
--- a/block_int.h
+++ b/block_int.h
@@ -29,6 +29,7 @@
#include "qemu-queue.h"
#include "qemu-coroutine.h"
#include "qemu-timer.h"
+#include "qapi-types.h"
#define BLOCK_FLAG_ENCRYPT 1
#define BLOCK_FLAG_COMPAT6 4
@@ -202,7 +203,8 @@ struct BlockDriverState {
drivers. They are not used by the block driver */
int cyls, heads, secs, translation;
BlockErrorAction on_read_error, on_write_error;
- BlockIOStatus iostatus;
+ bool iostatus_enabled;
+ BlockDeviceIoStatus iostatus;
char device_name[32];
unsigned long *dirty_bitmap;
int64_t dirty_count;
diff --git a/console.h b/console.h
index 9c1487e..6ac4ed3 100644
--- a/console.h
+++ b/console.h
@@ -383,8 +383,6 @@ char *vnc_display_local_addr(DisplayState *ds);
#ifdef CONFIG_VNC
int vnc_display_password(DisplayState *ds, const char *password);
int vnc_display_pw_expire(DisplayState *ds, time_t expires);
-void do_info_vnc_print(Monitor *mon, const QObject *data);
-void do_info_vnc(Monitor *mon, QObject **ret_data);
#else
static inline int vnc_display_password(DisplayState *ds, const char *password)
{
@@ -396,13 +394,6 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
qerror_report(QERR_FEATURE_DISABLED, "vnc");
return -ENODEV;
};
-static inline void do_info_vnc(Monitor *mon, QObject **ret_data)
-{
-};
-static inline void do_info_vnc_print(Monitor *mon, const QObject *data)
-{
- monitor_printf(mon, "VNC support disabled\n");
-};
#endif
/* curses.c */
diff --git a/cpus.c b/cpus.c
index 79a7656..f768683 100644
--- a/cpus.c
+++ b/cpus.c
@@ -30,6 +30,7 @@
#include "gdbstub.h"
#include "dma.h"
#include "kvm.h"
+#include "qmp-commands.h"
#include "qemu-thread.h"
#include "cpus.h"
@@ -1094,3 +1095,47 @@ void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
cpu_list(f, cpu_fprintf); /* deprecated */
#endif
}
+
+CpuInfoList *qmp_query_cpus(Error **errp)
+{
+ CpuInfoList *head = NULL, *cur_item = NULL;
+ CPUState *env;
+
+ for(env = first_cpu; env != NULL; env = env->next_cpu) {
+ CpuInfoList *info;
+
+ cpu_synchronize_state(env);
+
+ info = g_malloc0(sizeof(*info));
+ info->value = g_malloc0(sizeof(*info->value));
+ info->value->CPU = env->cpu_index;
+ info->value->current = (env == first_cpu);
+ info->value->halted = env->halted;
+ info->value->thread_id = env->thread_id;
+#if defined(TARGET_I386)
+ info->value->has_pc = true;
+ info->value->pc = env->eip + env->segs[R_CS].base;
+#elif defined(TARGET_PPC)
+ info->value->has_nip = true;
+ info->value->nip = env->nip;
+#elif defined(TARGET_SPARC)
+ info->value->has_pc = true;
+ info->value->pc = env->pc;
+ info->value->has_npc = true;
+ info->value->npc = env->npc;
+#elif defined(TARGET_MIPS)
+ info->value->has_PC = true;
+ info->value->PC = env->active_tc.PC;
+#endif
+
+ /* XXX: waiting for the qapi to support GSList */
+ if (!cur_item) {
+ head = cur_item = info;
+ } else {
+ cur_item->next = info;
+ cur_item = info;
+ }
+ }
+
+ return head;
+}
diff --git a/error.c b/error.c
index 68c0039..990050f 100644
--- a/error.c
+++ b/error.c
@@ -12,8 +12,9 @@
#include "qemu-common.h"
#include "error.h"
+#include "qjson.h"
+#include "qdict.h"
#include "error_int.h"
-#include "qemu-objects.h"
#include "qerror.h"
struct Error
diff --git a/hmp-commands.hx b/hmp-commands.hx
index e181267..089c1ac 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -587,8 +587,7 @@ ETEXI
.args_type = "index:i",
.params = "index",
.help = "set the default CPU",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_cpu_set,
+ .mhandler.cmd = hmp_cpu,
},
STEXI
diff --git a/hmp.c b/hmp.c
index 34416fc..443d3a7 100644
--- a/hmp.c
+++ b/hmp.c
@@ -94,6 +94,401 @@ void hmp_info_chardev(Monitor *mon)
qapi_free_ChardevInfoList(char_info);
}
+void hmp_info_mice(Monitor *mon)
+{
+ MouseInfoList *mice_list, *mouse;
+
+ mice_list = qmp_query_mice(NULL);
+ if (!mice_list) {
+ monitor_printf(mon, "No mouse devices connected\n");
+ return;
+ }
+
+ for (mouse = mice_list; mouse; mouse = mouse->next) {
+ monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
+ mouse->value->current ? '*' : ' ',
+ mouse->value->index, mouse->value->name,
+ mouse->value->absolute ? " (absolute)" : "");
+ }
+
+ qapi_free_MouseInfoList(mice_list);
+}
+
+void hmp_info_migrate(Monitor *mon)
+{
+ MigrationInfo *info;
+
+ info = qmp_query_migrate(NULL);
+
+ if (info->has_status) {
+ monitor_printf(mon, "Migration status: %s\n", info->status);
+ }
+
+ if (info->has_ram) {
+ monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n",
+ info->ram->transferred >> 10);
+ monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n",
+ info->ram->remaining >> 10);
+ monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n",
+ info->ram->total >> 10);
+ }
+
+ if (info->has_disk) {
+ monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n",
+ info->disk->transferred >> 10);
+ monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n",
+ info->disk->remaining >> 10);
+ monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n",
+ info->disk->total >> 10);
+ }
+
+ qapi_free_MigrationInfo(info);
+}
+
+void hmp_info_cpus(Monitor *mon)
+{
+ CpuInfoList *cpu_list, *cpu;
+
+ cpu_list = qmp_query_cpus(NULL);
+
+ for (cpu = cpu_list; cpu; cpu = cpu->next) {
+ int active = ' ';
+
+ if (cpu->value->CPU == monitor_get_cpu_index()) {
+ active = '*';
+ }
+
+ monitor_printf(mon, "%c CPU #%" PRId64 ": ", active, cpu->value->CPU);
+
+ if (cpu->value->has_pc) {
+ monitor_printf(mon, "pc=0x%016" PRIx64, cpu->value->pc);
+ }
+ if (cpu->value->has_nip) {
+ monitor_printf(mon, "nip=0x%016" PRIx64, cpu->value->nip);
+ }
+ if (cpu->value->has_npc) {
+ monitor_printf(mon, "pc=0x%016" PRIx64, cpu->value->pc);
+ monitor_printf(mon, "npc=0x%016" PRIx64, cpu->value->npc);
+ }
+ if (cpu->value->has_PC) {
+ monitor_printf(mon, "PC=0x%016" PRIx64, cpu->value->PC);
+ }
+
+ if (cpu->value->halted) {
+ monitor_printf(mon, " (halted)");
+ }
+
+ monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id);
+ }
+
+ qapi_free_CpuInfoList(cpu_list);
+}
+
+void hmp_info_block(Monitor *mon)
+{
+ BlockInfoList *block_list, *info;
+
+ block_list = qmp_query_block(NULL);
+
+ for (info = block_list; info; info = info->next) {
+ monitor_printf(mon, "%s: removable=%d",
+ info->value->device, info->value->removable);
+
+ if (info->value->removable) {
+ monitor_printf(mon, " locked=%d", info->value->locked);
+ monitor_printf(mon, " tray-open=%d", info->value->tray_open);
+ }
+
+ if (info->value->has_io_status) {
+ monitor_printf(mon, " io-status=%s",
+ BlockDeviceIoStatus_lookup[info->value->io_status]);
+ }
+
+ if (info->value->has_inserted) {
+ monitor_printf(mon, " file=");
+ monitor_print_filename(mon, info->value->inserted->file);
+
+ if (info->value->inserted->has_backing_file) {
+ monitor_printf(mon, " backing_file=");
+ monitor_print_filename(mon, info->value->inserted->backing_file);
+ }
+ monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
+ info->value->inserted->ro,
+ info->value->inserted->drv,
+ info->value->inserted->encrypted);
+ } else {
+ monitor_printf(mon, " [not inserted]");
+ }
+
+ monitor_printf(mon, "\n");
+ }
+
+ qapi_free_BlockInfoList(block_list);
+}
+
+void hmp_info_blockstats(Monitor *mon)
+{
+ BlockStatsList *stats_list, *stats;
+
+ stats_list = qmp_query_blockstats(NULL);
+
+ for (stats = stats_list; stats; stats = stats->next) {
+ if (!stats->value->has_device) {
+ continue;
+ }
+
+ monitor_printf(mon, "%s:", stats->value->device);
+ monitor_printf(mon, " rd_bytes=%" PRId64
+ " wr_bytes=%" PRId64
+ " rd_operations=%" PRId64
+ " wr_operations=%" PRId64
+ " flush_operations=%" PRId64
+ " wr_total_time_ns=%" PRId64
+ " rd_total_time_ns=%" PRId64
+ " flush_total_time_ns=%" PRId64
+ "\n",
+ stats->value->stats->rd_bytes,
+ stats->value->stats->wr_bytes,
+ stats->value->stats->rd_operations,
+ stats->value->stats->wr_operations,
+ stats->value->stats->flush_operations,
+ stats->value->stats->wr_total_time_ns,
+ stats->value->stats->rd_total_time_ns,
+ stats->value->stats->flush_total_time_ns);
+ }
+
+ qapi_free_BlockStatsList(stats_list);
+}
+
+void hmp_info_vnc(Monitor *mon)
+{
+ VncInfo *info;
+ Error *err = NULL;
+ VncClientInfoList *client;
+
+ info = qmp_query_vnc(&err);
+ if (err) {
+ monitor_printf(mon, "%s\n", error_get_pretty(err));
+ error_free(err);
+ return;
+ }
+
+ if (!info->enabled) {
+ monitor_printf(mon, "Server: disabled\n");
+ goto out;
+ }
+
+ monitor_printf(mon, "Server:\n");
+ if (info->has_host && info->has_service) {
+ monitor_printf(mon, " address: %s:%s\n", info->host, info->service);
+ }
+ if (info->has_auth) {
+ monitor_printf(mon, " auth: %s\n", info->auth);
+ }
+
+ if (!info->has_clients || info->clients == NULL) {
+ monitor_printf(mon, "Client: none\n");
+ } else {
+ for (client = info->clients; client; client = client->next) {
+ monitor_printf(mon, "Client:\n");
+ monitor_printf(mon, " address: %s:%s\n",
+ client->value->host, client->value->service);
+ monitor_printf(mon, " x509_dname: %s\n",
+ client->value->x509_dname ?
+ client->value->x509_dname : "none");
+ monitor_printf(mon, " username: %s\n",
+ client->value->has_sasl_username ?
+ client->value->sasl_username : "none");
+ }
+ }
+
+out:
+ qapi_free_VncInfo(info);
+}
+
+void hmp_info_spice(Monitor *mon)
+{
+ SpiceChannelList *chan;
+ SpiceInfo *info;
+
+ info = qmp_query_spice(NULL);
+
+ if (!info->enabled) {
+ monitor_printf(mon, "Server: disabled\n");
+ goto out;
+ }
+
+ monitor_printf(mon, "Server:\n");
+ if (info->has_port) {
+ monitor_printf(mon, " address: %s:%" PRId64 "\n",
+ info->host, info->port);
+ }
+ if (info->has_tls_port) {
+ monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
+ info->host, info->tls_port);
+ }
+ monitor_printf(mon, " auth: %s\n", info->auth);
+ monitor_printf(mon, " compiled: %s\n", info->compiled_version);
+
+ if (!info->has_channels || info->channels == NULL) {
+ monitor_printf(mon, "Channels: none\n");
+ } else {
+ for (chan = info->channels; chan; chan = chan->next) {
+ monitor_printf(mon, "Channel:\n");
+ monitor_printf(mon, " address: %s:%s%s\n",
+ chan->value->host, chan->value->port,
+ chan->value->tls ? " [tls]" : "");
+ monitor_printf(mon, " session: %" PRId64 "\n",
+ chan->value->connection_id);
+ monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n",
+ chan->value->channel_type, chan->value->channel_id);
+ }
+ }
+
+out:
+ qapi_free_SpiceInfo(info);
+}
+
+void hmp_info_balloon(Monitor *mon)
+{
+ BalloonInfo *info;
+ Error *err = NULL;
+
+ info = qmp_query_balloon(&err);
+ if (err) {
+ monitor_printf(mon, "%s\n", error_get_pretty(err));
+ error_free(err);
+ return;
+ }
+
+ monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20);
+ if (info->has_mem_swapped_in) {
+ monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in);
+ }
+ if (info->has_mem_swapped_out) {
+ monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out);
+ }
+ if (info->has_major_page_faults) {
+ monitor_printf(mon, " major_page_faults=%" PRId64,
+ info->major_page_faults);
+ }
+ if (info->has_minor_page_faults) {
+ monitor_printf(mon, " minor_page_faults=%" PRId64,
+ info->minor_page_faults);
+ }
+ if (info->has_free_mem) {
+ monitor_printf(mon, " free_mem=%" PRId64, info->free_mem);
+ }
+ if (info->has_total_mem) {
+ monitor_printf(mon, " total_mem=%" PRId64, info->total_mem);
+ }
+
+ monitor_printf(mon, "\n");
+
+ qapi_free_BalloonInfo(info);
+}
+
+static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
+{
+ PciMemoryRegionList *region;
+
+ monitor_printf(mon, " Bus %2" PRId64 ", ", dev->bus);
+ monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
+ dev->slot, dev->function);
+ monitor_printf(mon, " ");
+
+ if (dev->class_info.has_desc) {
+ monitor_printf(mon, "%s", dev->class_info.desc);
+ } else {
+ monitor_printf(mon, "Class %04" PRId64, dev->class_info.class);
+ }
+
+ monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
+ dev->id.vendor, dev->id.device);
+
+ if (dev->has_irq) {
+ monitor_printf(mon, " IRQ %" PRId64 ".\n", dev->irq);
+ }
+
+ if (dev->has_pci_bridge) {
+ monitor_printf(mon, " BUS %" PRId64 ".\n",
+ dev->pci_bridge->bus.number);
+ monitor_printf(mon, " secondary bus %" PRId64 ".\n",
+ dev->pci_bridge->bus.secondary);
+ monitor_printf(mon, " subordinate bus %" PRId64 ".\n",
+ dev->pci_bridge->bus.subordinate);
+
+ monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
+ dev->pci_bridge->bus.io_range->base,
+ dev->pci_bridge->bus.io_range->limit);
+
+ monitor_printf(mon,
+ " memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
+ dev->pci_bridge->bus.memory_range->base,
+ dev->pci_bridge->bus.memory_range->limit);
+
+ monitor_printf(mon, " prefetchable memory range "
+ "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
+ dev->pci_bridge->bus.prefetchable_range->base,
+ dev->pci_bridge->bus.prefetchable_range->limit);
+ }
+
+ for (region = dev->regions; region; region = region->next) {
+ uint64_t addr, size;
+
+ addr = region->value->address;
+ size = region->value->size;
+
+ monitor_printf(mon, " BAR%" PRId64 ": ", region->value->bar);
+
+ if (!strcmp(region->value->type, "io")) {
+ monitor_printf(mon, "I/O at 0x%04" PRIx64
+ " [0x%04" PRIx64 "].\n",
+ addr, addr + size - 1);
+ } else {
+ monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
+ " [0x%08" PRIx64 "].\n",
+ region->value->mem_type_64 ? 64 : 32,
+ region->value->prefetch ? " prefetchable" : "",
+ addr, addr + size - 1);
+ }
+ }
+
+ monitor_printf(mon, " id \"%s\"\n", dev->qdev_id);
+
+ if (dev->has_pci_bridge) {
+ if (dev->pci_bridge->has_devices) {
+ PciDeviceInfoList *cdev;
+ for (cdev = dev->pci_bridge->devices; cdev; cdev = cdev->next) {
+ hmp_info_pci_device(mon, cdev->value);
+ }
+ }
+ }
+}
+
+void hmp_info_pci(Monitor *mon)
+{
+ PciInfoList *info;
+ Error *err = NULL;
+
+ info = qmp_query_pci(&err);
+ if (err) {
+ monitor_printf(mon, "PCI devices not supported\n");
+ error_free(err);
+ return;
+ }
+
+ for (; info; info = info->next) {
+ PciDeviceInfoList *dev;
+
+ for (dev = info->value->devices; dev; dev = dev->next) {
+ hmp_info_pci_device(mon, dev->value);
+ }
+ }
+
+ qapi_free_PciInfoList(info);
+}
+
void hmp_quit(Monitor *mon, const QDict *qdict)
{
monitor_suspend(mon);
@@ -114,3 +509,15 @@ void hmp_system_powerdown(Monitor *mon, const QDict *qdict)
{
qmp_system_powerdown(NULL);
}
+
+void hmp_cpu(Monitor *mon, const QDict *qdict)
+{
+ int64_t cpu_index;
+
+ /* XXX: drop the monitor_set_cpu() usage when all HMP commands that
+ use it are converted to the QAPI */
+ cpu_index = qdict_get_int(qdict, "index");
+ if (monitor_set_cpu(cpu_index) < 0) {
+ monitor_printf(mon, "invalid CPU index\n");
+ }
+}
diff --git a/hmp.h b/hmp.h
index 92433cf..4422578 100644
--- a/hmp.h
+++ b/hmp.h
@@ -23,9 +23,19 @@ void hmp_info_kvm(Monitor *mon);
void hmp_info_status(Monitor *mon);
void hmp_info_uuid(Monitor *mon);
void hmp_info_chardev(Monitor *mon);
+void hmp_info_mice(Monitor *mon);
+void hmp_info_migrate(Monitor *mon);
+void hmp_info_cpus(Monitor *mon);
+void hmp_info_block(Monitor *mon);
+void hmp_info_blockstats(Monitor *mon);
+void hmp_info_vnc(Monitor *mon);
+void hmp_info_spice(Monitor *mon);
+void hmp_info_balloon(Monitor *mon);
+void hmp_info_pci(Monitor *mon);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
+void hmp_cpu(Monitor *mon, const QDict *qdict);
#endif
diff --git a/hw/pci-stub.c b/hw/pci-stub.c
index 1fb105d..636171c 100644
--- a/hw/pci-stub.c
+++ b/hw/pci-stub.c
@@ -21,20 +21,17 @@
#include "sysemu.h"
#include "monitor.h"
#include "pci.h"
+#include "qmp-commands.h"
-static void pci_error_message(Monitor *mon)
+PciInfoList *qmp_query_pci(Error **errp)
{
- monitor_printf(mon, "PCI devices not supported\n");
+ error_set(errp, QERR_UNSUPPORTED);
+ return NULL;
}
-void do_pci_info(Monitor *mon, QObject **ret_data)
-{
- pci_error_message(mon);
-}
-
-void do_pci_info_print(Monitor *mon, const QObject *data)
+static void pci_error_message(Monitor *mon)
{
- pci_error_message(mon);
+ monitor_printf(mon, "PCI devices not supported\n");
}
int do_pcie_aer_inejct_error(Monitor *mon,
diff --git a/hw/pci.c b/hw/pci.c
index e8cc1b0..399227f 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -29,8 +29,8 @@
#include "net.h"
#include "sysemu.h"
#include "loader.h"
-#include "qemu-objects.h"
#include "range.h"
+#include "qmp-commands.h"
//#define DEBUG_PCI
#ifdef DEBUG_PCI
@@ -1164,276 +1164,194 @@ void pci_for_each_device(PCIBus *bus, int bus_num,
}
}
-static void pci_device_print(Monitor *mon, QDict *device)
+static const pci_class_desc *get_class_desc(int class)
{
- QDict *qdict;
- QListEntry *entry;
- uint64_t addr, size;
-
- monitor_printf(mon, " Bus %2" PRId64 ", ", qdict_get_int(device, "bus"));
- monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
- qdict_get_int(device, "slot"),
- qdict_get_int(device, "function"));
- monitor_printf(mon, " ");
-
- qdict = qdict_get_qdict(device, "class_info");
- if (qdict_haskey(qdict, "desc")) {
- monitor_printf(mon, "%s", qdict_get_str(qdict, "desc"));
- } else {
- monitor_printf(mon, "Class %04" PRId64, qdict_get_int(qdict, "class"));
- }
-
- qdict = qdict_get_qdict(device, "id");
- monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
- qdict_get_int(qdict, "device"),
- qdict_get_int(qdict, "vendor"));
+ const pci_class_desc *desc;
- if (qdict_haskey(device, "irq")) {
- monitor_printf(mon, " IRQ %" PRId64 ".\n",
- qdict_get_int(device, "irq"));
+ desc = pci_class_descriptions;
+ while (desc->desc && class != desc->class) {
+ desc++;
}
- if (qdict_haskey(device, "pci_bridge")) {
- QDict *info;
-
- qdict = qdict_get_qdict(device, "pci_bridge");
-
- info = qdict_get_qdict(qdict, "bus");
- monitor_printf(mon, " BUS %" PRId64 ".\n",
- qdict_get_int(info, "number"));
- monitor_printf(mon, " secondary bus %" PRId64 ".\n",
- qdict_get_int(info, "secondary"));
- monitor_printf(mon, " subordinate bus %" PRId64 ".\n",
- qdict_get_int(info, "subordinate"));
+ return desc;
+}
- info = qdict_get_qdict(qdict, "io_range");
- monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
- qdict_get_int(info, "base"),
- qdict_get_int(info, "limit"));
+static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
- info = qdict_get_qdict(qdict, "memory_range");
- monitor_printf(mon,
- " memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
- qdict_get_int(info, "base"),
- qdict_get_int(info, "limit"));
+static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
+{
+ PciMemoryRegionList *head = NULL, *cur_item = NULL;
+ int i;
- info = qdict_get_qdict(qdict, "prefetchable_range");
- monitor_printf(mon, " prefetchable memory range "
- "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
- qdict_get_int(info, "base"),
- qdict_get_int(info, "limit"));
- }
+ for (i = 0; i < PCI_NUM_REGIONS; i++) {
+ const PCIIORegion *r = &dev->io_regions[i];
+ PciMemoryRegionList *region;
- QLIST_FOREACH_ENTRY(qdict_get_qlist(device, "regions"), entry) {
- qdict = qobject_to_qdict(qlist_entry_obj(entry));
- monitor_printf(mon, " BAR%d: ", (int) qdict_get_int(qdict, "bar"));
+ if (!r->size) {
+ continue;
+ }
- addr = qdict_get_int(qdict, "address");
- size = qdict_get_int(qdict, "size");
+ region = g_malloc0(sizeof(*region));
+ region->value = g_malloc0(sizeof(*region->value));
- if (!strcmp(qdict_get_str(qdict, "type"), "io")) {
- monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
- " [0x%04"FMT_PCIBUS"].\n",
- addr, addr + size - 1);
+ if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+ region->value->type = g_strdup("io");
} else {
- monitor_printf(mon, "%d bit%s memory at 0x%08"FMT_PCIBUS
- " [0x%08"FMT_PCIBUS"].\n",
- qdict_get_bool(qdict, "mem_type_64") ? 64 : 32,
- qdict_get_bool(qdict, "prefetch") ?
- " prefetchable" : "", addr, addr + size - 1);
+ region->value->type = g_strdup("memory");
+ region->value->has_prefetch = true;
+ region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH);
+ region->value->has_mem_type_64 = true;
+ region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
}
- }
- monitor_printf(mon, " id \"%s\"\n", qdict_get_str(device, "qdev_id"));
+ region->value->bar = i;
+ region->value->address = r->addr;
+ region->value->size = r->size;
- if (qdict_haskey(device, "pci_bridge")) {
- qdict = qdict_get_qdict(device, "pci_bridge");
- if (qdict_haskey(qdict, "devices")) {
- QListEntry *dev;
- QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
- pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
- }
+ /* XXX: waiting for the qapi to support GSList */
+ if (!cur_item) {
+ head = cur_item = region;
+ } else {
+ cur_item->next = region;
+ cur_item = region;
}
}
-}
-
-void do_pci_info_print(Monitor *mon, const QObject *data)
-{
- QListEntry *bus, *dev;
- QLIST_FOREACH_ENTRY(qobject_to_qlist(data), bus) {
- QDict *qdict = qobject_to_qdict(qlist_entry_obj(bus));
- QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
- pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
- }
- }
+ return head;
}
-static QObject *pci_get_dev_class(const PCIDevice *dev)
+static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
+ int bus_num)
{
- int class;
- const pci_class_desc *desc;
+ PciBridgeInfo *info;
- class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
- desc = pci_class_descriptions;
- while (desc->desc && class != desc->class)
- desc++;
+ info = g_malloc0(sizeof(*info));
- if (desc->desc) {
- return qobject_from_jsonf("{ 'desc': %s, 'class': %d }",
- desc->desc, class);
- } else {
- return qobject_from_jsonf("{ 'class': %d }", class);
- }
-}
+ info->bus.number = dev->config[PCI_PRIMARY_BUS];
+ info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
+ info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
-static QObject *pci_get_dev_id(const PCIDevice *dev)
-{
- return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }",
- pci_get_word(dev->config + PCI_VENDOR_ID),
- pci_get_word(dev->config + PCI_DEVICE_ID));
-}
+ info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
+ info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
+ info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
-static QObject *pci_get_regions_list(const PCIDevice *dev)
-{
- int i;
- QList *regions_list;
-
- regions_list = qlist_new();
-
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- QObject *obj;
- const PCIIORegion *r = &dev->io_regions[i];
+ info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
+ info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
+ info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
- if (!r->size) {
- continue;
- }
+ info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range));
+ info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
+ info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
- if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
- obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "
- "'address': %" PRId64 ", "
- "'size': %" PRId64 " }",
- i, r->addr, r->size);
- } else {
- int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;
-
- obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', "
- "'mem_type_64': %i, 'prefetch': %i, "
- "'address': %" PRId64 ", "
- "'size': %" PRId64 " }",
- i, mem_type_64,
- r->type & PCI_BASE_ADDRESS_MEM_PREFETCH,
- r->addr, r->size);
+ if (dev->config[PCI_SECONDARY_BUS] != 0) {
+ PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
+ if (child_bus) {
+ info->has_devices = true;
+ info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]);
}
-
- qlist_append_obj(regions_list, obj);
}
- return QOBJECT(regions_list);
+ return info;
}
-static QObject *pci_get_devices_list(PCIBus *bus, int bus_num);
-
-static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num)
+static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
+ int bus_num)
{
+ const pci_class_desc *desc;
+ PciDeviceInfo *info;
uint8_t type;
- QObject *obj;
+ int class;
+
+ info = g_malloc0(sizeof(*info));
+ info->bus = bus_num;
+ info->slot = PCI_SLOT(dev->devfn);
+ info->function = PCI_FUNC(dev->devfn);
- obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d," "'class_info': %p, 'id': %p, 'regions': %p,"
- " 'qdev_id': %s }",
- bus_num,
- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
- pci_get_dev_class(dev), pci_get_dev_id(dev),
- pci_get_regions_list(dev),
- dev->qdev.id ? dev->qdev.id : "");
+ class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
+ info->class_info.class = class;
+ desc = get_class_desc(class);
+ if (desc->desc) {
+ info->class_info.has_desc = true;
+ info->class_info.desc = g_strdup(desc->desc);
+ }
+
+ info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
+ info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
+ info->regions = qmp_query_pci_regions(dev);
+ info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
if (dev->config[PCI_INTERRUPT_PIN] != 0) {
- QDict *qdict = qobject_to_qdict(obj);
- qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE]));
+ info->has_irq = true;
+ info->irq = dev->config[PCI_INTERRUPT_LINE];
}
type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
if (type == PCI_HEADER_TYPE_BRIDGE) {
- QDict *qdict;
- QObject *pci_bridge;
-
- pci_bridge = qobject_from_jsonf("{ 'bus': "
- "{ 'number': %d, 'secondary': %d, 'subordinate': %d }, "
- "'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
- "'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
- "'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }",
- dev->config[PCI_PRIMARY_BUS], dev->config[PCI_SECONDARY_BUS],
- dev->config[PCI_SUBORDINATE_BUS],
- pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO),
- pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO),
- pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
- pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
- pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_PREFETCH),
- pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_PREFETCH));
-
- if (dev->config[PCI_SECONDARY_BUS] != 0) {
- PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
-
- if (child_bus) {
- qdict = qobject_to_qdict(pci_bridge);
- qdict_put_obj(qdict, "devices",
- pci_get_devices_list(child_bus,
- dev->config[PCI_SECONDARY_BUS]));
- }
- }
- qdict = qobject_to_qdict(obj);
- qdict_put_obj(qdict, "pci_bridge", pci_bridge);
+ info->has_pci_bridge = true;
+ info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
}
- return obj;
+ return info;
}
-static QObject *pci_get_devices_list(PCIBus *bus, int bus_num)
+static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
{
- int devfn;
+ PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
PCIDevice *dev;
- QList *dev_list;
-
- dev_list = qlist_new();
+ int devfn;
for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
dev = bus->devices[devfn];
if (dev) {
- qlist_append_obj(dev_list, pci_get_dev_dict(dev, bus, bus_num));
+ info = g_malloc0(sizeof(*info));
+ info->value = qmp_query_pci_device(dev, bus, bus_num);
+
+ /* XXX: waiting for the qapi to support GSList */
+ if (!cur_item) {
+ head = cur_item = info;
+ } else {
+ cur_item->next = info;
+ cur_item = info;
+ }
}
}
- return QOBJECT(dev_list);
+ return head;
}
-static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num)
+static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
{
+ PciInfo *info = NULL;
+
bus = pci_find_bus(bus, bus_num);
if (bus) {
- return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",
- bus_num, pci_get_devices_list(bus, bus_num));
+ info = g_malloc0(sizeof(*info));
+ info->bus = bus_num;
+ info->devices = qmp_query_pci_devices(bus, bus_num);
}
- return NULL;
+ return info;
}
-void do_pci_info(Monitor *mon, QObject **ret_data)
+PciInfoList *qmp_query_pci(Error **errp)
{
- QList *bus_list;
+ PciInfoList *info, *head = NULL, *cur_item = NULL;
struct PCIHostBus *host;
- bus_list = qlist_new();
-
QLIST_FOREACH(host, &host_buses, next) {
- QObject *obj = pci_get_bus_dict(host->bus, 0);
- if (obj) {
- qlist_append_obj(bus_list, obj);
+ info = g_malloc0(sizeof(*info));
+ info->value = qmp_query_pci_bus(host->bus, 0);
+
+ /* XXX: waiting for the qapi to support GSList */
+ if (!cur_item) {
+ head = cur_item = info;
+ } else {
+ cur_item->next = info;
+ cur_item = info;
}
}
- *ret_data = QOBJECT(bus_list);
+ return head;
}
static const char * const pci_nic_models[] = {
diff --git a/hw/pci.h b/hw/pci.h
index 86a81c8..98f30f7 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -2,7 +2,6 @@
#define QEMU_PCI_H
#include "qemu-common.h"
-#include "qobject.h"
#include "qdev.h"
#include "memory.h"
@@ -271,9 +270,6 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp,
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
unsigned *slotp);
-void do_pci_info_print(Monitor *mon, const QObject *data);
-void do_pci_info(Monitor *mon, QObject **ret_data);
-
void pci_device_deassert_intx(PCIDevice *dev);
static inline void
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 5f8f4bd..e24a2bf 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -18,22 +18,14 @@
#include "virtio.h"
#include "pc.h"
#include "cpu.h"
-#include "monitor.h"
#include "balloon.h"
#include "virtio-balloon.h"
#include "kvm.h"
-#include "qlist.h"
-#include "qint.h"
-#include "qstring.h"
#if defined(__linux__)
#include <sys/mman.h>
#endif
-/* Disable guest-provided stats by now (https://bugzilla.redhat.com/show_bug.cgi?id=623903) */
-#define ENABLE_GUEST_STATS 0
-
-
typedef struct VirtIOBalloon
{
VirtIODevice vdev;
@@ -43,8 +35,6 @@ typedef struct VirtIOBalloon
uint64_t stats[VIRTIO_BALLOON_S_NR];
VirtQueueElement stats_vq_elem;
size_t stats_vq_offset;
- MonitorCompletion *stats_callback;
- void *stats_opaque_callback_data;
DeviceState *qdev;
} VirtIOBalloon;
@@ -76,31 +66,6 @@ static inline void reset_stats(VirtIOBalloon *dev)
for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
}
-static void stat_put(QDict *dict, const char *label, uint64_t val)
-{
- if (val != -1)
- qdict_put(dict, label, qint_from_int(val));
-}
-
-static QObject *get_stats_qobject(VirtIOBalloon *dev)
-{
- QDict *dict = qdict_new();
- uint64_t actual = ram_size - ((uint64_t) dev->actual <<
- VIRTIO_BALLOON_PFN_SHIFT);
-
- 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_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]);
- 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, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]);
- stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]);
-#endif
-
- return QOBJECT(dict);
-}
-
static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOBalloon *s = to_virtio_balloon(vdev);
@@ -131,20 +96,6 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
}
}
-static void complete_stats_request(VirtIOBalloon *vb)
-{
- QObject *stats;
-
- if (!vb->stats_opaque_callback_data)
- return;
-
- stats = get_stats_qobject(vb);
- vb->stats_callback(vb->stats_opaque_callback_data, stats);
- qobject_decref(stats);
- vb->stats_opaque_callback_data = NULL;
- vb->stats_callback = NULL;
-}
-
static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
@@ -172,8 +123,6 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
s->stats[tag] = val;
}
s->stats_vq_offset = offset;
-
- complete_stats_request(s);
}
static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
@@ -202,32 +151,33 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
return f;
}
-static void virtio_balloon_stat(void *opaque, MonitorCompletion cb,
- void *cb_data)
+static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
{
VirtIOBalloon *dev = opaque;
- /* For now, only allow one request at a time. This restriction can be
- * removed later by queueing callback and data pairs.
+#if 0
+ /* Disable guest-provided stats for now. For more details please check:
+ * https://bugzilla.redhat.com/show_bug.cgi?id=623903
+ *
+ * If you do enable it (which is probably not going to happen as we
+ * need a new command for it), remember that you also need to fill the
+ * appropriate members of the BalloonInfo structure so that the stats
+ * are returned to the client.
*/
- if (dev->stats_callback != NULL) {
- return;
- }
- dev->stats_callback = cb;
- dev->stats_opaque_callback_data = cb_data;
-
- if (ENABLE_GUEST_STATS
- && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
+ if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
virtio_notify(&dev->vdev, dev->svq);
return;
}
+#endif
/* Stats are not supported. Clear out any stale values that might
* have been set by a more featureful guest kernel.
*/
reset_stats(dev);
- complete_stats_request(dev);
+
+ info->actual = ram_size - ((uint64_t) dev->actual <<
+ VIRTIO_BALLOON_PFN_SHIFT);
}
static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
diff --git a/input.c b/input.c
index e2f7c92..9ade63f 100644
--- a/input.c
+++ b/input.c
@@ -26,7 +26,8 @@
#include "net.h"
#include "monitor.h"
#include "console.h"
-#include "qjson.h"
+#include "error.h"
+#include "qmp-commands.h"
static QEMUPutKBDEvent *qemu_put_kbd_event;
static void *qemu_put_kbd_event_opaque;
@@ -211,60 +212,27 @@ int kbd_mouse_has_absolute(void)
return 0;
}
-static void info_mice_iter(QObject *data, void *opaque)
-{
- QDict *mouse;
- Monitor *mon = opaque;
-
- mouse = qobject_to_qdict(data);
- monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
- (qdict_get_bool(mouse, "current") ? '*' : ' '),
- qdict_get_int(mouse, "index"), qdict_get_str(mouse, "name"),
- qdict_get_bool(mouse, "absolute") ? " (absolute)" : "");
-}
-
-void do_info_mice_print(Monitor *mon, const QObject *data)
-{
- QList *mice_list;
-
- mice_list = qobject_to_qlist(data);
- if (qlist_empty(mice_list)) {
- monitor_printf(mon, "No mouse devices connected\n");
- return;
- }
-
- qlist_iter(mice_list, info_mice_iter, mon);
-}
-
-void do_info_mice(Monitor *mon, QObject **ret_data)
+MouseInfoList *qmp_query_mice(Error **errp)
{
+ MouseInfoList *mice_list = NULL;
QEMUPutMouseEntry *cursor;
- QList *mice_list;
- int current;
-
- mice_list = qlist_new();
+ bool current = true;
- if (QTAILQ_EMPTY(&mouse_handlers)) {
- goto out;
- }
+ QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
+ MouseInfoList *info = g_malloc0(sizeof(*info));
+ info->value = g_malloc0(sizeof(*info->value));
+ info->value->name = g_strdup(cursor->qemu_put_mouse_event_name);
+ info->value->index = cursor->index;
+ info->value->absolute = !!cursor->qemu_put_mouse_event_absolute;
+ info->value->current = current;
- current = QTAILQ_FIRST(&mouse_handlers)->index;
+ current = false;
- QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
- QObject *obj;
- obj = qobject_from_jsonf("{ 'name': %s,"
- " 'index': %d,"
- " 'current': %i,"
- " 'absolute': %i }",
- cursor->qemu_put_mouse_event_name,
- cursor->index,
- cursor->index == current,
- !!cursor->qemu_put_mouse_event_absolute);
- qlist_append_obj(mice_list, obj);
+ info->next = mice_list;
+ mice_list = info;
}
-out:
- *ret_data = QOBJECT(mice_list);
+ return mice_list;
}
void do_mouse_set(Monitor *mon, const QDict *qdict)
diff --git a/migration.c b/migration.c
index d693567..3b4abbd 100644
--- a/migration.c
+++ b/migration.c
@@ -19,7 +19,7 @@
#include "block.h"
#include "qemu_socket.h"
#include "block-migration.h"
-#include "qemu-objects.h"
+#include "qmp-commands.h"
//#define DEBUG_MIGRATION
@@ -107,53 +107,9 @@ uint64_t migrate_max_downtime(void)
return max_downtime;
}
-static void migrate_print_status(Monitor *mon, const char *name,
- const QDict *status_dict)
+MigrationInfo *qmp_query_migrate(Error **errp)
{
- QDict *qdict;
-
- qdict = qobject_to_qdict(qdict_get(status_dict, name));
-
- monitor_printf(mon, "transferred %s: %" PRIu64 " kbytes\n", name,
- qdict_get_int(qdict, "transferred") >> 10);
- monitor_printf(mon, "remaining %s: %" PRIu64 " kbytes\n", name,
- qdict_get_int(qdict, "remaining") >> 10);
- monitor_printf(mon, "total %s: %" PRIu64 " kbytes\n", name,
- qdict_get_int(qdict, "total") >> 10);
-}
-
-void do_info_migrate_print(Monitor *mon, const QObject *data)
-{
- QDict *qdict;
-
- qdict = qobject_to_qdict(data);
-
- monitor_printf(mon, "Migration status: %s\n",
- qdict_get_str(qdict, "status"));
-
- if (qdict_haskey(qdict, "ram")) {
- migrate_print_status(mon, "ram", qdict);
- }
-
- if (qdict_haskey(qdict, "disk")) {
- migrate_print_status(mon, "disk", qdict);
- }
-}
-
-static void migrate_put_status(QDict *qdict, const char *name,
- uint64_t trans, uint64_t rem, uint64_t total)
-{
- QObject *obj;
-
- obj = qobject_from_jsonf("{ 'transferred': %" PRId64 ", "
- "'remaining': %" PRId64 ", "
- "'total': %" PRId64 " }", trans, rem, total);
- qdict_put_obj(qdict, name, obj);
-}
-
-void do_info_migrate(Monitor *mon, QObject **ret_data)
-{
- QDict *qdict;
+ MigrationInfo *info = g_malloc0(sizeof(*info));
MigrationState *s = migrate_get_current();
switch (s->state) {
@@ -161,30 +117,38 @@ void do_info_migrate(Monitor *mon, QObject **ret_data)
/* no migration has happened ever */
break;
case MIG_STATE_ACTIVE:
- qdict = qdict_new();
- qdict_put(qdict, "status", qstring_from_str("active"));
+ info->has_status = true;
+ info->status = g_strdup("active");
- migrate_put_status(qdict, "ram", ram_bytes_transferred(),
- ram_bytes_remaining(), ram_bytes_total());
+ info->has_ram = true;
+ info->ram = g_malloc0(sizeof(*info->ram));
+ info->ram->transferred = ram_bytes_transferred();
+ info->ram->remaining = ram_bytes_remaining();
+ info->ram->total = ram_bytes_total();
if (blk_mig_active()) {
- migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
- blk_mig_bytes_remaining(),
- blk_mig_bytes_total());
+ info->has_disk = true;
+ info->disk = g_malloc0(sizeof(*info->disk));
+ info->disk->transferred = blk_mig_bytes_transferred();
+ info->disk->remaining = blk_mig_bytes_remaining();
+ info->disk->total = blk_mig_bytes_total();
}
-
- *ret_data = QOBJECT(qdict);
break;
case MIG_STATE_COMPLETED:
- *ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
+ info->has_status = true;
+ info->status = g_strdup("completed");
break;
case MIG_STATE_ERROR:
- *ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
+ info->has_status = true;
+ info->status = g_strdup("failed");
break;
case MIG_STATE_CANCELLED:
- *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
+ info->has_status = true;
+ info->status = g_strdup("cancelled");
break;
}
+
+ return info;
}
/* shared migration helpers */
diff --git a/monitor.c b/monitor.c
index ee53f7f..7c2a9b9 100644
--- a/monitor.c
+++ b/monitor.c
@@ -123,8 +123,6 @@ typedef struct mon_cmd_t {
void (*user_print)(Monitor *mon, const QObject *data);
union {
void (*info)(Monitor *mon);
- void (*info_new)(Monitor *mon, QObject **ret_data);
- int (*info_async)(Monitor *mon, MonitorCompletion *cb, void *opaque);
void (*cmd)(Monitor *mon, const QDict *qdict);
int (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
int (*cmd_async)(Monitor *mon, const QDict *params,
@@ -205,7 +203,6 @@ 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;
@@ -514,7 +511,6 @@ static int do_qmp_capabilities(Monitor *mon, const QDict *params,
return 0;
}
-static int mon_set_cpu(int cpu_index);
static void handle_user_command(Monitor *mon, const char *cmdline);
static int do_hmp_passthrough(Monitor *mon, const QDict *params,
@@ -532,7 +528,7 @@ static int do_hmp_passthrough(Monitor *mon, const QDict *params,
cur_mon = &hmp;
if (qdict_haskey(params, "cpu-index")) {
- ret = mon_set_cpu(qdict_get_int(params, "cpu-index"));
+ ret = monitor_set_cpu(qdict_get_int(params, "cpu-index"));
if (ret < 0) {
cur_mon = old_mon;
qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number");
@@ -664,11 +660,6 @@ static int qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
return cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
}
-static void qmp_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
-{
- cmd->mhandler.info_async(mon, qmp_monitor_complete, mon);
-}
-
static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
const QDict *params)
{
@@ -686,21 +677,6 @@ static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
}
}
-static void user_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
-{
- int ret;
-
- MonitorCompletionData *cb_data = g_malloc(sizeof(*cb_data));
- cb_data->mon = mon;
- cb_data->user_print = cmd->user_print;
- monitor_suspend(mon);
- ret = cmd->mhandler.info_async(mon, user_monitor_complete, cb_data);
- if (ret < 0) {
- monitor_resume(mon);
- g_free(cb_data);
- }
-}
-
static void do_info(Monitor *mon, const QDict *qdict)
{
const mon_cmd_t *cmd;
@@ -719,52 +695,23 @@ static void do_info(Monitor *mon, const QDict *qdict)
goto help;
}
- if (handler_is_async(cmd)) {
- user_async_info_handler(mon, cmd);
- } else if (handler_is_qobject(cmd)) {
- QObject *info_data = NULL;
-
- cmd->mhandler.info_new(mon, &info_data);
- if (info_data) {
- cmd->user_print(mon, info_data);
- qobject_decref(info_data);
- }
- } else {
- cmd->mhandler.info(mon);
- }
-
+ cmd->mhandler.info(mon);
return;
help:
help_cmd(mon, "info");
}
-static CommandInfoList *alloc_cmd_entry(const char *cmd_name)
-{
- CommandInfoList *info;
-
- info = g_malloc0(sizeof(*info));
- info->value = g_malloc0(sizeof(*info->value));
- info->value->name = g_strdup(cmd_name);
-
- return info;
-}
-
CommandInfoList *qmp_query_commands(Error **errp)
{
CommandInfoList *info, *cmd_list = NULL;
const mon_cmd_t *cmd;
for (cmd = qmp_cmds; cmd->name != NULL; cmd++) {
- info = alloc_cmd_entry(cmd->name);
- info->next = cmd_list;
- cmd_list = info;
- }
+ info = g_malloc0(sizeof(*info));
+ info->value = g_malloc0(sizeof(*info->value));
+ info->value->name = g_strdup(cmd->name);
- for (cmd = qmp_query_cmds; cmd->name != NULL; cmd++) {
- char buf[128];
- snprintf(buf, sizeof(buf), "query-%s", cmd->name);
- info = alloc_cmd_entry(buf);
info->next = cmd_list;
cmd_list = info;
}
@@ -772,8 +719,8 @@ CommandInfoList *qmp_query_commands(Error **errp)
return cmd_list;
}
-/* get the current CPU defined by the user */
-static int mon_set_cpu(int cpu_index)
+/* set the current CPU defined by the user */
+int monitor_set_cpu(int cpu_index)
{
CPUState *env;
@@ -789,12 +736,17 @@ static int mon_set_cpu(int cpu_index)
static CPUState *mon_get_cpu(void)
{
if (!cur_mon->mon_cpu) {
- mon_set_cpu(0);
+ monitor_set_cpu(0);
}
cpu_synchronize_state(cur_mon->mon_cpu);
return cur_mon->mon_cpu;
}
+int monitor_get_cpu_index(void)
+{
+ return mon_get_cpu()->cpu_index;
+}
+
static void do_info_registers(Monitor *mon)
{
CPUState *env;
@@ -808,107 +760,6 @@ static void do_info_registers(Monitor *mon)
#endif
}
-static void print_cpu_iter(QObject *obj, void *opaque)
-{
- QDict *cpu;
- int active = ' ';
- Monitor *mon = opaque;
-
- assert(qobject_type(obj) == QTYPE_QDICT);
- cpu = qobject_to_qdict(obj);
-
- if (qdict_get_bool(cpu, "current")) {
- active = '*';
- }
-
- monitor_printf(mon, "%c CPU #%d: ", active, (int)qdict_get_int(cpu, "CPU"));
-
-#if defined(TARGET_I386)
- monitor_printf(mon, "pc=0x" TARGET_FMT_lx,
- (target_ulong) qdict_get_int(cpu, "pc"));
-#elif defined(TARGET_PPC)
- monitor_printf(mon, "nip=0x" TARGET_FMT_lx,
- (target_long) qdict_get_int(cpu, "nip"));
-#elif defined(TARGET_SPARC)
- monitor_printf(mon, "pc=0x" TARGET_FMT_lx,
- (target_long) qdict_get_int(cpu, "pc"));
- monitor_printf(mon, "npc=0x" TARGET_FMT_lx,
- (target_long) qdict_get_int(cpu, "npc"));
-#elif defined(TARGET_MIPS)
- monitor_printf(mon, "PC=0x" TARGET_FMT_lx,
- (target_long) qdict_get_int(cpu, "PC"));
-#endif
-
- if (qdict_get_bool(cpu, "halted")) {
- monitor_printf(mon, " (halted)");
- }
-
- monitor_printf(mon, " thread_id=%" PRId64 " ",
- qdict_get_int(cpu, "thread_id"));
-
- monitor_printf(mon, "\n");
-}
-
-static void monitor_print_cpus(Monitor *mon, const QObject *data)
-{
- QList *cpu_list;
-
- assert(qobject_type(data) == QTYPE_QLIST);
- cpu_list = qobject_to_qlist(data);
- qlist_iter(cpu_list, print_cpu_iter, mon);
-}
-
-static void do_info_cpus(Monitor *mon, QObject **ret_data)
-{
- CPUState *env;
- QList *cpu_list;
-
- cpu_list = qlist_new();
-
- /* just to set the default cpu if not already done */
- mon_get_cpu();
-
- for(env = first_cpu; env != NULL; env = env->next_cpu) {
- QDict *cpu;
- QObject *obj;
-
- cpu_synchronize_state(env);
-
- obj = qobject_from_jsonf("{ 'CPU': %d, 'current': %i, 'halted': %i }",
- env->cpu_index, env == mon->mon_cpu,
- env->halted);
-
- cpu = qobject_to_qdict(obj);
-
-#if defined(TARGET_I386)
- qdict_put(cpu, "pc", qint_from_int(env->eip + env->segs[R_CS].base));
-#elif defined(TARGET_PPC)
- qdict_put(cpu, "nip", qint_from_int(env->nip));
-#elif defined(TARGET_SPARC)
- qdict_put(cpu, "pc", qint_from_int(env->pc));
- qdict_put(cpu, "npc", qint_from_int(env->npc));
-#elif defined(TARGET_MIPS)
- qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC));
-#endif
- qdict_put(cpu, "thread_id", qint_from_int(env->thread_id));
-
- qlist_append(cpu_list, cpu);
- }
-
- *ret_data = QOBJECT(cpu_list);
-}
-
-static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- int index = qdict_get_int(qdict, "index");
- if (mon_set_cpu(index) < 0) {
- qerror_report(QERR_INVALID_PARAMETER_VALUE, "index",
- "a CPU number");
- return -1;
- }
- return 0;
-}
-
static void do_info_jit(Monitor *mon)
{
dump_exec_info((FILE *)mon, monitor_fprintf);
@@ -2773,16 +2624,14 @@ static const mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show the block devices",
- .user_print = bdrv_info_print,
- .mhandler.info_new = bdrv_info,
+ .mhandler.info = hmp_info_block,
},
{
.name = "blockstats",
.args_type = "",
.params = "",
.help = "show block device statistics",
- .user_print = bdrv_stats_print,
- .mhandler.info_new = bdrv_info_stats,
+ .mhandler.info = hmp_info_blockstats,
},
{
.name = "registers",
@@ -2796,8 +2645,7 @@ static const mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show infos for each CPU",
- .user_print = monitor_print_cpus,
- .mhandler.info_new = do_info_cpus,
+ .mhandler.info = hmp_info_cpus,
},
{
.name = "history",
@@ -2840,8 +2688,7 @@ static const mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show PCI info",
- .user_print = do_pci_info_print,
- .mhandler.info_new = do_pci_info,
+ .mhandler.info = hmp_info_pci,
},
#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
defined(TARGET_PPC)
@@ -2944,16 +2791,14 @@ static const mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show which guest mouse is receiving events",
- .user_print = do_info_mice_print,
- .mhandler.info_new = do_info_mice,
+ .mhandler.info = hmp_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,
+ .mhandler.info = hmp_info_vnc,
},
#if defined(CONFIG_SPICE)
{
@@ -2961,8 +2806,7 @@ static const mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show the spice server status",
- .user_print = do_info_spice_print,
- .mhandler.info_new = do_info_spice,
+ .mhandler.info = hmp_info_spice,
},
#endif
{
@@ -3002,17 +2846,14 @@ static const mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show migration status",
- .user_print = do_info_migrate_print,
- .mhandler.info_new = do_info_migrate,
+ .mhandler.info = hmp_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,
+ .mhandler.info = hmp_info_balloon,
},
{
.name = "qtree",
@@ -3061,85 +2902,6 @@ static const mon_cmd_t qmp_cmds[] = {
{ /* NULL */ },
};
-static const mon_cmd_t qmp_query_cmds[] = {
- {
- .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 = "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,
- },
-#if defined(CONFIG_SPICE)
- {
- .name = "spice",
- .args_type = "",
- .params = "",
- .help = "show the spice server status",
- .user_print = do_info_spice_print,
- .mhandler.info_new = do_info_spice,
- },
-#endif
- {
- .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;
@@ -3934,11 +3696,6 @@ 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);
@@ -4862,22 +4619,6 @@ 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);
- 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)
{
@@ -4898,10 +4639,9 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
QObject *obj;
QDict *input, *args;
const mon_cmd_t *cmd;
+ const char *cmd_name;
Monitor *mon = cur_mon;
- const char *cmd_name, *query_cmd;
- query_cmd = NULL;
args = input = NULL;
obj = json_parser_parse(tokens, NULL);
@@ -4928,9 +4668,6 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
}
cmd = qmp_find_cmd(cmd_name);
- if (!cmd && strstart(cmd_name, "query-", &query_cmd)) {
- cmd = qmp_find_query_cmd(query_cmd);
- }
if (!cmd) {
qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
goto err_out;
@@ -4949,9 +4686,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
goto err_out;
}
- if (query_cmd) {
- qmp_call_query_cmd(mon, cmd);
- } else if (handler_is_async(cmd)) {
+ if (handler_is_async(cmd)) {
err = qmp_async_cmd_handler(mon, cmd, args);
if (err) {
/* emit the error response */
diff --git a/monitor.h b/monitor.h
index 4f2d328..e76795f 100644
--- a/monitor.h
+++ b/monitor.h
@@ -57,6 +57,8 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
void monitor_printf(Monitor *mon, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
void monitor_print_filename(Monitor *mon, const char *filename);
void monitor_flush(Monitor *mon);
+int monitor_set_cpu(int cpu_index);
+int monitor_get_cpu_index(void);
typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
diff --git a/qapi-schema.json b/qapi-schema.json
index 5922c4a..cb1ba77 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -226,6 +226,611 @@
{ 'command': 'query-commands', 'returns': ['CommandInfo'] }
##
+# @MigrationStats
+#
+# Detailed migration status.
+#
+# @transferred: amount of bytes already transferred to the target VM
+#
+# @remaining: amount of bytes remaining to be transferred to the target VM
+#
+# @total: total amount of bytes involved in the migration process
+#
+# Since: 0.14.0.
+##
+{ 'type': 'MigrationStats',
+ 'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' } }
+
+##
+# @MigrationInfo
+#
+# Information about current migration process.
+#
+# @status: #optional string describing the current migration status.
+# As of 0.14.0 this can be 'active', 'completed', 'failed' or
+# 'cancelled'. If this field is not returned, no migration process
+# has been initiated
+#
+# @ram: #optional @MigrationStats containing detailed migration status,
+# only returned if status is 'active'
+#
+# @disk: #optional @MigrationStats containing detailed disk migration
+# status, only returned if status is 'active' and it is a block
+# migration
+#
+# Since: 0.14.0
+##
+{ 'type': 'MigrationInfo',
+ 'data': {'*status': 'str', '*ram': 'MigrationStats',
+ '*disk': 'MigrationStats'} }
+
+##
+# @query-migrate
+#
+# Returns information about current migration process.
+#
+# Returns: @MigrationInfo
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-migrate', 'returns': 'MigrationInfo' }
+
+##
+# @MouseInfo:
+#
+# Information about a mouse device.
+#
+# @name: the name of the mouse device
+#
+# @index: the index of the mouse device
+#
+# @current: true if this device is currently receiving mouse events
+#
+# @absolute: true if this device supports absolute coordinates as input
+#
+# Since: 0.14.0
+##
+{ 'type': 'MouseInfo',
+ 'data': {'name': 'str', 'index': 'int', 'current': 'bool',
+ 'absolute': 'bool'} }
+
+##
+# @query-mice:
+#
+# Returns information about each active mouse device
+#
+# Returns: a list of @MouseInfo for each device
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-mice', 'returns': ['MouseInfo'] }
+
+##
+# @CpuInfo:
+#
+# Information about a virtual CPU
+#
+# @CPU: the index of the virtual CPU
+#
+# @current: this only exists for backwards compatible and should be ignored
+#
+# @halted: true if the virtual CPU is in the halt state. Halt usually refers
+# to a processor specific low power mode.
+#
+# @pc: #optional If the target is i386 or x86_64, this is the 64-bit instruction
+# pointer.
+# If the target is Sparc, this is the PC component of the
+# instruction pointer.
+#
+# @nip: #optional If the target is PPC, the instruction pointer
+#
+# @npc: #optional If the target is Sparc, the NPC component of the instruction
+# pointer
+#
+# @PC: #optional If the target is MIPS, the instruction pointer
+#
+# @thread_id: ID of the underlying host thread
+#
+# Since: 0.14.0
+#
+# Notes: @halted is a transient state that changes frequently. By the time the
+# data is sent to the client, the guest may no longer be halted.
+##
+{ 'type': 'CpuInfo',
+ 'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool', '*pc': 'int',
+ '*nip': 'int', '*npc': 'int', '*PC': 'int', 'thread_id': 'int'} }
+
+##
+# @query-cpus:
+#
+# Returns a list of information about each virtual CPU.
+#
+# Returns: a list of @CpuInfo for each virtual CPU
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-cpus', 'returns': ['CpuInfo'] }
+
+##
+# @BlockDeviceInfo:
+#
+# Information about the backing device for a block device.
+#
+# @file: the filename of the backing device
+#
+# @ro: true if the backing device was open read-only
+#
+# @drv: the name of the block format used to open the backing device. As of
+# 0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg',
+# 'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
+# 'host_floppy', 'http', 'https', 'nbd', 'parallels', 'qcow',
+# 'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat'
+#
+# @backing_file: #optional the name of the backing file (for copy-on-write)
+#
+# @encrypted: true if the backing device is encrypted
+#
+# Since: 0.14.0
+#
+# Notes: This interface is only found in @BlockInfo.
+##
+{ 'type': 'BlockDeviceInfo',
+ 'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
+ '*backing_file': 'str', 'encrypted': 'bool' } }
+
+##
+# @BlockDeviceIoStatus:
+#
+# An enumeration of block device I/O status.
+#
+# @ok: The last I/O operation has succeeded
+#
+# @failed: The last I/O operation has failed
+#
+# @nospace: The last I/O operation has failed due to a no-space condition
+#
+# Since: 1.0
+##
+{ 'enum': 'BlockDeviceIoStatus', 'data': [ 'ok', 'failed', 'nospace' ] }
+
+##
+# @BlockInfo:
+#
+# Block device information. This structure describes a virtual device and
+# the backing device associated with it.
+#
+# @device: The device name associated with the virtual device.
+#
+# @type: This field is returned only for compatibility reasons, it should
+# not be used (always returns 'unknown')
+#
+# @removable: True if the device supports removable media.
+#
+# @locked: True if the guest has locked this device from having its media
+# removed
+#
+# @tray_open: #optional True if the device has a tray and it is open
+# (only present if removable is true)
+#
+# @io-status: #optional @BlockDeviceIoStatus. Only present if the device
+# supports it and the VM is configured to stop on errors
+#
+# @inserted: #optional @BlockDeviceInfo describing the device if media is
+# present
+#
+# Since: 0.14.0
+##
+{ 'type': 'BlockInfo',
+ 'data': {'device': 'str', 'type': 'str', 'removable': 'bool',
+ 'locked': 'bool', '*inserted': 'BlockDeviceInfo',
+ '*tray_open': 'bool', '*io-status': 'BlockDeviceIoStatus'} }
+
+##
+# @query-block:
+#
+# Get a list of BlockInfo for all virtual block devices.
+#
+# Returns: a list of @BlockInfo describing each virtual block device
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-block', 'returns': ['BlockInfo'] }
+
+##
+# @BlockDeviceStats:
+#
+# Statistics of a virtual block device or a block backing device.
+#
+# @rd_bytes: The number of bytes read by the device.
+#
+# @wr_bytes: The number of bytes written by the device.
+#
+# @rd_operations: The number of read operations performed by the device.
+#
+# @wr_operations: The number of write operations performed by the device.
+#
+# @flush_operations: The number of cache flush operations performed by the
+# device (since 0.15.0)
+#
+# @flush_total_time_ns: Total time spend on cache flushes in nano-seconds
+# (since 0.15.0).
+#
+# @wr_total_time_ns: Total time spend on writes in nano-seconds (since 0.15.0).
+#
+# @rd_total_time_ns: Total_time_spend on reads in nano-seconds (since 0.15.0).
+#
+# @wr_highest_offset: The offset after the greatest byte written to the
+# device. The intended use of this information is for
+# growable sparse files (like qcow2) that are used on top
+# of a physical device.
+#
+# Since: 0.14.0
+##
+{ 'type': 'BlockDeviceStats',
+ 'data': {'rd_bytes': 'int', 'wr_bytes': 'int', 'rd_operations': 'int',
+ 'wr_operations': 'int', 'flush_operations': 'int',
+ 'flush_total_time_ns': 'int', 'wr_total_time_ns': 'int',
+ 'rd_total_time_ns': 'int', 'wr_highest_offset': 'int' } }
+
+##
+# @BlockStats:
+#
+# Statistics of a virtual block device or a block backing device.
+#
+# @device: #optional If the stats are for a virtual block device, the name
+# corresponding to the virtual block device.
+#
+# @stats: A @BlockDeviceStats for the device.
+#
+# @parent: #optional This may point to the backing block device if this is a
+# a virtual block device. If it's a backing block, this will point
+# to the backing file is one is present.
+#
+# Since: 0.14.0
+##
+{ 'type': 'BlockStats',
+ 'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
+ '*parent': 'BlockStats'} }
+
+##
+# @query-blockstats:
+#
+# Query the @BlockStats for all virtual block devices.
+#
+# Returns: A list of @BlockStats for each virtual block devices.
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-blockstats', 'returns': ['BlockStats'] }
+
+##
+# @VncClientInfo:
+#
+# Information about a connected VNC client.
+#
+# @host: The host name of the client. QEMU tries to resolve this to a DNS name
+# when possible.
+#
+# @family: 'ipv6' if the client is connected via IPv6 and TCP
+# 'ipv4' if the client is connected via IPv4 and TCP
+# 'unix' if the client is connected via a unix domain socket
+# 'unknown' otherwise
+#
+# @service: The service name of the client's port. This may depends on the
+# host system's service database so symbolic names should not be
+# relied on.
+#
+# @x509_dname: #optional If x509 authentication is in use, the Distinguished
+# Name of the client.
+#
+# @sasl_username: #optional If SASL authentication is in use, the SASL username
+# used for authentication.
+#
+# Since: 0.14.0
+##
+{ 'type': 'VncClientInfo',
+ 'data': {'host': 'str', 'family': 'str', 'service': 'str',
+ '*x509_dname': 'str', '*sasl_username': 'str'} }
+
+##
+# @VncInfo:
+#
+# Information about the VNC session.
+#
+# @enabled: true if the VNC server is enabled, false otherwise
+#
+# @host: #optional The hostname the VNC server is bound to. This depends on
+# the name resolution on the host and may be an IP address.
+#
+# @family: #optional 'ipv6' if the host is listening for IPv6 connections
+# 'ipv4' if the host is listening for IPv4 connections
+# 'unix' if the host is listening on a unix domain socket
+# 'unknown' otherwise
+#
+# @service: #optional The service name of the server's port. This may depends
+# on the host system's service database so symbolic names should not
+# be relied on.
+#
+# @auth: #optional the current authentication type used by the server
+# 'none' if no authentication is being used
+# 'vnc' if VNC authentication is being used
+# 'vencrypt+plain' if VEncrypt is used with plain text authentication
+# 'vencrypt+tls+none' if VEncrypt is used with TLS and no authentication
+# 'vencrypt+tls+vnc' if VEncrypt is used with TLS and VNC authentication
+# 'vencrypt+tls+plain' if VEncrypt is used with TLS and plain text auth
+# 'vencrypt+x509+none' if VEncrypt is used with x509 and no auth
+# 'vencrypt+x509+vnc' if VEncrypt is used with x509 and VNC auth
+# 'vencrypt+x509+plain' if VEncrypt is used with x509 and plain text auth
+# 'vencrypt+tls+sasl' if VEncrypt is used with TLS and SASL auth
+# 'vencrypt+x509+sasl' if VEncrypt is used with x509 and SASL auth
+#
+# @clients: a list of @VncClientInfo of all currently connected clients
+#
+# Since: 0.14.0
+##
+{ 'type': 'VncInfo',
+ 'data': {'enabled': 'bool', '*host': 'str', '*family': 'str',
+ '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
+
+##
+# @query-vnc:
+#
+# Returns information about the current VNC server
+#
+# Returns: @VncInfo
+# If VNC support is not compiled in, FeatureDisabled
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-vnc', 'returns': 'VncInfo' }
+
+##
+# @SpiceChannel
+#
+# Information about a SPICE client channel.
+#
+# @host: The host name of the client. QEMU tries to resolve this to a DNS name
+# when possible.
+#
+# @family: 'ipv6' if the client is connected via IPv6 and TCP
+# 'ipv4' if the client is connected via IPv4 and TCP
+# 'unix' if the client is connected via a unix domain socket
+# 'unknown' otherwise
+#
+# @port: The client's port number.
+#
+# @connection-id: SPICE connection id number. All channels with the same id
+# belong to the same SPICE session.
+#
+# @connection-type: SPICE channel type number. "1" is the main control channel,
+# filter for this one if you want track spice sessions only
+#
+# @channel-id: SPICE channel ID number. Usually "0", might be different needed
+# when multiple channels of the same type exist, such as multiple
+# display channels in a multihead setup
+#
+# @tls: true if the channel is encrypted, false otherwise.
+#
+# Since: 0.14.0
+##
+{ 'type': 'SpiceChannel',
+ 'data': {'host': 'str', 'family': 'str', 'port': 'str',
+ 'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
+ 'tls': 'bool'} }
+
+##
+# @SpiceInfo
+#
+# Information about the SPICE session.
+#
+# @enabled: true if the SPICE server is enabled, false otherwise
+#
+# @host: #optional The hostname the SPICE server is bound to. This depends on
+# the name resolution on the host and may be an IP address.
+#
+# @port: #optional The SPICE server's port number.
+#
+# @compiled-version: #optional SPICE server version.
+#
+# @tls-port: #optional The SPICE server's TLS port number.
+#
+# @auth: #optional the current authentication type used by the server
+# 'none' if no authentication is being used
+# 'spice' (TODO: describe)
+#
+# @channels: a list of @SpiceChannel for each active spice channel
+#
+# Since: 0.14.0
+##
+{ 'type': 'SpiceInfo',
+ 'data': {'enabled': 'bool', '*host': 'str', '*port': 'int',
+ '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
+ '*channels': ['SpiceChannel']} }
+
+##
+# @query-spice
+#
+# Returns information about the current SPICE server
+#
+# Returns: @SpiceInfo
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-spice', 'returns': 'SpiceInfo' }
+
+##
+# @BalloonInfo:
+#
+# Information about the guest balloon device.
+#
+# @actual: the number of bytes the balloon currently contains
+#
+# @mem_swapped_in: #optional number of pages swapped in within the guest
+#
+# @mem_swapped_out: #optional number of pages swapped out within the guest
+#
+# @major_page_faults: #optional number of major page faults within the guest
+#
+# @minor_page_faults: #optional number of minor page faults within the guest
+#
+# @free_mem: #optional amount of memory (in bytes) free in the guest
+#
+# @total_mem: #optional amount of memory (in bytes) visible to the guest
+#
+# Since: 0.14.0
+#
+# Notes: all current versions of QEMU do not fill out optional information in
+# this structure.
+##
+{ 'type': 'BalloonInfo',
+ 'data': {'actual': 'int', '*mem_swapped_in': 'int',
+ '*mem_swapped_out': 'int', '*major_page_faults': 'int',
+ '*minor_page_faults': 'int', '*free_mem': 'int',
+ '*total_mem': 'int'} }
+
+##
+# @query-balloon:
+#
+# Return information about the balloon device.
+#
+# Returns: @BalloonInfo on success
+# If the balloon driver is enabled but not functional because the KVM
+# kernel module cannot support it, KvmMissingCap
+# If no balloon device is present, DeviceNotActive
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-balloon', 'returns': 'BalloonInfo' }
+
+##
+# @PciMemoryRange:
+#
+# A PCI device memory region
+#
+# @base: the starting address (guest physical)
+#
+# @limit: the ending address (guest physical)
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
+
+##
+# @PciMemoryRegion
+#
+# Information about a PCI device I/O region.
+#
+# @bar: the index of the Base Address Register for this region
+#
+# @type: 'io' if the region is a PIO region
+# 'memory' if the region is a MMIO region
+#
+# @prefetch: #optional if @type is 'memory', true if the memory is prefetchable
+#
+# @mem_type_64: #optional if @type is 'memory', true if the BAR is 64-bit
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciMemoryRegion',
+ 'data': {'bar': 'int', 'type': 'str', 'address': 'int', 'size': 'int',
+ '*prefetch': 'bool', '*mem_type_64': 'bool' } }
+
+##
+# @PciBridgeInfo:
+#
+# Information about a PCI Bridge device
+#
+# @bus.number: primary bus interface number. This should be the number of the
+# bus the device resides on.
+#
+# @bus.secondary: secondary bus interface number. This is the number of the
+# main bus for the bridge
+#
+# @bus.subordinate: This is the highest number bus that resides below the
+# bridge.
+#
+# @bus.io_range: The PIO range for all devices on this bridge
+#
+# @bus.memory_range: The MMIO range for all devices on this bridge
+#
+# @bus.prefetchable_range: The range of prefetchable MMIO for all devices on
+# this bridge
+#
+# @devices: a list of @PciDeviceInfo for each device on this bridge
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciBridgeInfo',
+ 'data': {'bus': { 'number': 'int', 'secondary': 'int', 'subordinate': 'int',
+ 'io_range': 'PciMemoryRange',
+ 'memory_range': 'PciMemoryRange',
+ 'prefetchable_range': 'PciMemoryRange' },
+ '*devices': ['PciDeviceInfo']} }
+
+##
+# @PciDeviceInfo:
+#
+# Information about a PCI device
+#
+# @bus: the bus number of the device
+#
+# @slot: the slot the device is located in
+#
+# @function: the function of the slot used by the device
+#
+# @class_info.desc: #optional a string description of the device's class
+#
+# @class_info.class: the class code of the device
+#
+# @id.device: the PCI device id
+#
+# @id.vendor: the PCI vendor id
+#
+# @irq: #optional if an IRQ is assigned to the device, the IRQ number
+#
+# @qdev_id: the device name of the PCI device
+#
+# @pci_bridge: if the device is a PCI bridge, the bridge information
+#
+# @regions: a list of the PCI I/O regions associated with the device
+#
+# Notes: the contents of @class_info.desc are not stable and should only be
+# treated as informational.
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciDeviceInfo',
+ 'data': {'bus': 'int', 'slot': 'int', 'function': 'int',
+ 'class_info': {'*desc': 'str', 'class': 'int'},
+ 'id': {'device': 'int', 'vendor': 'int'},
+ '*irq': 'int', 'qdev_id': 'str', '*pci_bridge': 'PciBridgeInfo',
+ 'regions': ['PciMemoryRegion']} }
+
+##
+# @PciInfo:
+#
+# Information about a PCI bus
+#
+# @bus: the bus index
+#
+# @devices: a list of devices on this bus
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
+
+##
+# @query-pci:
+#
+# Return information about the PCI bus topology of the guest.
+#
+# Returns: a list of @PciInfo for each PCI bus
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-pci', 'returns': ['PciInfo'] }
+
+##
# @quit:
#
# This command will cause the QEMU process to exit gracefully. While every
@@ -271,3 +876,14 @@
# prompting the user in some way.
##
{ 'command': 'system_powerdown' }
+
+##
+# @cpu:
+#
+# This command is a nop that is only provided for the purposes of compatibility.
+#
+# Since: 0.14.0
+#
+# Notes: Do not use this command.
+##
+{ 'command': 'cpu', 'data': {'index': 'int'} }
diff --git a/qerror.c b/qerror.c
index 68998d4..4b48b39 100644
--- a/qerror.c
+++ b/qerror.c
@@ -117,6 +117,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "No file descriptor supplied via SCM_RIGHTS",
},
{
+ .error_fmt = QERR_FEATURE_DISABLED,
+ .desc = "The feature '%(name)' is not enabled",
+ },
+ {
.error_fmt = QERR_INVALID_BLOCK_FORMAT,
.desc = "Invalid block format '%(name)'",
},
diff --git a/qmp-commands.hx b/qmp-commands.hx
index cb60d0c..97975a5 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -331,10 +331,7 @@ EQMP
{
.name = "cpu",
.args_type = "index:i",
- .params = "index",
- .help = "set the default CPU",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_cpu_set,
+ .mhandler.cmd_new = qmp_marshal_input_cpu,
},
SQMP
@@ -1202,6 +1199,12 @@ Example:
EQMP
+ {
+ .name = "query-block",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_block,
+ },
+
SQMP
query-blockstats
----------------
@@ -1309,6 +1312,12 @@ Example:
EQMP
+ {
+ .name = "query-blockstats",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_blockstats,
+ },
+
SQMP
query-cpus
----------
@@ -1351,6 +1360,12 @@ Example:
EQMP
+ {
+ .name = "query-cpus",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_cpus,
+ },
+
SQMP
query-pci
---------
@@ -1562,6 +1577,12 @@ Note: This example has been shortened as the real response is too long.
EQMP
+ {
+ .name = "query-pci",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_pci,
+ },
+
SQMP
query-kvm
---------
@@ -1664,6 +1685,12 @@ Example:
EQMP
+ {
+ .name = "query-mice",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_mice,
+ },
+
SQMP
query-vnc
---------
@@ -1721,6 +1748,12 @@ Example:
EQMP
+ {
+ .name = "query-vnc",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_vnc,
+ },
+
SQMP
query-spice
-----------
@@ -1791,6 +1824,14 @@ Example:
EQMP
+#if defined(CONFIG_SPICE)
+ {
+ .name = "query-spice",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_spice,
+ },
+#endif
+
SQMP
query-name
----------
@@ -1914,6 +1955,12 @@ Examples:
EQMP
+ {
+ .name = "query-migrate",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_migrate,
+ },
+
SQMP
query-balloon
-------------
@@ -1949,3 +1996,8 @@ Example:
EQMP
+ {
+ .name = "query-balloon",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_balloon,
+ },
diff --git a/qmp.c b/qmp.c
index bf58b05..511dd62 100644
--- a/qmp.c
+++ b/qmp.c
@@ -90,3 +90,30 @@ void qmp_system_powerdown(Error **erp)
{
qemu_system_powerdown_request();
}
+
+void qmp_cpu(int64_t index, Error **errp)
+{
+ /* Just do nothing */
+}
+
+#ifndef CONFIG_VNC
+/* If VNC support is enabled, the "true" query-vnc command is
+ defined in the VNC subsystem */
+VncInfo *qmp_query_vnc(Error **errp)
+{
+ error_set(errp, QERR_FEATURE_DISABLED, "vnc");
+ return NULL;
+};
+#endif
+
+#ifndef CONFIG_SPICE
+/* If SPICE support is enabled, the "true" query-spice command is
+ defined in the SPICE subsystem. Also note that we use a small
+ trick to maintain query-spice's original behavior, which is not
+ to be available in the namespace if SPICE is not compiled in */
+SpiceInfo *qmp_query_spice(Error **errp)
+{
+ error_set(errp, QERR_COMMAND_NOT_FOUND, "query-spice");
+ return NULL;
+};
+#endif
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index c947ba4..f7def16 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -62,7 +62,9 @@ def gen_sync_call(name, args, ret_type, indent=0):
name=c_var(name), args=arglist, retval=retval).rstrip()
if ret_type:
ret += "\n" + mcgen(''''
-%(marshal_output_call)s
+if (!error_is_set(errp)) {
+ %(marshal_output_call)s
+}
''',
marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
pop_indent(indent)
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 6d3dab6..5639c6f 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -27,6 +27,7 @@
#include "qemu-queue.h"
#include "qemu-x509.h"
#include "qemu_socket.h"
+#include "qmp-commands.h"
#include "qint.h"
#include "qbool.h"
#include "qstring.h"
@@ -194,22 +195,6 @@ static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info)
qdict_put(dict, "tls", qbool_from_int(tls));
}
-static QList *channel_list_get(void)
-{
- ChannelList *item;
- QList *list;
- QDict *dict;
-
- list = qlist_new();
- QTAILQ_FOREACH(item, &channel_list, link) {
- dict = qdict_new();
- add_addr_info(dict, &item->info->paddr, item->info->plen);
- add_channel_info(dict, item->info);
- qlist_append(list, dict);
- }
- return list;
-}
-
static void channel_event(int event, SpiceChannelEventInfo *info)
{
static const int qevent[] = {
@@ -383,98 +368,90 @@ static const char *wan_compression_names[] = {
/* functions for the rest of qemu */
-static void info_spice_iter(QObject *obj, void *opaque)
+static SpiceChannelList *qmp_query_spice_channels(void)
{
- QDict *client;
- Monitor *mon = opaque;
-
- client = qobject_to_qdict(obj);
- monitor_printf(mon, "Channel:\n");
- monitor_printf(mon, " address: %s:%s%s\n",
- qdict_get_str(client, "host"),
- qdict_get_str(client, "port"),
- qdict_get_bool(client, "tls") ? " [tls]" : "");
- monitor_printf(mon, " session: %" PRId64 "\n",
- qdict_get_int(client, "connection-id"));
- monitor_printf(mon, " channel: %d:%d\n",
- (int)qdict_get_int(client, "channel-type"),
- (int)qdict_get_int(client, "channel-id"));
-}
-
-void do_info_spice_print(Monitor *mon, const QObject *data)
-{
- QDict *server;
- QList *channels;
- const char *host;
- int port;
-
- server = qobject_to_qdict(data);
- if (qdict_get_bool(server, "enabled") == 0) {
- monitor_printf(mon, "Server: disabled\n");
- return;
- }
+ SpiceChannelList *cur_item = NULL, *head = NULL;
+ ChannelList *item;
- monitor_printf(mon, "Server:\n");
- host = qdict_get_str(server, "host");
- port = qdict_get_try_int(server, "port", -1);
- if (port != -1) {
- monitor_printf(mon, " address: %s:%d\n", host, port);
- }
- port = qdict_get_try_int(server, "tls-port", -1);
- if (port != -1) {
- monitor_printf(mon, " address: %s:%d [tls]\n", host, port);
+ QTAILQ_FOREACH(item, &channel_list, link) {
+ SpiceChannelList *chan;
+ char host[NI_MAXHOST], port[NI_MAXSERV];
+
+ chan = g_malloc0(sizeof(*chan));
+ chan->value = g_malloc0(sizeof(*chan->value));
+
+ getnameinfo(&item->info->paddr, item->info->plen,
+ host, sizeof(host), port, sizeof(port),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ chan->value->host = g_strdup(host);
+ chan->value->port = g_strdup(port);
+ chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family));
+
+ chan->value->connection_id = item->info->connection_id;
+ chan->value->channel_type = item->info->type;
+ chan->value->channel_id = item->info->id;
+ chan->value->tls = item->info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS;
+
+ /* XXX: waiting for the qapi to support GSList */
+ if (!cur_item) {
+ head = cur_item = chan;
+ } else {
+ cur_item->next = chan;
+ cur_item = chan;
+ }
}
- monitor_printf(mon, " auth: %s\n", qdict_get_str(server, "auth"));
- monitor_printf(mon, " compiled: %s\n",
- qdict_get_str(server, "compiled-version"));
- channels = qdict_get_qlist(server, "channels");
- if (qlist_empty(channels)) {
- monitor_printf(mon, "Channels: none\n");
- } else {
- qlist_iter(channels, info_spice_iter, mon);
- }
+ return head;
}
-void do_info_spice(Monitor *mon, QObject **ret_data)
+SpiceInfo *qmp_query_spice(Error **errp)
{
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
- QDict *server;
- QList *clist;
- const char *addr;
int port, tls_port;
+ const char *addr;
+ SpiceInfo *info;
char version_string[20]; /* 12 = |255.255.255\0| is the max */
+ info = g_malloc0(sizeof(*info));
+
if (!spice_server || !opts) {
- *ret_data = qobject_from_jsonf("{ 'enabled': false }");
- return;
+ info->enabled = false;
+ return info;
}
+ info->enabled = true;
+
addr = qemu_opt_get(opts, "addr");
port = qemu_opt_get_number(opts, "port", 0);
tls_port = qemu_opt_get_number(opts, "tls-port", 0);
- clist = channel_list_get();
- server = qdict_new();
- qdict_put(server, "enabled", qbool_from_int(true));
- qdict_put(server, "auth", qstring_from_str(auth));
- qdict_put(server, "host", qstring_from_str(addr ? addr : "0.0.0.0"));
+ info->has_auth = true;
+ info->auth = g_strdup(auth);
+
+ info->has_host = true;
+ info->host = g_strdup(addr ? addr : "0.0.0.0");
+
+ info->has_compiled_version = true;
snprintf(version_string, sizeof(version_string), "%d.%d.%d",
(SPICE_SERVER_VERSION & 0xff0000) >> 16,
(SPICE_SERVER_VERSION & 0xff00) >> 8,
SPICE_SERVER_VERSION & 0xff);
- qdict_put(server, "compiled-version", qstring_from_str(version_string));
+ info->compiled_version = g_strdup(version_string);
+
if (port) {
- qdict_put(server, "port", qint_from_int(port));
+ info->has_port = true;
+ info->port = port;
}
if (tls_port) {
- qdict_put(server, "tls-port", qint_from_int(tls_port));
- }
- if (clist) {
- qdict_put(server, "channels", clist);
+ info->has_tls_port = true;
+ info->tls_port = tls_port;
}
- *ret_data = QOBJECT(server);
+ /* for compatibility with the original command */
+ info->has_channels = true;
+ info->channels = qmp_query_spice_channels();
+
+ return info;
}
static void migration_state_notifier(Notifier *notifier, void *data)
diff --git a/ui/vnc.c b/ui/vnc.c
index fc3a612..32d4cb7 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -31,6 +31,7 @@
#include "qemu-timer.h"
#include "acl.h"
#include "qemu-objects.h"
+#include "qmp-commands.h"
#define VNC_REFRESH_INTERVAL_BASE 30
#define VNC_REFRESH_INTERVAL_INC 50
@@ -274,80 +275,110 @@ static void vnc_qmp_event(VncState *vs, MonitorEvent event)
qobject_decref(data);
}
-static void info_vnc_iter(QObject *obj, void *opaque)
+static VncClientInfo *qmp_query_vnc_client(const VncState *client)
{
- QDict *client;
- Monitor *mon = opaque;
+ struct sockaddr_storage sa;
+ socklen_t salen = sizeof(sa);
+ char host[NI_MAXHOST];
+ char serv[NI_MAXSERV];
+ VncClientInfo *info;
+
+ if (getpeername(client->csock, (struct sockaddr *)&sa, &salen) < 0) {
+ return NULL;
+ }
+
+ if (getnameinfo((struct sockaddr *)&sa, salen,
+ host, sizeof(host),
+ serv, sizeof(serv),
+ NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
+ return NULL;
+ }
- client = qobject_to_qdict(obj);
- monitor_printf(mon, "Client:\n");
- monitor_printf(mon, " address: %s:%s\n",
- qdict_get_str(client, "host"),
- qdict_get_str(client, "service"));
+ info = g_malloc0(sizeof(*info));
+ info->host = g_strdup(host);
+ info->service = g_strdup(serv);
+ info->family = g_strdup(inet_strfamily(sa.ss_family));
#ifdef CONFIG_VNC_TLS
- monitor_printf(mon, " x509_dname: %s\n",
- qdict_haskey(client, "x509_dname") ?
- qdict_get_str(client, "x509_dname") : "none");
+ if (client->tls.session && client->tls.dname) {
+ info->has_x509_dname = true;
+ info->x509_dname = g_strdup(client->tls.dname);
+ }
#endif
#ifdef CONFIG_VNC_SASL
- monitor_printf(mon, " username: %s\n",
- qdict_haskey(client, "sasl_username") ?
- qdict_get_str(client, "sasl_username") : "none");
-#endif
-}
-
-void do_info_vnc_print(Monitor *mon, const QObject *data)
-{
- QDict *server;
- QList *clients;
-
- server = qobject_to_qdict(data);
- if (qdict_get_bool(server, "enabled") == 0) {
- monitor_printf(mon, "Server: disabled\n");
- return;
+ if (client->sasl.conn && client->sasl.username) {
+ info->has_sasl_username = true;
+ info->sasl_username = g_strdup(client->sasl.username);
}
+#endif
- monitor_printf(mon, "Server:\n");
- monitor_printf(mon, " address: %s:%s\n",
- qdict_get_str(server, "host"),
- qdict_get_str(server, "service"));
- monitor_printf(mon, " auth: %s\n", qdict_get_str(server, "auth"));
-
- clients = qdict_get_qlist(server, "clients");
- if (qlist_empty(clients)) {
- monitor_printf(mon, "Client: none\n");
- } else {
- qlist_iter(clients, info_vnc_iter, mon);
- }
+ return info;
}
-void do_info_vnc(Monitor *mon, QObject **ret_data)
+VncInfo *qmp_query_vnc(Error **errp)
{
+ VncInfo *info = g_malloc0(sizeof(*info));
+
if (vnc_display == NULL || vnc_display->display == NULL) {
- *ret_data = qobject_from_jsonf("{ 'enabled': false }");
+ info->enabled = false;
} else {
- QList *clist;
+ VncClientInfoList *cur_item = NULL;
+ struct sockaddr_storage sa;
+ socklen_t salen = sizeof(sa);
+ char host[NI_MAXHOST];
+ char serv[NI_MAXSERV];
VncState *client;
- clist = qlist_new();
+ info->enabled = true;
+
+ /* for compatibility with the original command */
+ info->has_clients = true;
+
QTAILQ_FOREACH(client, &vnc_display->clients, next) {
- if (client->info) {
- /* incref so that it's not freed by upper layers */
- qobject_incref(client->info);
- qlist_append_obj(clist, client->info);
+ VncClientInfoList *cinfo = g_malloc0(sizeof(*info));
+ cinfo->value = qmp_query_vnc_client(client);
+
+ /* XXX: waiting for the qapi to support GSList */
+ if (!cur_item) {
+ info->clients = cur_item = cinfo;
+ } else {
+ cur_item->next = cinfo;
+ cur_item = cinfo;
}
}
- *ret_data = qobject_from_jsonf("{ 'enabled': true, 'clients': %p }",
- QOBJECT(clist));
- assert(*ret_data != NULL);
+ if (getsockname(vnc_display->lsock, (struct sockaddr *)&sa,
+ &salen) == -1) {
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ goto out_error;
+ }
- if (vnc_server_info_put(qobject_to_qdict(*ret_data)) < 0) {
- qobject_decref(*ret_data);
- *ret_data = NULL;
+ if (getnameinfo((struct sockaddr *)&sa, salen,
+ host, sizeof(host),
+ serv, sizeof(serv),
+ NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ goto out_error;
}
+
+ info->has_host = true;
+ info->host = g_strdup(host);
+
+ info->has_service = true;
+ info->service = g_strdup(serv);
+
+ info->has_family = true;
+ info->family = g_strdup(inet_strfamily(sa.ss_family));
+
+ info->has_auth = true;
+ info->auth = g_strdup(vnc_auth_name(vnc_display));
}
+
+ return info;
+
+out_error:
+ qapi_free_VncInfo(info);
+ return NULL;
}
/* TODO
diff --git a/vl.c b/vl.c
index 1ddb17b..fb28ffc 100644
--- a/vl.c
+++ b/vl.c
@@ -143,9 +143,9 @@ int main(int argc, char **argv)
#include "audio/audio.h"
#include "migration.h"
#include "kvm.h"
+#include "qjson.h"
#include "qemu-option.h"
#include "qemu-config.h"
-#include "qemu-objects.h"
#include "qemu-options.h"
#include "qmp-commands.h"
#include "main-loop.h"