2011-09-02 19:34:48 +02:00
|
|
|
/*
|
|
|
|
* Human Monitor Interface
|
|
|
|
*
|
|
|
|
* Copyright IBM, Corp. 2011
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2. See
|
|
|
|
* the COPYING file in the top-level directory.
|
|
|
|
*
|
2012-01-13 17:44:23 +01:00
|
|
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
|
|
|
* GNU GPL, version 2 or (at your option) any later version.
|
2011-09-02 19:34:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "hmp.h"
|
2012-10-24 08:43:34 +02:00
|
|
|
#include "net/net.h"
|
2013-04-08 16:55:25 +02:00
|
|
|
#include "sysemu/char.h"
|
2015-02-05 19:58:22 +01:00
|
|
|
#include "sysemu/block-backend.h"
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/option.h"
|
|
|
|
#include "qemu/timer.h"
|
2011-09-02 19:34:48 +02:00
|
|
|
#include "qmp-commands.h"
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/sockets.h"
|
2012-12-17 18:19:49 +01:00
|
|
|
#include "monitor/monitor.h"
|
2013-12-20 23:21:10 +01:00
|
|
|
#include "qapi/opts-visitor.h"
|
2014-05-14 11:43:35 +02:00
|
|
|
#include "qapi/string-output-visitor.h"
|
|
|
|
#include "qapi-visit.h"
|
2012-11-28 12:06:30 +01:00
|
|
|
#include "ui/console.h"
|
2013-06-06 06:28:00 +02:00
|
|
|
#include "block/qapi.h"
|
2013-06-05 14:19:41 +02:00
|
|
|
#include "qemu-io.h"
|
2011-09-02 19:34:48 +02:00
|
|
|
|
2015-03-01 15:29:18 +01:00
|
|
|
#ifdef CONFIG_SPICE
|
|
|
|
#include <spice/enums.h>
|
|
|
|
#endif
|
|
|
|
|
2011-11-22 19:32:37 +01:00
|
|
|
static void hmp_handle_error(Monitor *mon, Error **errp)
|
|
|
|
{
|
2014-05-02 13:26:34 +02:00
|
|
|
assert(errp);
|
|
|
|
if (*errp) {
|
2011-11-22 19:32:37 +01:00
|
|
|
monitor_printf(mon, "%s\n", error_get_pretty(*errp));
|
|
|
|
error_free(*errp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_name(Monitor *mon, const QDict *qdict)
|
2011-09-02 19:34:48 +02:00
|
|
|
{
|
|
|
|
NameInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_name(NULL);
|
|
|
|
if (info->has_name) {
|
|
|
|
monitor_printf(mon, "%s\n", info->name);
|
|
|
|
}
|
|
|
|
qapi_free_NameInfo(info);
|
|
|
|
}
|
2011-08-26 22:38:13 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_version(Monitor *mon, const QDict *qdict)
|
2011-08-26 22:38:13 +02:00
|
|
|
{
|
|
|
|
VersionInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_version(NULL);
|
|
|
|
|
|
|
|
monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
|
|
|
|
info->qemu.major, info->qemu.minor, info->qemu.micro,
|
|
|
|
info->package);
|
|
|
|
|
|
|
|
qapi_free_VersionInfo(info);
|
|
|
|
}
|
2011-09-12 20:10:53 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_kvm(Monitor *mon, const QDict *qdict)
|
2011-09-12 20:10:53 +02:00
|
|
|
{
|
|
|
|
KvmInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_kvm(NULL);
|
|
|
|
monitor_printf(mon, "kvm support: ");
|
|
|
|
if (info->present) {
|
|
|
|
monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "not compiled\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_KvmInfo(info);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_status(Monitor *mon, const QDict *qdict)
|
2011-09-12 22:54:20 +02:00
|
|
|
{
|
|
|
|
StatusInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_status(NULL);
|
|
|
|
|
|
|
|
monitor_printf(mon, "VM status: %s%s",
|
|
|
|
info->running ? "running" : "paused",
|
|
|
|
info->singlestep ? " (single step mode)" : "");
|
|
|
|
|
|
|
|
if (!info->running && info->status != RUN_STATE_PAUSED) {
|
|
|
|
monitor_printf(mon, " (%s)", RunState_lookup[info->status]);
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
|
|
|
|
qapi_free_StatusInfo(info);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_uuid(Monitor *mon, const QDict *qdict)
|
2011-09-13 22:16:25 +02:00
|
|
|
{
|
|
|
|
UuidInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_uuid(NULL);
|
|
|
|
monitor_printf(mon, "%s\n", info->UUID);
|
|
|
|
qapi_free_UuidInfo(info);
|
|
|
|
}
|
2011-09-14 21:05:49 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_chardev(Monitor *mon, const QDict *qdict)
|
2011-09-14 21:05:49 +02:00
|
|
|
{
|
|
|
|
ChardevInfoList *char_info, *info;
|
|
|
|
|
|
|
|
char_info = qmp_query_chardev(NULL);
|
|
|
|
for (info = char_info; info; info = info->next) {
|
|
|
|
monitor_printf(mon, "%s: filename=%s\n", info->value->label,
|
|
|
|
info->value->filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_ChardevInfoList(char_info);
|
|
|
|
}
|
2011-09-15 19:20:28 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_mice(Monitor *mon, const QDict *qdict)
|
2011-09-21 20:29:55 +02:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
2011-09-13 22:37:16 +02:00
|
|
|
{
|
|
|
|
MigrationInfo *info;
|
2012-08-06 20:42:47 +02:00
|
|
|
MigrationCapabilityStatusList *caps, *cap;
|
2011-09-13 22:37:16 +02:00
|
|
|
|
|
|
|
info = qmp_query_migrate(NULL);
|
2012-08-06 20:42:47 +02:00
|
|
|
caps = qmp_query_migrate_capabilities(NULL);
|
|
|
|
|
|
|
|
/* do not display parameters during setup */
|
|
|
|
if (info->has_status && caps) {
|
|
|
|
monitor_printf(mon, "capabilities: ");
|
|
|
|
for (cap = caps; cap; cap = cap->next) {
|
|
|
|
monitor_printf(mon, "%s: %s ",
|
|
|
|
MigrationCapability_lookup[cap->value->capability],
|
|
|
|
cap->value->state ? "on" : "off");
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
2011-09-13 22:37:16 +02:00
|
|
|
|
|
|
|
if (info->has_status) {
|
2015-03-13 09:08:40 +01:00
|
|
|
monitor_printf(mon, "Migration status: %s\n",
|
|
|
|
MigrationStatus_lookup[info->status]);
|
2012-08-18 13:17:10 +02:00
|
|
|
monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
|
|
|
|
info->total_time);
|
2012-08-13 09:53:12 +02:00
|
|
|
if (info->has_expected_downtime) {
|
|
|
|
monitor_printf(mon, "expected downtime: %" PRIu64 " milliseconds\n",
|
|
|
|
info->expected_downtime);
|
|
|
|
}
|
2012-08-13 09:35:16 +02:00
|
|
|
if (info->has_downtime) {
|
|
|
|
monitor_printf(mon, "downtime: %" PRIu64 " milliseconds\n",
|
|
|
|
info->downtime);
|
|
|
|
}
|
2013-07-22 16:01:58 +02:00
|
|
|
if (info->has_setup_time) {
|
|
|
|
monitor_printf(mon, "setup: %" PRIu64 " milliseconds\n",
|
|
|
|
info->setup_time);
|
|
|
|
}
|
2011-09-13 22:37:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info->has_ram) {
|
|
|
|
monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->transferred >> 10);
|
2013-06-26 03:35:30 +02:00
|
|
|
monitor_printf(mon, "throughput: %0.2f mbps\n",
|
|
|
|
info->ram->mbps);
|
2011-09-13 22:37:16 +02:00
|
|
|
monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->remaining >> 10);
|
|
|
|
monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->total >> 10);
|
2012-08-06 20:42:56 +02:00
|
|
|
monitor_printf(mon, "duplicate: %" PRIu64 " pages\n",
|
|
|
|
info->ram->duplicate);
|
2013-03-26 10:58:37 +01:00
|
|
|
monitor_printf(mon, "skipped: %" PRIu64 " pages\n",
|
|
|
|
info->ram->skipped);
|
2012-08-06 20:42:56 +02:00
|
|
|
monitor_printf(mon, "normal: %" PRIu64 " pages\n",
|
|
|
|
info->ram->normal);
|
|
|
|
monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->normal_bytes >> 10);
|
2014-04-04 11:57:55 +02:00
|
|
|
monitor_printf(mon, "dirty sync count: %" PRIu64 "\n",
|
|
|
|
info->ram->dirty_sync_count);
|
2012-08-13 12:31:25 +02:00
|
|
|
if (info->ram->dirty_pages_rate) {
|
|
|
|
monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",
|
|
|
|
info->ram->dirty_pages_rate);
|
|
|
|
}
|
2011-09-13 22:37:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-08-06 20:42:57 +02:00
|
|
|
if (info->has_xbzrle_cache) {
|
|
|
|
monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
|
|
|
|
info->xbzrle_cache->cache_size);
|
|
|
|
monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
|
|
|
|
info->xbzrle_cache->bytes >> 10);
|
|
|
|
monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
|
|
|
|
info->xbzrle_cache->pages);
|
|
|
|
monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
|
|
|
|
info->xbzrle_cache->cache_miss);
|
2014-04-04 11:57:56 +02:00
|
|
|
monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n",
|
|
|
|
info->xbzrle_cache->cache_miss_rate);
|
2012-08-06 20:42:57 +02:00
|
|
|
monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
|
|
|
|
info->xbzrle_cache->overflow);
|
|
|
|
}
|
|
|
|
|
2011-09-13 22:37:16 +02:00
|
|
|
qapi_free_MigrationInfo(info);
|
2012-08-06 20:42:47 +02:00
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
|
2012-08-06 20:42:47 +02:00
|
|
|
{
|
|
|
|
MigrationCapabilityStatusList *caps, *cap;
|
|
|
|
|
|
|
|
caps = qmp_query_migrate_capabilities(NULL);
|
|
|
|
|
|
|
|
if (caps) {
|
|
|
|
monitor_printf(mon, "capabilities: ");
|
|
|
|
for (cap = caps; cap; cap = cap->next) {
|
|
|
|
monitor_printf(mon, "%s: %s ",
|
|
|
|
MigrationCapability_lookup[cap->value->capability],
|
|
|
|
cap->value->state ? "on" : "off");
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
2011-09-13 22:37:16 +02:00
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict)
|
2012-08-06 20:42:54 +02:00
|
|
|
{
|
|
|
|
monitor_printf(mon, "xbzrel cache size: %" PRId64 " kbytes\n",
|
|
|
|
qmp_query_migrate_cache_size(NULL) >> 10);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_cpus(Monitor *mon, const QDict *qdict)
|
2011-09-21 21:38:35 +02:00
|
|
|
{
|
|
|
|
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 = '*';
|
|
|
|
}
|
|
|
|
|
2012-10-19 23:19:19 +02:00
|
|
|
monitor_printf(mon, "%c CPU #%" PRId64 ":", active, cpu->value->CPU);
|
2011-09-21 21:38:35 +02:00
|
|
|
|
|
|
|
if (cpu->value->has_pc) {
|
2012-10-19 23:19:19 +02:00
|
|
|
monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->pc);
|
2011-09-21 21:38:35 +02:00
|
|
|
}
|
|
|
|
if (cpu->value->has_nip) {
|
2012-10-19 23:19:19 +02:00
|
|
|
monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->nip);
|
2011-09-21 21:38:35 +02:00
|
|
|
}
|
|
|
|
if (cpu->value->has_npc) {
|
2012-10-19 23:19:19 +02:00
|
|
|
monitor_printf(mon, " npc=0x%016" PRIx64, cpu->value->npc);
|
2011-09-21 21:38:35 +02:00
|
|
|
}
|
|
|
|
if (cpu->value->has_PC) {
|
2012-10-19 23:19:19 +02:00
|
|
|
monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->PC);
|
2011-09-21 21:38:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cpu->value->halted) {
|
|
|
|
monitor_printf(mon, " (halted)");
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_CpuInfoList(cpu_list);
|
|
|
|
}
|
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
static void print_block_info(Monitor *mon, BlockInfo *info,
|
|
|
|
BlockDeviceInfo *inserted, bool verbose)
|
2011-09-21 22:16:47 +02:00
|
|
|
{
|
2013-06-06 06:28:00 +02:00
|
|
|
ImageInfo *image_info;
|
2011-09-21 22:16:47 +02:00
|
|
|
|
2014-09-15 12:12:52 +02:00
|
|
|
assert(!info || !info->has_inserted || info->inserted == inserted);
|
|
|
|
|
|
|
|
if (info) {
|
|
|
|
monitor_printf(mon, "%s", info->device);
|
|
|
|
if (inserted && inserted->has_node_name) {
|
|
|
|
monitor_printf(mon, " (%s)", inserted->node_name);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(inserted);
|
|
|
|
monitor_printf(mon, "%s",
|
|
|
|
inserted->has_node_name
|
|
|
|
? inserted->node_name
|
|
|
|
: "<anonymous>");
|
|
|
|
}
|
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (inserted) {
|
|
|
|
monitor_printf(mon, ": %s (%s%s%s)\n",
|
|
|
|
inserted->file,
|
|
|
|
inserted->drv,
|
|
|
|
inserted->ro ? ", read-only" : "",
|
|
|
|
inserted->encrypted ? ", encrypted" : "");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, ": [not inserted]\n");
|
|
|
|
}
|
2011-09-21 22:16:47 +02:00
|
|
|
|
2014-09-15 12:12:52 +02:00
|
|
|
if (info) {
|
|
|
|
if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
|
|
|
|
monitor_printf(mon, " I/O status: %s\n",
|
|
|
|
BlockDeviceIoStatus_lookup[info->io_status]);
|
|
|
|
}
|
2011-09-21 22:16:47 +02:00
|
|
|
|
2014-09-15 12:12:52 +02:00
|
|
|
if (info->removable) {
|
|
|
|
monitor_printf(mon, " Removable device: %slocked, tray %s\n",
|
|
|
|
info->locked ? "" : "not ",
|
|
|
|
info->tray_open ? "open" : "closed");
|
|
|
|
}
|
2014-09-15 12:06:39 +02:00
|
|
|
}
|
2013-06-19 16:10:55 +02:00
|
|
|
|
2011-09-21 22:16:47 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (!inserted) {
|
|
|
|
return;
|
|
|
|
}
|
2011-09-21 22:16:47 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
monitor_printf(mon, " Cache mode: %s%s%s\n",
|
|
|
|
inserted->cache->writeback ? "writeback" : "writethrough",
|
|
|
|
inserted->cache->direct ? ", direct" : "",
|
|
|
|
inserted->cache->no_flush ? ", ignore flushes" : "");
|
|
|
|
|
|
|
|
if (inserted->has_backing_file) {
|
|
|
|
monitor_printf(mon,
|
|
|
|
" Backing file: %s "
|
|
|
|
"(chain depth: %" PRId64 ")\n",
|
|
|
|
inserted->backing_file,
|
|
|
|
inserted->backing_file_depth);
|
|
|
|
}
|
2011-11-08 06:00:31 +01:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
|
|
|
monitor_printf(mon, " Detect zeroes: %s\n",
|
|
|
|
BlockdevDetectZeroesOptions_lookup[inserted->detect_zeroes]);
|
|
|
|
}
|
2013-06-19 16:10:55 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (inserted->bps || inserted->bps_rd || inserted->bps_wr ||
|
|
|
|
inserted->iops || inserted->iops_rd || inserted->iops_wr)
|
|
|
|
{
|
|
|
|
monitor_printf(mon, " I/O throttling: bps=%" PRId64
|
|
|
|
" bps_rd=%" PRId64 " bps_wr=%" PRId64
|
|
|
|
" bps_max=%" PRId64
|
|
|
|
" bps_rd_max=%" PRId64
|
|
|
|
" bps_wr_max=%" PRId64
|
|
|
|
" iops=%" PRId64 " iops_rd=%" PRId64
|
|
|
|
" iops_wr=%" PRId64
|
|
|
|
" iops_max=%" PRId64
|
|
|
|
" iops_rd_max=%" PRId64
|
|
|
|
" iops_wr_max=%" PRId64
|
|
|
|
" iops_size=%" PRId64 "\n",
|
|
|
|
inserted->bps,
|
|
|
|
inserted->bps_rd,
|
|
|
|
inserted->bps_wr,
|
|
|
|
inserted->bps_max,
|
|
|
|
inserted->bps_rd_max,
|
|
|
|
inserted->bps_wr_max,
|
|
|
|
inserted->iops,
|
|
|
|
inserted->iops_rd,
|
|
|
|
inserted->iops_wr,
|
|
|
|
inserted->iops_max,
|
|
|
|
inserted->iops_rd_max,
|
|
|
|
inserted->iops_wr_max,
|
|
|
|
inserted->iops_size);
|
|
|
|
}
|
2013-06-19 16:10:55 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (verbose) {
|
|
|
|
monitor_printf(mon, "\nImages:\n");
|
|
|
|
image_info = inserted->image;
|
|
|
|
while (1) {
|
|
|
|
bdrv_image_info_dump((fprintf_function)monitor_printf,
|
|
|
|
mon, image_info);
|
|
|
|
if (image_info->has_backing_image) {
|
|
|
|
image_info = image_info->backing_image;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-22 13:28:45 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
void hmp_info_block(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
BlockInfoList *block_list, *info;
|
2014-09-15 12:19:14 +02:00
|
|
|
BlockDeviceInfoList *blockdev_list, *blockdev;
|
2014-09-15 12:06:39 +02:00
|
|
|
const char *device = qdict_get_try_str(qdict, "device");
|
|
|
|
bool verbose = qdict_get_try_bool(qdict, "verbose", 0);
|
2014-09-15 12:19:14 +02:00
|
|
|
bool nodes = qdict_get_try_bool(qdict, "nodes", 0);
|
|
|
|
bool printed = false;
|
2014-05-22 13:28:45 +02:00
|
|
|
|
2014-09-15 12:19:14 +02:00
|
|
|
/* Print BlockBackend information */
|
|
|
|
if (!nodes) {
|
2015-02-08 15:40:48 +01:00
|
|
|
block_list = qmp_query_block(NULL);
|
2014-09-15 12:19:14 +02:00
|
|
|
} else {
|
|
|
|
block_list = NULL;
|
|
|
|
}
|
2013-06-19 16:10:55 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
for (info = block_list; info; info = info->next) {
|
|
|
|
if (device && strcmp(device, info->value->device)) {
|
|
|
|
continue;
|
2014-05-18 00:58:19 +02:00
|
|
|
}
|
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (info != block_list) {
|
|
|
|
monitor_printf(mon, "\n");
|
2013-06-19 16:10:55 +02:00
|
|
|
}
|
2013-06-06 06:28:00 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
print_block_info(mon, info->value, info->value->has_inserted
|
|
|
|
? info->value->inserted : NULL,
|
|
|
|
verbose);
|
2014-09-15 12:19:14 +02:00
|
|
|
printed = true;
|
2011-09-21 22:16:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_BlockInfoList(block_list);
|
2014-09-15 12:19:14 +02:00
|
|
|
|
|
|
|
if ((!device && !nodes) || printed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print node information */
|
|
|
|
blockdev_list = qmp_query_named_block_nodes(NULL);
|
|
|
|
for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) {
|
|
|
|
assert(blockdev->value->has_node_name);
|
|
|
|
if (device && strcmp(device, blockdev->value->node_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blockdev != blockdev_list) {
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
print_block_info(mon, NULL, blockdev->value, verbose);
|
|
|
|
}
|
|
|
|
qapi_free_BlockDeviceInfoList(blockdev_list);
|
2011-09-21 22:16:47 +02:00
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
|
2011-09-22 20:56:36 +02:00
|
|
|
{
|
|
|
|
BlockStatsList *stats_list, *stats;
|
|
|
|
|
2014-10-31 04:32:57 +01:00
|
|
|
stats_list = qmp_query_blockstats(false, false, NULL);
|
2011-09-22 20:56:36 +02:00
|
|
|
|
|
|
|
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
|
2015-02-02 14:52:18 +01:00
|
|
|
" rd_merged=%" PRId64
|
|
|
|
" wr_merged=%" PRId64
|
2011-09-22 20:56:36 +02:00
|
|
|
"\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,
|
2015-02-02 14:52:18 +01:00
|
|
|
stats->value->stats->flush_total_time_ns,
|
|
|
|
stats->value->stats->rd_merged,
|
|
|
|
stats->value->stats->wr_merged);
|
2011-09-22 20:56:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_BlockStatsList(stats_list);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_vnc(Monitor *mon, const QDict *qdict)
|
2011-10-17 20:41:22 +02:00
|
|
|
{
|
|
|
|
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",
|
2014-06-18 08:43:30 +02:00
|
|
|
client->value->base->host,
|
|
|
|
client->value->base->service);
|
2011-10-17 20:41:22 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-01-13 15:46:39 +01:00
|
|
|
#ifdef CONFIG_SPICE
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_spice(Monitor *mon, const QDict *qdict)
|
2011-10-20 21:01:33 +02:00
|
|
|
{
|
|
|
|
SpiceChannelList *chan;
|
|
|
|
SpiceInfo *info;
|
2015-03-01 15:29:18 +01:00
|
|
|
const char *channel_name;
|
|
|
|
const char * const channel_names[] = {
|
|
|
|
[SPICE_CHANNEL_MAIN] = "main",
|
|
|
|
[SPICE_CHANNEL_DISPLAY] = "display",
|
|
|
|
[SPICE_CHANNEL_INPUTS] = "inputs",
|
|
|
|
[SPICE_CHANNEL_CURSOR] = "cursor",
|
|
|
|
[SPICE_CHANNEL_PLAYBACK] = "playback",
|
|
|
|
[SPICE_CHANNEL_RECORD] = "record",
|
|
|
|
[SPICE_CHANNEL_TUNNEL] = "tunnel",
|
|
|
|
[SPICE_CHANNEL_SMARTCARD] = "smartcard",
|
|
|
|
[SPICE_CHANNEL_USBREDIR] = "usbredir",
|
|
|
|
[SPICE_CHANNEL_PORT] = "port",
|
2015-03-03 09:27:28 +01:00
|
|
|
#if 0
|
|
|
|
/* minimum spice-protocol is 0.12.3, webdav was added in 0.12.7,
|
|
|
|
* no easy way to #ifdef (SPICE_CHANNEL_* is a enum). Disable
|
|
|
|
* as quick fix for build failures with older versions. */
|
2015-03-01 15:29:18 +01:00
|
|
|
[SPICE_CHANNEL_WEBDAV] = "webdav",
|
2015-03-03 09:27:28 +01:00
|
|
|
#endif
|
2015-03-01 15:29:18 +01:00
|
|
|
};
|
2011-10-20 21:01:33 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2012-08-21 10:51:58 +02:00
|
|
|
monitor_printf(mon, " migrated: %s\n",
|
|
|
|
info->migrated ? "true" : "false");
|
2011-10-20 21:01:33 +02:00
|
|
|
monitor_printf(mon, " auth: %s\n", info->auth);
|
|
|
|
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
2012-03-29 23:23:14 +02:00
|
|
|
monitor_printf(mon, " mouse-mode: %s\n",
|
|
|
|
SpiceQueryMouseMode_lookup[info->mouse_mode]);
|
2011-10-20 21:01:33 +02:00
|
|
|
|
|
|
|
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",
|
2014-06-18 08:43:30 +02:00
|
|
|
chan->value->base->host, chan->value->base->port,
|
2011-10-20 21:01:33 +02:00
|
|
|
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);
|
2015-03-01 15:29:18 +01:00
|
|
|
|
|
|
|
channel_name = "unknown";
|
|
|
|
if (chan->value->channel_type > 0 &&
|
|
|
|
chan->value->channel_type < ARRAY_SIZE(channel_names) &&
|
|
|
|
channel_names[chan->value->channel_type]) {
|
|
|
|
channel_name = channel_names[chan->value->channel_type];
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, " channel name: %s\n", channel_name);
|
2011-10-20 21:01:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
qapi_free_SpiceInfo(info);
|
|
|
|
}
|
2015-01-13 15:46:39 +01:00
|
|
|
#endif
|
2011-10-20 21:01:33 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_balloon(Monitor *mon, const QDict *qdict)
|
2011-10-21 15:41:37 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-12-03 18:56:41 +01:00
|
|
|
monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20);
|
2011-10-21 15:41:37 +02:00
|
|
|
|
|
|
|
qapi_free_BalloonInfo(info);
|
|
|
|
}
|
|
|
|
|
2011-10-21 18:15:33 +02:00
|
|
|
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 {
|
2013-08-07 17:39:43 +02:00
|
|
|
monitor_printf(mon, "Class %04" PRId64, dev->class_info.q_class);
|
2011-10-21 18:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_pci(Monitor *mon, const QDict *qdict)
|
2011-10-21 18:15:33 +02:00
|
|
|
{
|
2012-01-11 16:51:52 +01:00
|
|
|
PciInfoList *info_list, *info;
|
2011-10-21 18:15:33 +02:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2012-01-11 16:51:52 +01:00
|
|
|
info_list = qmp_query_pci(&err);
|
2011-10-21 18:15:33 +02:00
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "PCI devices not supported\n");
|
|
|
|
error_free(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-11 16:51:52 +01:00
|
|
|
for (info = info_list; info; info = info->next) {
|
2011-10-21 18:15:33 +02:00
|
|
|
PciDeviceInfoList *dev;
|
|
|
|
|
|
|
|
for (dev = info->value->devices; dev; dev = dev->next) {
|
|
|
|
hmp_info_pci_device(mon, dev->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-11 16:51:52 +01:00
|
|
|
qapi_free_PciInfoList(info_list);
|
2011-10-21 18:15:33 +02:00
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
|
2012-01-18 15:40:49 +01:00
|
|
|
{
|
|
|
|
BlockJobInfoList *list;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
list = qmp_query_block_jobs(&err);
|
|
|
|
assert(!err);
|
|
|
|
|
|
|
|
if (!list) {
|
|
|
|
monitor_printf(mon, "No active jobs\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (list) {
|
|
|
|
if (strcmp(list->value->type, "stream") == 0) {
|
|
|
|
monitor_printf(mon, "Streaming device %s: Completed %" PRId64
|
|
|
|
" of %" PRId64 " bytes, speed limit %" PRId64
|
|
|
|
" bytes/s\n",
|
|
|
|
list->value->device,
|
|
|
|
list->value->offset,
|
|
|
|
list->value->len,
|
|
|
|
list->value->speed);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "Type %s, device %s: Completed %" PRId64
|
|
|
|
" of %" PRId64 " bytes, speed limit %" PRId64
|
|
|
|
" bytes/s\n",
|
|
|
|
list->value->type,
|
|
|
|
list->value->device,
|
|
|
|
list->value->offset,
|
|
|
|
list->value->len,
|
|
|
|
list->value->speed);
|
|
|
|
}
|
|
|
|
list = list->next;
|
|
|
|
}
|
2014-09-16 15:36:55 +02:00
|
|
|
|
|
|
|
qapi_free_BlockJobInfoList(list);
|
2012-01-18 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-27 18:47:49 +01:00
|
|
|
void hmp_info_tpm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
TPMInfoList *info_list, *info;
|
|
|
|
Error *err = NULL;
|
|
|
|
unsigned int c = 0;
|
|
|
|
TPMPassthroughOptions *tpo;
|
|
|
|
|
|
|
|
info_list = qmp_query_tpm(&err);
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "TPM device not supported\n");
|
|
|
|
error_free(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info_list) {
|
|
|
|
monitor_printf(mon, "TPM device:\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (info = info_list; info; info = info->next) {
|
|
|
|
TPMInfo *ti = info->value;
|
|
|
|
monitor_printf(mon, " tpm%d: model=%s\n",
|
|
|
|
c, TpmModel_lookup[ti->model]);
|
|
|
|
|
|
|
|
monitor_printf(mon, " \\ %s: type=%s",
|
2013-03-20 17:34:48 +01:00
|
|
|
ti->id, TpmTypeOptionsKind_lookup[ti->options->kind]);
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-27 18:47:49 +01:00
|
|
|
|
2013-03-20 17:34:48 +01:00
|
|
|
switch (ti->options->kind) {
|
|
|
|
case TPM_TYPE_OPTIONS_KIND_PASSTHROUGH:
|
|
|
|
tpo = ti->options->passthrough;
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-27 18:47:49 +01:00
|
|
|
monitor_printf(mon, "%s%s%s%s",
|
|
|
|
tpo->has_path ? ",path=" : "",
|
|
|
|
tpo->has_path ? tpo->path : "",
|
|
|
|
tpo->has_cancel_path ? ",cancel-path=" : "",
|
|
|
|
tpo->has_cancel_path ? tpo->cancel_path : "");
|
|
|
|
break;
|
|
|
|
case TPM_TYPE_OPTIONS_KIND_MAX:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
qapi_free_TPMInfoList(info_list);
|
|
|
|
}
|
|
|
|
|
2011-09-15 19:20:28 +02:00
|
|
|
void hmp_quit(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
monitor_suspend(mon);
|
|
|
|
qmp_quit(NULL);
|
|
|
|
}
|
2011-09-15 19:34:39 +02:00
|
|
|
|
|
|
|
void hmp_stop(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_stop(NULL);
|
|
|
|
}
|
2011-09-15 19:41:46 +02:00
|
|
|
|
|
|
|
void hmp_system_reset(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_system_reset(NULL);
|
|
|
|
}
|
2011-09-28 16:06:15 +02:00
|
|
|
|
|
|
|
void hmp_system_powerdown(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_system_powerdown(NULL);
|
|
|
|
}
|
2011-10-06 19:31:39 +02:00
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
2011-11-22 19:32:37 +01:00
|
|
|
|
|
|
|
void hmp_memsave(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
|
|
|
uint64_t addr = qdict_get_int(qdict, "val");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-22 19:32:37 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-22 19:32:37 +01:00
|
|
|
}
|
2011-11-22 20:26:46 +01:00
|
|
|
|
|
|
|
void hmp_pmemsave(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
|
|
|
uint64_t addr = qdict_get_int(qdict, "val");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-22 20:26:46 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_pmemsave(addr, size, filename, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-01-24 17:03:20 +01:00
|
|
|
}
|
|
|
|
|
qemu-char: Saner naming of memchar stuff & doc fixes
New device, has never been released, so we can still improve things
without worrying about compatibility.
Naming is a mess. The code calls the device driver CirMemCharDriver,
the public API calls it "memory", "memchardev", or "memchar", and the
special commands are named like "memchar-FOO". "memory" is a
particularly unfortunate choice, because there's another character
device driver called MemoryDriver. Moreover, the device's distinctive
property is that it's a ring buffer, not that's in memory. Therefore:
* Rename CirMemCharDriver to RingBufCharDriver, and call the thing a
"ringbuf" in the API.
* Rename QMP and HMP commands from memchar-FOO to ringbuf-FOO.
* Rename device parameter from maxcapacity to size (simple words are
good for you).
* Clearly mark the parameter as optional in documentation.
* Fix error reporting so that chardev-add reports to current monitor,
not stderr.
* Replace cirmem in C identifiers by ringbuf.
* Rework documentation. Document the impact of our crappy UTF-8
handling on reading.
* QMP examples that even work.
I could split this up into multiple commits, but they'd change the
same documentation lines multiple times. Not worth it.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-06 21:27:24 +01:00
|
|
|
void hmp_ringbuf_write(Monitor *mon, const QDict *qdict)
|
2013-01-24 17:03:20 +01:00
|
|
|
{
|
|
|
|
const char *chardev = qdict_get_str(qdict, "device");
|
|
|
|
const char *data = qdict_get_str(qdict, "data");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-01-24 17:03:20 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_ringbuf_write(chardev, data, false, 0, &err);
|
2013-01-24 17:03:20 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-22 20:26:46 +01:00
|
|
|
}
|
2011-11-22 20:58:31 +01:00
|
|
|
|
qemu-char: Saner naming of memchar stuff & doc fixes
New device, has never been released, so we can still improve things
without worrying about compatibility.
Naming is a mess. The code calls the device driver CirMemCharDriver,
the public API calls it "memory", "memchardev", or "memchar", and the
special commands are named like "memchar-FOO". "memory" is a
particularly unfortunate choice, because there's another character
device driver called MemoryDriver. Moreover, the device's distinctive
property is that it's a ring buffer, not that's in memory. Therefore:
* Rename CirMemCharDriver to RingBufCharDriver, and call the thing a
"ringbuf" in the API.
* Rename QMP and HMP commands from memchar-FOO to ringbuf-FOO.
* Rename device parameter from maxcapacity to size (simple words are
good for you).
* Clearly mark the parameter as optional in documentation.
* Fix error reporting so that chardev-add reports to current monitor,
not stderr.
* Replace cirmem in C identifiers by ringbuf.
* Rework documentation. Document the impact of our crappy UTF-8
handling on reading.
* QMP examples that even work.
I could split this up into multiple commits, but they'd change the
same documentation lines multiple times. Not worth it.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-06 21:27:24 +01:00
|
|
|
void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
|
2013-01-24 17:03:21 +01:00
|
|
|
{
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
const char *chardev = qdict_get_str(qdict, "device");
|
2013-02-06 21:27:15 +01:00
|
|
|
char *data;
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-02-06 21:27:26 +01:00
|
|
|
int i;
|
2013-01-24 17:03:21 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
data = qmp_ringbuf_read(chardev, size, false, 0, &err);
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "%s\n", error_get_pretty(err));
|
|
|
|
error_free(err);
|
2013-01-24 17:03:21 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-02-06 21:27:26 +01:00
|
|
|
for (i = 0; data[i]; i++) {
|
|
|
|
unsigned char ch = data[i];
|
|
|
|
|
|
|
|
if (ch == '\\') {
|
|
|
|
monitor_printf(mon, "\\\\");
|
|
|
|
} else if ((ch < 0x20 && ch != '\n' && ch != '\t') || ch == 0x7F) {
|
|
|
|
monitor_printf(mon, "\\u%04X", ch);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "%c", ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
2013-02-06 21:27:15 +01:00
|
|
|
g_free(data);
|
2013-01-24 17:03:21 +01:00
|
|
|
}
|
|
|
|
|
2011-11-22 20:58:31 +01:00
|
|
|
static void hmp_cont_cb(void *opaque, int err)
|
|
|
|
{
|
|
|
|
if (!err) {
|
2012-07-27 01:41:53 +02:00
|
|
|
qmp_cont(NULL);
|
2011-11-22 20:58:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-27 01:41:53 +02:00
|
|
|
static bool key_is_missing(const BlockInfo *bdev)
|
|
|
|
{
|
|
|
|
return (bdev->inserted && bdev->inserted->encryption_key_missing);
|
|
|
|
}
|
|
|
|
|
2011-11-22 20:58:31 +01:00
|
|
|
void hmp_cont(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2012-07-27 01:41:53 +02:00
|
|
|
BlockInfoList *bdev_list, *bdev;
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-22 20:58:31 +01:00
|
|
|
|
2012-07-27 01:41:53 +02:00
|
|
|
bdev_list = qmp_query_block(NULL);
|
|
|
|
for (bdev = bdev_list; bdev; bdev = bdev->next) {
|
|
|
|
if (key_is_missing(bdev->value)) {
|
|
|
|
monitor_read_block_device_key(mon, bdev->value->device,
|
|
|
|
hmp_cont_cb, NULL);
|
|
|
|
goto out;
|
2011-11-22 20:58:31 +01:00
|
|
|
}
|
|
|
|
}
|
2012-07-27 01:41:53 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_cont(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-07-27 01:41:53 +02:00
|
|
|
|
|
|
|
out:
|
|
|
|
qapi_free_BlockInfoList(bdev_list);
|
2011-11-22 20:58:31 +01:00
|
|
|
}
|
2011-11-23 15:55:53 +01:00
|
|
|
|
2012-02-23 13:45:21 +01:00
|
|
|
void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_system_wakeup(NULL);
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 13:55:43 +01:00
|
|
|
void hmp_nmi(Monitor *mon, const QDict *qdict)
|
2011-11-23 15:55:53 +01:00
|
|
|
{
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-23 15:55:53 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_inject_nmi(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 15:55:53 +01:00
|
|
|
}
|
2011-11-23 16:11:55 +01:00
|
|
|
|
|
|
|
void hmp_set_link(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
int up = qdict_get_bool(qdict, "up");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-23 16:11:55 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_set_link(name, up, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 16:11:55 +01:00
|
|
|
}
|
2011-11-23 16:28:21 +01:00
|
|
|
|
|
|
|
void hmp_block_passwd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *password = qdict_get_str(qdict, "password");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-23 16:28:21 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_block_passwd(true, device, false, NULL, password, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 16:28:21 +01:00
|
|
|
}
|
2011-11-25 17:38:09 +01:00
|
|
|
|
|
|
|
void hmp_balloon(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t value = qdict_get_int(qdict, "value");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-25 17:38:09 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_balloon(value, &err);
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "balloon: %s\n", error_get_pretty(err));
|
|
|
|
error_free(err);
|
2011-11-25 17:38:09 +01:00
|
|
|
}
|
|
|
|
}
|
2011-11-25 17:57:10 +01:00
|
|
|
|
|
|
|
void hmp_block_resize(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
int64_t size = qdict_get_int(qdict, "size");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-25 17:57:10 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_block_resize(true, device, false, NULL, size, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-25 17:57:10 +01:00
|
|
|
}
|
2011-11-25 19:15:19 +01:00
|
|
|
|
2012-10-18 16:49:24 +02:00
|
|
|
void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *filename = qdict_get_str(qdict, "target");
|
|
|
|
const char *format = qdict_get_try_str(qdict, "format");
|
|
|
|
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
|
|
|
int full = qdict_get_try_bool(qdict, "full", 0);
|
|
|
|
enum NewImageMode mode;
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2012-10-18 16:49:24 +02:00
|
|
|
|
|
|
|
if (!filename) {
|
2014-05-02 13:26:29 +02:00
|
|
|
error_set(&err, QERR_MISSING_PARAMETER, "target");
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-10-18 16:49:24 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reuse) {
|
|
|
|
mode = NEW_IMAGE_MODE_EXISTING;
|
|
|
|
} else {
|
|
|
|
mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_drive_mirror(device, filename, !!format, format,
|
2014-06-27 18:25:25 +02:00
|
|
|
false, NULL, false, NULL,
|
2012-10-18 16:49:24 +02:00
|
|
|
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
2013-01-22 09:03:13 +01:00
|
|
|
true, mode, false, 0, false, 0, false, 0,
|
2014-05-02 13:26:29 +02:00
|
|
|
false, 0, false, 0, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-10-18 16:49:24 +02:00
|
|
|
}
|
|
|
|
|
2013-06-26 14:11:58 +02:00
|
|
|
void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *filename = qdict_get_str(qdict, "target");
|
|
|
|
const char *format = qdict_get_try_str(qdict, "format");
|
|
|
|
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
|
|
|
int full = qdict_get_try_bool(qdict, "full", 0);
|
|
|
|
enum NewImageMode mode;
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-06-26 14:11:58 +02:00
|
|
|
|
|
|
|
if (!filename) {
|
2014-05-02 13:26:29 +02:00
|
|
|
error_set(&err, QERR_MISSING_PARAMETER, "target");
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-06-26 14:11:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reuse) {
|
|
|
|
mode = NEW_IMAGE_MODE_EXISTING;
|
|
|
|
} else {
|
|
|
|
mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_drive_backup(device, filename, !!format, format,
|
|
|
|
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
2014-05-02 13:26:29 +02:00
|
|
|
true, mode, false, 0, false, 0, false, 0, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-06-26 14:11:58 +02:00
|
|
|
}
|
|
|
|
|
2011-11-25 19:15:19 +01:00
|
|
|
void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *filename = qdict_get_try_str(qdict, "snapshot-file");
|
|
|
|
const char *format = qdict_get_try_str(qdict, "format");
|
2012-03-06 18:55:59 +01:00
|
|
|
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
|
|
|
enum NewImageMode mode;
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-25 19:15:19 +01:00
|
|
|
|
|
|
|
if (!filename) {
|
|
|
|
/* In the future, if 'snapshot-file' is not specified, the snapshot
|
|
|
|
will be taken internally. Today it's actually required. */
|
2014-05-02 13:26:29 +02:00
|
|
|
error_set(&err, QERR_MISSING_PARAMETER, "snapshot-file");
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-25 19:15:19 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-06 18:55:59 +01:00
|
|
|
mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
2014-01-23 21:31:38 +01:00
|
|
|
qmp_blockdev_snapshot_sync(true, device, false, NULL,
|
|
|
|
filename, false, NULL,
|
|
|
|
!!format, format,
|
2014-05-02 13:26:29 +02:00
|
|
|
true, mode, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-25 19:15:19 +01:00
|
|
|
}
|
2011-11-28 01:54:09 +01:00
|
|
|
|
2013-09-11 08:04:37 +02:00
|
|
|
void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-09-11 08:04:37 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_blockdev_snapshot_internal_sync(device, name, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-09-11 08:04:37 +02:00
|
|
|
}
|
|
|
|
|
2013-09-11 08:04:38 +02:00
|
|
|
void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
const char *id = qdict_get_try_str(qdict, "id");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-09-11 08:04:38 +02:00
|
|
|
|
|
|
|
qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id,
|
2014-05-02 13:26:29 +02:00
|
|
|
true, name, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-09-11 08:04:38 +02:00
|
|
|
}
|
|
|
|
|
2011-11-28 01:54:09 +01:00
|
|
|
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_migrate_cancel(NULL);
|
|
|
|
}
|
2011-11-28 02:18:01 +01:00
|
|
|
|
2015-02-19 12:40:28 +01:00
|
|
|
void hmp_migrate_incoming(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
|
|
|
|
|
|
|
qmp_migrate_incoming(uri, &err);
|
|
|
|
|
2015-02-26 15:54:39 +01:00
|
|
|
hmp_handle_error(mon, &err);
|
2015-02-19 12:40:28 +01:00
|
|
|
}
|
|
|
|
|
2011-11-28 02:18:01 +01:00
|
|
|
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
double value = qdict_get_double(qdict, "value");
|
|
|
|
qmp_migrate_set_downtime(value, NULL);
|
|
|
|
}
|
2011-11-28 14:59:37 +01:00
|
|
|
|
2012-08-06 20:42:54 +02:00
|
|
|
void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t value = qdict_get_int(qdict, "value");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_migrate_set_cache_size(value, &err);
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "%s\n", error_get_pretty(err));
|
|
|
|
error_free(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-28 14:59:37 +01:00
|
|
|
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t value = qdict_get_int(qdict, "value");
|
|
|
|
qmp_migrate_set_speed(value, NULL);
|
|
|
|
}
|
2011-12-07 14:17:51 +01:00
|
|
|
|
2012-08-06 20:42:48 +02:00
|
|
|
void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *cap = qdict_get_str(qdict, "capability");
|
|
|
|
bool state = qdict_get_bool(qdict, "state");
|
|
|
|
Error *err = NULL;
|
|
|
|
MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
|
|
|
|
if (strcmp(cap, MigrationCapability_lookup[i]) == 0) {
|
|
|
|
caps->value = g_malloc0(sizeof(*caps->value));
|
|
|
|
caps->value->capability = i;
|
|
|
|
caps->value->state = state;
|
|
|
|
caps->next = NULL;
|
|
|
|
qmp_migrate_set_capabilities(caps, &err);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == MIGRATION_CAPABILITY_MAX) {
|
|
|
|
error_set(&err, QERR_INVALID_PARAMETER, cap);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
|
|
|
|
|
|
|
if (err) {
|
2013-01-31 08:12:19 +01:00
|
|
|
monitor_printf(mon, "migrate_set_capability: %s\n",
|
2012-08-06 20:42:48 +02:00
|
|
|
error_get_pretty(err));
|
|
|
|
error_free(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-07 14:17:51 +01:00
|
|
|
void hmp_set_password(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
|
|
|
const char *password = qdict_get_str(qdict, "password");
|
|
|
|
const char *connected = qdict_get_try_str(qdict, "connected");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_set_password(protocol, password, !!connected, connected, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-07 14:47:57 +01:00
|
|
|
|
|
|
|
void hmp_expire_password(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
|
|
|
const char *whenstr = qdict_get_str(qdict, "time");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_expire_password(protocol, whenstr, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-07 19:02:36 +01:00
|
|
|
|
|
|
|
void hmp_eject(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int force = qdict_get_try_bool(qdict, "force", 0);
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_eject(device, true, force, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-08 14:13:50 +01:00
|
|
|
|
2013-11-14 11:54:14 +01:00
|
|
|
static void hmp_change_read_arg(void *opaque, const char *password,
|
|
|
|
void *readline_opaque)
|
2011-12-08 14:13:50 +01:00
|
|
|
{
|
|
|
|
qmp_change_vnc_password(password, NULL);
|
2013-11-14 11:54:14 +01:00
|
|
|
monitor_read_command(opaque, 1);
|
2011-12-08 14:13:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_change(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *target = qdict_get_str(qdict, "target");
|
|
|
|
const char *arg = qdict_get_try_str(qdict, "arg");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
if (strcmp(device, "vnc") == 0 &&
|
|
|
|
(strcmp(target, "passwd") == 0 ||
|
|
|
|
strcmp(target, "password") == 0)) {
|
|
|
|
if (!arg) {
|
|
|
|
monitor_read_password(mon, hmp_change_read_arg, NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_change(device, target, !!arg, arg, &err);
|
2014-01-30 15:07:28 +01:00
|
|
|
if (err &&
|
2012-08-06 20:55:22 +02:00
|
|
|
error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
|
2012-08-06 20:49:34 +02:00
|
|
|
error_free(err);
|
|
|
|
monitor_read_block_device_key(mon, device, NULL, NULL);
|
2011-12-08 14:13:50 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-14 19:49:14 +01:00
|
|
|
|
|
|
|
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_block_set_io_throttle(qdict_get_str(qdict, "device"),
|
|
|
|
qdict_get_int(qdict, "bps"),
|
|
|
|
qdict_get_int(qdict, "bps_rd"),
|
|
|
|
qdict_get_int(qdict, "bps_wr"),
|
|
|
|
qdict_get_int(qdict, "iops"),
|
|
|
|
qdict_get_int(qdict, "iops_rd"),
|
2013-09-02 14:14:40 +02:00
|
|
|
qdict_get_int(qdict, "iops_wr"),
|
|
|
|
false, /* no burst max via HMP */
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
0,
|
|
|
|
false,
|
2013-09-02 14:14:41 +02:00
|
|
|
0,
|
|
|
|
false, /* No default I/O size */
|
2013-09-02 14:14:40 +02:00
|
|
|
0, &err);
|
2011-12-14 19:49:14 +01:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-01-18 15:40:46 +01:00
|
|
|
|
|
|
|
void hmp_block_stream(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *base = qdict_get_try_str(qdict, "base");
|
2012-04-25 17:51:03 +02:00
|
|
|
int64_t speed = qdict_get_try_int(qdict, "speed", 0);
|
2012-01-18 15:40:46 +01:00
|
|
|
|
block: add backing-file option to block-stream
On some image chains, QEMU may not always be able to resolve the
filenames properly, when updating the backing file of an image
after a block job.
For instance, certain relative pathnames may fail, or drives may
have been specified originally by file descriptor (e.g. /dev/fd/???),
or a relative protocol pathname may have been used.
In these instances, QEMU may lack the information to be able to make
the correct choice, but the user or management layer most likely does
have that knowledge.
With this extension to the block-stream api, the user is able to change
the backing file of the active layer as part of the block-stream
operation.
This allows the change to be 'safe', in the sense that if the attempt
to write the active image metadata fails, then the block-stream
operation returns failure, without disrupting the guest.
If a backing file string is not specified in the command, the backing
file string to use is determined in the same manner as it was
previously.
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Jeff Cody <jcody@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-25 21:40:11 +02:00
|
|
|
qmp_block_stream(device, base != NULL, base, false, NULL,
|
2012-09-28 17:22:59 +02:00
|
|
|
qdict_haskey(qdict, "speed"), speed,
|
2013-09-17 18:10:47 +02:00
|
|
|
true, BLOCKDEV_ON_ERROR_REPORT, &error);
|
2012-01-18 15:40:46 +01:00
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
2012-01-18 15:40:47 +01:00
|
|
|
|
|
|
|
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
2012-05-08 16:51:56 +02:00
|
|
|
int64_t value = qdict_get_int(qdict, "speed");
|
2012-01-18 15:40:47 +01:00
|
|
|
|
|
|
|
qmp_block_job_set_speed(device, value, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
2012-01-18 15:40:48 +01:00
|
|
|
|
|
|
|
void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
2012-09-28 17:22:51 +02:00
|
|
|
bool force = qdict_get_try_bool(qdict, "force", 0);
|
2012-01-18 15:40:48 +01:00
|
|
|
|
2012-09-28 17:22:51 +02:00
|
|
|
qmp_block_job_cancel(device, true, force, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_block_job_pause(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
|
|
|
|
qmp_block_job_pause(device, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_block_job_resume(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
|
|
|
|
qmp_block_job_resume(device, &error);
|
2012-01-18 15:40:48 +01:00
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
2011-12-05 17:48:01 +01:00
|
|
|
|
2012-10-18 16:49:21 +02:00
|
|
|
void hmp_block_job_complete(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
|
|
|
|
qmp_block_job_complete(device, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
|
|
|
|
2015-03-13 09:08:39 +01:00
|
|
|
typedef struct HMPMigrationStatus
|
2011-12-05 17:48:01 +01:00
|
|
|
{
|
|
|
|
QEMUTimer *timer;
|
|
|
|
Monitor *mon;
|
|
|
|
bool is_block_migration;
|
2015-03-13 09:08:39 +01:00
|
|
|
} HMPMigrationStatus;
|
2011-12-05 17:48:01 +01:00
|
|
|
|
|
|
|
static void hmp_migrate_status_cb(void *opaque)
|
|
|
|
{
|
2015-03-13 09:08:39 +01:00
|
|
|
HMPMigrationStatus *status = opaque;
|
2011-12-05 17:48:01 +01:00
|
|
|
MigrationInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_migrate(NULL);
|
2015-03-13 09:08:40 +01:00
|
|
|
if (!info->has_status || info->status == MIGRATION_STATUS_ACTIVE ||
|
|
|
|
info->status == MIGRATION_STATUS_SETUP) {
|
2011-12-05 17:48:01 +01:00
|
|
|
if (info->has_disk) {
|
|
|
|
int progress;
|
|
|
|
|
|
|
|
if (info->disk->remaining) {
|
|
|
|
progress = info->disk->transferred * 100 / info->disk->total;
|
|
|
|
} else {
|
|
|
|
progress = 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(status->mon, "Completed %d %%\r", progress);
|
|
|
|
monitor_flush(status->mon);
|
|
|
|
}
|
|
|
|
|
2013-08-21 17:03:08 +02:00
|
|
|
timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
|
2011-12-05 17:48:01 +01:00
|
|
|
} else {
|
|
|
|
if (status->is_block_migration) {
|
|
|
|
monitor_printf(status->mon, "\n");
|
|
|
|
}
|
|
|
|
monitor_resume(status->mon);
|
2013-08-21 17:03:08 +02:00
|
|
|
timer_del(status->timer);
|
2011-12-05 17:48:01 +01:00
|
|
|
g_free(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationInfo(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_migrate(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int detach = qdict_get_try_bool(qdict, "detach", 0);
|
|
|
|
int blk = qdict_get_try_bool(qdict, "blk", 0);
|
|
|
|
int inc = qdict_get_try_bool(qdict, "inc", 0);
|
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_migrate(uri, !!blk, blk, !!inc, inc, false, false, &err);
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "migrate: %s\n", error_get_pretty(err));
|
|
|
|
error_free(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach) {
|
2015-03-13 09:08:39 +01:00
|
|
|
HMPMigrationStatus *status;
|
2011-12-05 17:48:01 +01:00
|
|
|
|
|
|
|
if (monitor_suspend(mon) < 0) {
|
|
|
|
monitor_printf(mon, "terminal does not allow synchronous "
|
|
|
|
"migration, continuing detached\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = g_malloc0(sizeof(*status));
|
|
|
|
status->mon = mon;
|
|
|
|
status->is_block_migration = blk || inc;
|
2013-08-21 17:03:08 +02:00
|
|
|
status->timer = timer_new_ms(QEMU_CLOCK_REALTIME, hmp_migrate_status_cb,
|
2011-12-05 17:48:01 +01:00
|
|
|
status);
|
2013-08-21 17:03:08 +02:00
|
|
|
timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
|
2011-12-05 17:48:01 +01:00
|
|
|
}
|
|
|
|
}
|
2012-03-29 17:38:50 +02:00
|
|
|
|
|
|
|
void hmp_device_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_device_del(id, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-05-07 06:10:47 +02:00
|
|
|
|
|
|
|
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2012-05-07 06:10:47 +02:00
|
|
|
int paging = qdict_get_try_bool(qdict, "paging", 0);
|
2014-04-17 10:15:07 +02:00
|
|
|
int zlib = qdict_get_try_bool(qdict, "zlib", 0);
|
|
|
|
int lzo = qdict_get_try_bool(qdict, "lzo", 0);
|
|
|
|
int snappy = qdict_get_try_bool(qdict, "snappy", 0);
|
2012-09-21 18:53:00 +02:00
|
|
|
const char *file = qdict_get_str(qdict, "filename");
|
2012-05-07 06:10:47 +02:00
|
|
|
bool has_begin = qdict_haskey(qdict, "begin");
|
|
|
|
bool has_length = qdict_haskey(qdict, "length");
|
|
|
|
int64_t begin = 0;
|
|
|
|
int64_t length = 0;
|
2014-02-18 07:11:36 +01:00
|
|
|
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
2012-09-21 18:53:00 +02:00
|
|
|
char *prot;
|
2012-05-07 06:10:47 +02:00
|
|
|
|
2014-04-17 10:15:07 +02:00
|
|
|
if (zlib + lzo + snappy > 1) {
|
2014-05-02 13:26:29 +02:00
|
|
|
error_setg(&err, "only one of '-z|-l|-s' can be set");
|
|
|
|
hmp_handle_error(mon, &err);
|
2014-04-17 10:15:07 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zlib) {
|
|
|
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lzo) {
|
|
|
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (snappy) {
|
|
|
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
|
|
|
|
}
|
|
|
|
|
2012-05-07 06:10:47 +02:00
|
|
|
if (has_begin) {
|
|
|
|
begin = qdict_get_int(qdict, "begin");
|
|
|
|
}
|
|
|
|
if (has_length) {
|
|
|
|
length = qdict_get_int(qdict, "length");
|
|
|
|
}
|
|
|
|
|
2012-09-21 18:53:00 +02:00
|
|
|
prot = g_strconcat("file:", file, NULL);
|
|
|
|
|
|
|
|
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
|
2014-05-02 13:26:29 +02:00
|
|
|
true, dump_format, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-09-21 18:53:00 +02:00
|
|
|
g_free(prot);
|
2012-05-07 06:10:47 +02:00
|
|
|
}
|
2012-04-18 22:34:15 +02:00
|
|
|
|
|
|
|
void hmp_netdev_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
|
|
|
opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &err);
|
2014-01-30 15:07:28 +01:00
|
|
|
if (err) {
|
2012-04-18 22:34:15 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
netdev_add(opts, &err);
|
2014-01-30 15:07:28 +01:00
|
|
|
if (err) {
|
2012-04-18 22:34:15 +02:00
|
|
|
qemu_opts_del(opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-04-16 19:36:32 +02:00
|
|
|
|
|
|
|
void hmp_netdev_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_netdev_del(id, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-06-22 20:36:09 +02:00
|
|
|
|
2013-12-20 23:21:10 +01:00
|
|
|
void hmp_object_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
2014-05-07 09:53:51 +02:00
|
|
|
Error *err_end = NULL;
|
2013-12-20 23:21:10 +01:00
|
|
|
QemuOpts *opts;
|
|
|
|
char *type = NULL;
|
|
|
|
char *id = NULL;
|
|
|
|
void *dummy = NULL;
|
|
|
|
OptsVisitor *ov;
|
|
|
|
QDict *pdict;
|
|
|
|
|
|
|
|
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
|
|
|
|
if (err) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ov = opts_visitor_new(opts);
|
|
|
|
pdict = qdict_clone_shallow(qdict);
|
|
|
|
|
|
|
|
visit_start_struct(opts_get_visitor(ov), &dummy, NULL, NULL, 0, &err);
|
|
|
|
if (err) {
|
|
|
|
goto out_clean;
|
|
|
|
}
|
|
|
|
|
|
|
|
qdict_del(pdict, "qom-type");
|
|
|
|
visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err);
|
|
|
|
if (err) {
|
2014-05-07 09:53:51 +02:00
|
|
|
goto out_end;
|
2013-12-20 23:21:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
qdict_del(pdict, "id");
|
|
|
|
visit_type_str(opts_get_visitor(ov), &id, "id", &err);
|
|
|
|
if (err) {
|
2014-05-07 09:53:51 +02:00
|
|
|
goto out_end;
|
2013-12-20 23:21:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
object_add(type, id, pdict, opts_get_visitor(ov), &err);
|
2014-05-07 09:53:51 +02:00
|
|
|
|
|
|
|
out_end:
|
|
|
|
visit_end_struct(opts_get_visitor(ov), &err_end);
|
|
|
|
if (!err && err_end) {
|
2013-12-20 23:21:10 +01:00
|
|
|
qmp_object_del(id, NULL);
|
|
|
|
}
|
2014-05-07 09:53:51 +02:00
|
|
|
error_propagate(&err, err_end);
|
2013-12-20 23:21:10 +01:00
|
|
|
out_clean:
|
|
|
|
opts_visitor_cleanup(ov);
|
|
|
|
|
|
|
|
QDECREF(pdict);
|
|
|
|
qemu_opts_del(opts);
|
|
|
|
g_free(id);
|
|
|
|
g_free(type);
|
|
|
|
g_free(dummy);
|
|
|
|
|
|
|
|
out:
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2012-06-22 20:36:09 +02:00
|
|
|
void hmp_getfd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2012-06-22 20:36:09 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_getfd(fdname, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-06-22 20:36:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_closefd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2012-06-22 20:36:09 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_closefd(fdname, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-06-22 20:36:09 +02:00
|
|
|
}
|
2012-08-31 04:56:26 +02:00
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 13:55:43 +01:00
|
|
|
void hmp_sendkey(Monitor *mon, const QDict *qdict)
|
2012-08-31 04:56:26 +02:00
|
|
|
{
|
|
|
|
const char *keys = qdict_get_str(qdict, "keys");
|
2012-09-20 19:19:47 +02:00
|
|
|
KeyValueList *keylist, *head = NULL, *tmp = NULL;
|
2012-08-31 04:56:26 +02:00
|
|
|
int has_hold_time = qdict_haskey(qdict, "hold-time");
|
|
|
|
int hold_time = qdict_get_try_int(qdict, "hold-time", -1);
|
|
|
|
Error *err = NULL;
|
|
|
|
char keyname_buf[16];
|
|
|
|
char *separator;
|
2012-09-20 19:19:47 +02:00
|
|
|
int keyname_len;
|
2012-08-31 04:56:26 +02:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
separator = strchr(keys, '-');
|
|
|
|
keyname_len = separator ? separator - keys : strlen(keys);
|
|
|
|
pstrcpy(keyname_buf, sizeof(keyname_buf), keys);
|
|
|
|
|
|
|
|
/* Be compatible with old interface, convert user inputted "<" */
|
|
|
|
if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) {
|
|
|
|
pstrcpy(keyname_buf, sizeof(keyname_buf), "less");
|
|
|
|
keyname_len = 4;
|
|
|
|
}
|
|
|
|
keyname_buf[keyname_len] = 0;
|
|
|
|
|
|
|
|
keylist = g_malloc0(sizeof(*keylist));
|
2012-09-20 19:19:47 +02:00
|
|
|
keylist->value = g_malloc0(sizeof(*keylist->value));
|
2012-08-31 04:56:26 +02:00
|
|
|
|
|
|
|
if (!head) {
|
|
|
|
head = keylist;
|
|
|
|
}
|
|
|
|
if (tmp) {
|
|
|
|
tmp->next = keylist;
|
|
|
|
}
|
|
|
|
tmp = keylist;
|
|
|
|
|
2012-09-20 19:19:47 +02:00
|
|
|
if (strstart(keyname_buf, "0x", NULL)) {
|
|
|
|
char *endp;
|
|
|
|
int value = strtoul(keyname_buf, &endp, 0);
|
|
|
|
if (*endp != '\0') {
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
keylist->value->kind = KEY_VALUE_KIND_NUMBER;
|
|
|
|
keylist->value->number = value;
|
|
|
|
} else {
|
|
|
|
int idx = index_from_key(keyname_buf);
|
|
|
|
if (idx == Q_KEY_CODE_MAX) {
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
keylist->value->kind = KEY_VALUE_KIND_QCODE;
|
|
|
|
keylist->value->qcode = idx;
|
|
|
|
}
|
|
|
|
|
2012-08-31 04:56:26 +02:00
|
|
|
if (!separator) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
keys = separator + 1;
|
|
|
|
}
|
|
|
|
|
2012-09-20 19:19:47 +02:00
|
|
|
qmp_send_key(head, has_hold_time, hold_time, &err);
|
2012-08-31 04:56:26 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-09-20 19:19:47 +02:00
|
|
|
|
|
|
|
out:
|
|
|
|
qapi_free_KeyValueList(head);
|
|
|
|
return;
|
|
|
|
|
|
|
|
err_out:
|
|
|
|
monitor_printf(mon, "invalid parameter: %s\n", keyname_buf);
|
|
|
|
goto out;
|
2012-08-31 04:56:26 +02:00
|
|
|
}
|
2012-05-24 18:48:23 +02:00
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 13:55:43 +01:00
|
|
|
void hmp_screendump(Monitor *mon, const QDict *qdict)
|
2012-05-24 18:48:23 +02:00
|
|
|
{
|
|
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_screendump(filename, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-08-23 11:53:04 +02:00
|
|
|
|
|
|
|
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
|
|
|
int writable = qdict_get_try_bool(qdict, "writable", 0);
|
|
|
|
int all = qdict_get_try_bool(qdict, "all", 0);
|
|
|
|
Error *local_err = NULL;
|
|
|
|
BlockInfoList *block_list, *info;
|
|
|
|
SocketAddress *addr;
|
|
|
|
|
|
|
|
if (writable && !all) {
|
|
|
|
error_setg(&local_err, "-w only valid together with -a");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First check if the address is valid and start the server. */
|
|
|
|
addr = socket_parse(uri, &local_err);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_nbd_server_start(addr, &local_err);
|
|
|
|
qapi_free_SocketAddress(addr);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!all) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then try adding all block devices. If one fails, close all and
|
|
|
|
* exit.
|
|
|
|
*/
|
|
|
|
block_list = qmp_query_block(NULL);
|
|
|
|
|
|
|
|
for (info = block_list; info; info = info->next) {
|
|
|
|
if (!info->value->has_inserted) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_nbd_server_add(info->value->device, true, writable, &local_err);
|
|
|
|
|
|
|
|
if (local_err != NULL) {
|
|
|
|
qmp_nbd_server_stop(NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_BlockInfoList(block_list);
|
|
|
|
|
|
|
|
exit:
|
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
int writable = qdict_get_try_bool(qdict, "writable", 0);
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
qmp_nbd_server_add(device, true, writable, &local_err);
|
|
|
|
|
|
|
|
if (local_err != NULL) {
|
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2012-08-23 11:53:04 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_nbd_server_stop(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-08-23 11:53:04 +02:00
|
|
|
}
|
2012-12-19 10:33:40 +01:00
|
|
|
|
2013-12-11 19:24:14 +01:00
|
|
|
void hmp_cpu_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int cpuid;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
cpuid = qdict_get_int(qdict, "id");
|
|
|
|
qmp_cpu_add(cpuid, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2012-12-19 10:33:40 +01:00
|
|
|
void hmp_chardev_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *args = qdict_get_str(qdict, "args");
|
|
|
|
Error *err = NULL;
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
|
|
|
opts = qemu_opts_parse(qemu_find_opts("chardev"), args, 1);
|
|
|
|
if (opts == NULL) {
|
error: Strip trailing '\n' from error string arguments (again)
Commit 6daf194d and be62a2eb got rid of a bunch, but they keep coming
back. Tracked down with this Coccinelle semantic patch:
@r@
expression err, eno, cls, fmt;
position p;
@@
(
error_report(fmt, ...)@p
|
error_set(err, cls, fmt, ...)@p
|
error_set_errno(err, eno, cls, fmt, ...)@p
|
error_setg(err, fmt, ...)@p
|
error_setg_errno(err, eno, fmt, ...)@p
)
@script:python@
fmt << r.fmt;
p << r.p;
@@
if "\\n" in str(fmt):
print "%s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt)
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-id: 1360354939-10994-4-git-send-email-armbru@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-08 21:22:16 +01:00
|
|
|
error_setg(&err, "Parsing chardev args failed");
|
2012-12-19 10:33:40 +01:00
|
|
|
} else {
|
|
|
|
qemu_chr_new_from_opts(opts, NULL, &err);
|
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
|
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
2013-06-05 14:19:41 +02:00
|
|
|
|
|
|
|
void hmp_qemu_io(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2015-02-05 19:58:22 +01:00
|
|
|
BlockBackend *blk;
|
2013-06-05 14:19:41 +02:00
|
|
|
const char* device = qdict_get_str(qdict, "device");
|
|
|
|
const char* command = qdict_get_str(qdict, "command");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2015-02-05 19:58:22 +01:00
|
|
|
blk = blk_by_name(device);
|
|
|
|
if (blk) {
|
|
|
|
qemuio_command(blk, command);
|
2013-06-05 14:19:41 +02:00
|
|
|
} else {
|
|
|
|
error_set(&err, QERR_DEVICE_NOT_FOUND, device);
|
|
|
|
}
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2013-12-20 23:21:09 +01:00
|
|
|
|
|
|
|
void hmp_object_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_object_del(id, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2014-05-14 11:43:35 +02:00
|
|
|
|
|
|
|
void hmp_info_memdev(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
MemdevList *memdev_list = qmp_query_memdev(&err);
|
|
|
|
MemdevList *m = memdev_list;
|
|
|
|
StringOutputVisitor *ov;
|
2014-08-18 08:46:34 +02:00
|
|
|
char *str;
|
2014-05-14 11:43:35 +02:00
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
|
|
while (m) {
|
|
|
|
ov = string_output_visitor_new(false);
|
|
|
|
visit_type_uint16List(string_output_get_visitor(ov),
|
|
|
|
&m->value->host_nodes, NULL, NULL);
|
2014-06-19 16:14:43 +02:00
|
|
|
monitor_printf(mon, "memory backend: %d\n", i);
|
2014-05-14 11:43:35 +02:00
|
|
|
monitor_printf(mon, " size: %" PRId64 "\n", m->value->size);
|
|
|
|
monitor_printf(mon, " merge: %s\n",
|
|
|
|
m->value->merge ? "true" : "false");
|
|
|
|
monitor_printf(mon, " dump: %s\n",
|
|
|
|
m->value->dump ? "true" : "false");
|
|
|
|
monitor_printf(mon, " prealloc: %s\n",
|
|
|
|
m->value->prealloc ? "true" : "false");
|
|
|
|
monitor_printf(mon, " policy: %s\n",
|
|
|
|
HostMemPolicy_lookup[m->value->policy]);
|
2014-08-18 08:46:34 +02:00
|
|
|
str = string_output_get_string(ov);
|
|
|
|
monitor_printf(mon, " host nodes: %s\n", str);
|
2014-05-14 11:43:35 +02:00
|
|
|
|
2014-08-18 08:46:34 +02:00
|
|
|
g_free(str);
|
2014-05-14 11:43:35 +02:00
|
|
|
string_output_visitor_cleanup(ov);
|
|
|
|
m = m->next;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
2014-08-18 08:46:35 +02:00
|
|
|
|
|
|
|
qapi_free_MemdevList(memdev_list);
|
2014-05-14 11:43:35 +02:00
|
|
|
}
|
2014-09-23 07:35:19 +02:00
|
|
|
|
|
|
|
void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err);
|
|
|
|
MemoryDeviceInfoList *info;
|
|
|
|
MemoryDeviceInfo *value;
|
|
|
|
PCDIMMDeviceInfo *di;
|
|
|
|
|
|
|
|
for (info = info_list; info; info = info->next) {
|
|
|
|
value = info->value;
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
switch (value->kind) {
|
|
|
|
case MEMORY_DEVICE_INFO_KIND_DIMM:
|
|
|
|
di = value->dimm;
|
|
|
|
|
|
|
|
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
|
|
|
|
MemoryDeviceInfoKind_lookup[value->kind],
|
|
|
|
di->id ? di->id : "");
|
|
|
|
monitor_printf(mon, " addr: 0x%" PRIx64 "\n", di->addr);
|
|
|
|
monitor_printf(mon, " slot: %" PRId64 "\n", di->slot);
|
|
|
|
monitor_printf(mon, " node: %" PRId64 "\n", di->node);
|
|
|
|
monitor_printf(mon, " size: %" PRIu64 "\n", di->size);
|
|
|
|
monitor_printf(mon, " memdev: %s\n", di->memdev);
|
|
|
|
monitor_printf(mon, " hotplugged: %s\n",
|
|
|
|
di->hotplugged ? "true" : "false");
|
|
|
|
monitor_printf(mon, " hotpluggable: %s\n",
|
|
|
|
di->hotpluggable ? "true" : "false");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MemoryDeviceInfoList(info_list);
|
|
|
|
}
|
2014-05-07 18:08:29 +02:00
|
|
|
|
|
|
|
void hmp_qom_list(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *path = qdict_get_try_str(qdict, "path");
|
|
|
|
ObjectPropertyInfoList *list;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
if (path == NULL) {
|
|
|
|
monitor_printf(mon, "/\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
list = qmp_qom_list(path, &err);
|
|
|
|
if (err == NULL) {
|
|
|
|
ObjectPropertyInfoList *start = list;
|
|
|
|
while (list != NULL) {
|
|
|
|
ObjectPropertyInfo *value = list->value;
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s (%s)\n",
|
|
|
|
value->name, value->type);
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
qapi_free_ObjectPropertyInfoList(start);
|
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2014-05-07 19:48:15 +02:00
|
|
|
|
|
|
|
void hmp_qom_set(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *path = qdict_get_str(qdict, "path");
|
|
|
|
const char *property = qdict_get_str(qdict, "property");
|
|
|
|
const char *value = qdict_get_str(qdict, "value");
|
|
|
|
Error *err = NULL;
|
|
|
|
bool ambiguous = false;
|
|
|
|
Object *obj;
|
|
|
|
|
|
|
|
obj = object_resolve_path(path, &ambiguous);
|
|
|
|
if (obj == NULL) {
|
|
|
|
error_set(&err, QERR_DEVICE_NOT_FOUND, path);
|
|
|
|
} else {
|
|
|
|
if (ambiguous) {
|
|
|
|
monitor_printf(mon, "Warning: Path '%s' is ambiguous\n", path);
|
|
|
|
}
|
|
|
|
object_property_parse(obj, value, property, &err);
|
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|