Initial support for the new QEMU monitor protocol using JSON
as the data encoding format instead of plain text
* po/POTFILES.in: Add src/qemu/qemu_monitor_json.c
* src/qemu/qemu_conf.c, src/qemu/qemu_conf.h: Hack to turn on QMP
mode. Replace with a version number check on >= 0.12 later
* src/qemu/qemu_monitor.c: Delegate to json monitor if enabled
* src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_json.h: Add
impl of QMP protocol
* src/Makefile.am: Add src/qemu/qemu_monitor_json.{c,h}
---
po/POTFILES.in | 1 +
src/Makefile.am | 2 +
src/qemu/qemu_conf.c | 7 +
src/qemu/qemu_conf.h | 3 +
src/qemu/qemu_driver.c | 16 +-
src/qemu/qemu_monitor.c | 260 +++++++--
src/qemu/qemu_monitor.h | 4 +
src/qemu/qemu_monitor_json.c | 1423 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 156 +++++
tests/qemuxml2argvtest.c | 2 +-
10 files changed, 1825 insertions(+), 49 deletions(-)
create mode 100644 src/qemu/qemu_monitor_json.c
create mode 100644 src/qemu/qemu_monitor_json.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9864259..f8e9130 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -29,6 +29,7 @@ src/qemu/qemu_bridge_filter.c
src/qemu/qemu_conf.c
src/qemu/qemu_driver.c
src/qemu/qemu_monitor.c
+src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_text.c
src/remote/remote_driver.c
src/secret/secret_driver.c
diff --git a/src/Makefile.am b/src/Makefile.am
index b0775a8..043ca6b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -188,6 +188,8 @@ QEMU_DRIVER_SOURCES = \
qemu/qemu_monitor.c qemu/qemu_monitor.h \
qemu/qemu_monitor_text.c \
qemu/qemu_monitor_text.h \
+ qemu/qemu_monitor_json.c \
+ qemu/qemu_monitor_json.h \
qemu/qemu_driver.c qemu/qemu_driver.h \
qemu/qemu_bridge_filter.c \
qemu/qemu_bridge_filter.h
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 8f8d490..7d41b5d 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -942,6 +942,9 @@ static unsigned int qemudComputeCmdFlags(const char *help,
if (version >= 10000)
flags |= QEMUD_CMD_FLAG_0_10;
+ if (version >= 12000)
+ flags |= QEMUD_CMD_FLAG_0_12;
+
return flags;
}
@@ -1584,6 +1587,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
struct qemud_driver *driver,
virDomainDefPtr def,
virDomainChrDefPtr monitor_chr,
+ int monitor_json,
unsigned int qemuCmdFlags,
const char ***retargv,
const char ***retenv,
@@ -1858,6 +1862,9 @@ int qemudBuildCommandLine(virConnectPtr conn,
if (monitor_chr) {
virBuffer buf = VIR_BUFFER_INITIALIZER;
+ if (monitor_json)
+ virBufferAddLit(&buf, "control,");
+
qemudBuildCommandLineChrDevStr(monitor_chr, &buf);
if (virBufferError(&buf))
goto error;
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 1bf3e16..248677a 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -74,6 +74,8 @@ enum qemud_cmd_flags {
QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX = (1 << 21), /* Does qemu support unix domain
sockets for migration? */
QEMUD_CMD_FLAG_CHARDEV = (1 << 22), /* Is the new -chardev arg available
*/
QEMUD_CMD_FLAG_ENABLE_KVM = (1 << 23), /* Is the -enable-kvm flag available
to "enable KVM full virtualization support" */
+ QEMUD_CMD_FLAG_0_12 = (1 << 24),
+ QEMUD_CMD_FLAG_MONITOR_JSON = QEMUD_CMD_FLAG_0_12, /* JSON mode for monitor */
};
/* Main driver state */
@@ -168,6 +170,7 @@ int qemudBuildCommandLine (virConnectPtr conn,
struct qemud_driver *driver,
virDomainDefPtr def,
virDomainChrDefPtr monitor_chr,
+ int monitor_json,
unsigned int qemuCmdFlags,
const char ***retargv,
const char ***retenv,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 468e0ab..e3759bf 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -87,6 +87,7 @@ struct _qemuDomainObjPrivate {
qemuMonitorPtr mon;
virDomainChrDefPtr monConfig;
+ int monJSON;
int nvcpupids;
int *vcpupids;
@@ -173,6 +174,8 @@ static int qemuDomainObjPrivateXMLFormat(virBufferPtr buf, void
*data)
}
virBufferEscapeString(buf, " <monitor path='%s'",
monitorpath);
+ if (priv->monJSON)
+ virBufferAddLit(buf, " json='1'");
virBufferVSprintf(buf, " type='%s'/>\n",
virDomainChrTypeToString(priv->monConfig->type));
}
@@ -217,6 +220,9 @@ static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void
*data)
priv->monConfig->type = VIR_DOMAIN_CHR_TYPE_PTY;
VIR_FREE(tmp);
+ if (virXPathBoolean(NULL, "int(./monitor[1]/@json)", ctxt))
+ priv->monJSON = 1;
+
switch (priv->monConfig->type) {
case VIR_DOMAIN_CHR_TYPE_PTY:
priv->monConfig->data.file.path = monitorpath;
@@ -780,6 +786,7 @@ qemuConnectMonitor(virDomainObjPtr vm)
if ((priv->mon = qemuMonitorOpen(vm,
priv->monConfig,
+ priv->monJSON,
qemuHandleMonitorEOF)) == NULL) {
VIR_ERROR(_("Failed to connect monitor for %s\n"),
vm->def->name);
return -1;
@@ -2328,6 +2335,11 @@ static int qemudStartVMDaemon(virConnectPtr conn,
if (qemuPrepareMonitorChr(conn, driver, priv->monConfig, vm->def->name) <
0)
goto cleanup;
+#if HAVE_YAJL
+ if (qemuCmdFlags & QEMUD_CMD_FLAG_MONITOR_JSON)
+ priv->monJSON = 1;
+#endif
+
if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) {
virReportSystemError(conn, ret,
_("Cannot remove stale PID file for %s"),
@@ -2343,7 +2355,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
vm->def->id = driver->nextvmid++;
if (qemudBuildCommandLine(conn, driver, vm->def, priv->monConfig,
- qemuCmdFlags, &argv, &progenv,
+ priv->monJSON, qemuCmdFlags, &argv, &progenv,
&tapfds, &ntapfds, migrateFrom) < 0)
goto cleanup;
@@ -4418,7 +4430,7 @@ static char *qemuDomainXMLToNative(virConnectPtr conn,
goto cleanup;
if (qemudBuildCommandLine(conn, driver, def,
- &monConfig, qemuCmdFlags,
+ &monConfig, 0, qemuCmdFlags,
&retargv, &retenv,
NULL, NULL, /* Don't want it to create TAP devices */
NULL) < 0) {
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 6c4dfde..502b389 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -30,6 +30,7 @@
#include "qemu_monitor.h"
#include "qemu_monitor_text.h"
+#include "qemu_monitor_json.h"
#include "qemu_conf.h"
#include "event.h"
#include "virterror_internal.h"
@@ -74,6 +75,7 @@ struct _qemuMonitor {
/* If the monitor is in process of shutting down */
unsigned closed: 1;
+ unsigned json: 1;
};
@@ -283,9 +285,14 @@ qemuMonitorIOProcess(qemuMonitorPtr mon)
msg = mon->msg;
VIR_DEBUG("Process %d", (int)mon->bufferOffset);
- len = qemuMonitorTextIOProcess(mon,
- mon->buffer, mon->bufferOffset,
- msg);
+ if (mon->json)
+ len = qemuMonitorJSONIOProcess(mon,
+ mon->buffer, mon->bufferOffset,
+ msg);
+ else
+ len = qemuMonitorTextIOProcess(mon,
+ mon->buffer, mon->bufferOffset,
+ msg);
if (len < 0) {
mon->lastErrno = errno;
@@ -534,6 +541,7 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque) {
qemuMonitorPtr
qemuMonitorOpen(virDomainObjPtr vm,
virDomainChrDefPtr config,
+ int json,
qemuMonitorEOFNotify eofCB)
{
qemuMonitorPtr mon;
@@ -560,6 +568,7 @@ qemuMonitorOpen(virDomainObjPtr vm,
mon->refs = 1;
mon->vm = vm;
mon->eofCB = eofCB;
+ mon->json = json;
qemuMonitorLock(mon);
virDomainObjRef(vm);
@@ -699,43 +708,68 @@ int
qemuMonitorStartCPUs(qemuMonitorPtr mon,
virConnectPtr conn)
{
+ int ret;
DEBUG("mon=%p, fd=%d", mon, mon->fd);
- return qemuMonitorTextStartCPUs(mon, conn);
+ if (mon->json)
+ ret = qemuMonitorJSONStartCPUs(mon, conn);
+ else
+ ret = qemuMonitorTextStartCPUs(mon, conn);
+ return ret;
}
int
qemuMonitorStopCPUs(qemuMonitorPtr mon)
{
+ int ret;
DEBUG("mon=%p, fd=%d", mon, mon->fd);
- return qemuMonitorTextStopCPUs(mon);
+ if (mon->json)
+ ret = qemuMonitorJSONStopCPUs(mon);
+ else
+ ret = qemuMonitorTextStopCPUs(mon);
+ return ret;
}
int qemuMonitorSystemPowerdown(qemuMonitorPtr mon)
{
+ int ret;
DEBUG("mon=%p, fd=%d", mon, mon->fd);
- return qemuMonitorTextSystemPowerdown(mon);
+ if (mon->json)
+ ret = qemuMonitorJSONSystemPowerdown(mon);
+ else
+ ret = qemuMonitorTextSystemPowerdown(mon);
+ return ret;
}
int qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
int **pids)
{
+ int ret;
DEBUG("mon=%p, fd=%d", mon, mon->fd);
- return qemuMonitorTextGetCPUInfo(mon, pids);
+ if (mon->json)
+ ret = qemuMonitorJSONGetCPUInfo(mon, pids);
+ else
+ ret = qemuMonitorTextGetCPUInfo(mon, pids);
+ return ret;
}
int qemuMonitorGetBalloonInfo(qemuMonitorPtr mon,
unsigned long *currmem)
{
+ int ret;
DEBUG("mon=%p, fd=%d", mon, mon->fd);
- return qemuMonitorTextGetBalloonInfo(mon, currmem);
+ if (mon->json)
+ ret = qemuMonitorJSONGetBalloonInfo(mon, currmem);
+ else
+ ret = qemuMonitorTextGetBalloonInfo(mon, currmem);
+ return ret;
}
@@ -747,38 +781,61 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
long long *wr_bytes,
long long *errs)
{
+ int ret;
DEBUG("mon=%p, fd=%d dev=%s", mon, mon->fd, devname);
- return qemuMonitorTextGetBlockStatsInfo(mon, devname,
- rd_req, rd_bytes,
- wr_req, wr_bytes,
- errs);
+ if (mon->json)
+ ret = qemuMonitorJSONGetBlockStatsInfo(mon, devname,
+ rd_req, rd_bytes,
+ wr_req, wr_bytes,
+ errs);
+ else
+ ret = qemuMonitorTextGetBlockStatsInfo(mon, devname,
+ rd_req, rd_bytes,
+ wr_req, wr_bytes,
+ errs);
+ return ret;
}
int qemuMonitorSetVNCPassword(qemuMonitorPtr mon,
const char *password)
{
+ int ret;
DEBUG("mon=%p, fd=%d", mon, mon->fd);
- return qemuMonitorTextSetVNCPassword(mon, password);
+ if (mon->json)
+ ret = qemuMonitorJSONSetVNCPassword(mon, password);
+ else
+ ret = qemuMonitorTextSetVNCPassword(mon, password);
+ return ret;
}
int qemuMonitorSetBalloon(qemuMonitorPtr mon,
unsigned long newmem)
{
+ int ret;
DEBUG("mon=%p, fd=%d newmem=%lu", mon, mon->fd, newmem);
- return qemuMonitorTextSetBalloon(mon, newmem);
+ if (mon->json)
+ ret = qemuMonitorJSONSetBalloon(mon, newmem);
+ else
+ ret = qemuMonitorTextSetBalloon(mon, newmem);
+ return ret;
}
int qemuMonitorEjectMedia(qemuMonitorPtr mon,
const char *devname)
{
+ int ret;
DEBUG("mon=%p, fd=%d devname=%s", mon, mon->fd, devname);
- return qemuMonitorTextEjectMedia(mon, devname);
+ if (mon->json)
+ ret = qemuMonitorJSONEjectMedia(mon, devname);
+ else
+ ret = qemuMonitorTextEjectMedia(mon, devname);
+ return ret;
}
@@ -787,10 +844,15 @@ int qemuMonitorChangeMedia(qemuMonitorPtr mon,
const char *newmedia,
const char *format)
{
+ int ret;
DEBUG("mon=%p, fd=%d devname=%s newmedia=%s format=%s",
mon, mon->fd, devname, newmedia, format);
- return qemuMonitorTextChangeMedia(mon, devname, newmedia, format);
+ if (mon->json)
+ ret = qemuMonitorJSONChangeMedia(mon, devname, newmedia, format);
+ else
+ ret = qemuMonitorTextChangeMedia(mon, devname, newmedia, format);
+ return ret;
}
@@ -799,10 +861,15 @@ int qemuMonitorSaveVirtualMemory(qemuMonitorPtr mon,
size_t length,
const char *path)
{
+ int ret;
DEBUG("mon=%p, fd=%d offset=%llu length=%zu path=%s",
mon, mon->fd, offset, length, path);
- return qemuMonitorTextSaveVirtualMemory(mon, offset, length, path);
+ if (mon->json)
+ ret = qemuMonitorJSONSaveVirtualMemory(mon, offset, length, path);
+ else
+ ret = qemuMonitorTextSaveVirtualMemory(mon, offset, length, path);
+ return ret;
}
int qemuMonitorSavePhysicalMemory(qemuMonitorPtr mon,
@@ -810,19 +877,29 @@ int qemuMonitorSavePhysicalMemory(qemuMonitorPtr mon,
size_t length,
const char *path)
{
+ int ret;
DEBUG("mon=%p, fd=%d offset=%llu length=%zu path=%s",
mon, mon->fd, offset, length, path);
- return qemuMonitorTextSavePhysicalMemory(mon, offset, length, path);
+ if (mon->json)
+ ret = qemuMonitorJSONSavePhysicalMemory(mon, offset, length, path);
+ else
+ ret = qemuMonitorTextSavePhysicalMemory(mon, offset, length, path);
+ return ret;
}
int qemuMonitorSetMigrationSpeed(qemuMonitorPtr mon,
unsigned long bandwidth)
{
+ int ret;
DEBUG("mon=%p, fd=%d bandwidth=%lu", mon, mon->fd, bandwidth);
- return qemuMonitorTextSetMigrationSpeed(mon, bandwidth);
+ if (mon->json)
+ ret = qemuMonitorJSONSetMigrationSpeed(mon, bandwidth);
+ else
+ ret = qemuMonitorTextSetMigrationSpeed(mon, bandwidth);
+ return ret;
}
int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon,
@@ -831,12 +908,20 @@ int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon,
unsigned long long *remaining,
unsigned long long *total)
{
+ int ret;
DEBUG("mon=%p, fd=%d", mon, mon->fd);
- return qemuMonitorTextGetMigrationStatus(mon, status,
- transferred,
- remaining,
- total);
+ if (mon->json)
+ ret = qemuMonitorJSONGetMigrationStatus(mon, status,
+ transferred,
+ remaining,
+ total);
+ else
+ ret = qemuMonitorTextGetMigrationStatus(mon, status,
+ transferred,
+ remaining,
+ total);
+ return ret;
}
@@ -845,10 +930,15 @@ int qemuMonitorMigrateToHost(qemuMonitorPtr mon,
const char *hostname,
int port)
{
+ int ret;
DEBUG("mon=%p, fd=%d hostname=%s port=%d",
mon, mon->fd, hostname, port);
- return qemuMonitorTextMigrateToHost(mon, background, hostname, port);
+ if (mon->json)
+ ret = qemuMonitorJSONMigrateToHost(mon, background, hostname, port);
+ else
+ ret = qemuMonitorTextMigrateToHost(mon, background, hostname, port);
+ return ret;
}
@@ -857,35 +947,55 @@ int qemuMonitorMigrateToCommand(qemuMonitorPtr mon,
const char * const *argv,
const char *target)
{
+ int ret;
DEBUG("mon=%p, fd=%d argv=%p target=%s",
mon, mon->fd, argv, target);
- return qemuMonitorTextMigrateToCommand(mon, background, argv, target);
+ if (mon->json)
+ ret = qemuMonitorJSONMigrateToCommand(mon, background, argv, target);
+ else
+ ret = qemuMonitorTextMigrateToCommand(mon, background, argv, target);
+ return ret;
}
int qemuMonitorMigrateToUnix(qemuMonitorPtr mon,
int background,
const char *unixfile)
{
+ int ret;
DEBUG("mon=%p fd=%d unixfile=%s",
mon, mon->fd, unixfile);
- return qemuMonitorTextMigrateToUnix(mon, background, unixfile);
+ if (mon->json)
+ ret = qemuMonitorJSONMigrateToUnix(mon, background, unixfile);
+ else
+ ret = qemuMonitorTextMigrateToUnix(mon, background, unixfile);
+ return ret;
}
int qemuMonitorMigrateCancel(qemuMonitorPtr mon)
{
+ int ret;
DEBUG("mon=%p fd=%d", mon, mon->fd);
- return qemuMonitorTextMigrateCancel(mon);
+ if (mon->json)
+ ret = qemuMonitorJSONMigrateCancel(mon);
+ else
+ ret = qemuMonitorTextMigrateCancel(mon);
+ return ret;
}
int qemuMonitorAddUSBDisk(qemuMonitorPtr mon,
const char *path)
{
+ int ret;
DEBUG("mon=%p, fd=%d path=%s", mon, mon->fd, path);
- return qemuMonitorTextAddUSBDisk(mon, path);
+ if (mon->json)
+ ret = qemuMonitorJSONAddUSBDisk(mon, path);
+ else
+ ret = qemuMonitorTextAddUSBDisk(mon, path);
+ return ret;
}
@@ -893,19 +1003,29 @@ int qemuMonitorAddUSBDeviceExact(qemuMonitorPtr mon,
int bus,
int dev)
{
+ int ret;
DEBUG("mon=%p, fd=%d bus=%d dev=%d", mon, mon->fd, bus, dev);
- return qemuMonitorTextAddUSBDeviceExact(mon, bus, dev);
+ if (mon->json)
+ ret = qemuMonitorJSONAddUSBDeviceExact(mon, bus, dev);
+ else
+ ret = qemuMonitorTextAddUSBDeviceExact(mon, bus, dev);
+ return ret;
}
int qemuMonitorAddUSBDeviceMatch(qemuMonitorPtr mon,
int vendor,
int product)
{
+ int ret;
DEBUG("mon=%p, fd=%d vendor=%d product=%d",
mon, mon->fd, vendor, product);
- return qemuMonitorTextAddUSBDeviceMatch(mon, vendor, product);
+ if (mon->json)
+ ret = qemuMonitorJSONAddUSBDeviceMatch(mon, vendor, product);
+ else
+ ret = qemuMonitorTextAddUSBDeviceMatch(mon, vendor, product);
+ return ret;
}
@@ -918,16 +1038,26 @@ int qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon,
unsigned *guestBus,
unsigned *guestSlot)
{
+ int ret;
DEBUG("mon=%p, fd=%d domain=%d bus=%d slot=%d function=%d",
mon, mon->fd,
hostDomain, hostBus, hostSlot, hostFunction);
- return qemuMonitorTextAddPCIHostDevice(mon, hostDomain,
- hostBus, hostSlot,
- hostFunction,
- guestDomain,
- guestBus,
- guestSlot);
+ if (mon->json)
+ ret = qemuMonitorJSONAddPCIHostDevice(mon, hostDomain,
+ hostBus, hostSlot,
+ hostFunction,
+ guestDomain,
+ guestBus,
+ guestSlot);
+ else
+ ret = qemuMonitorTextAddPCIHostDevice(mon, hostDomain,
+ hostBus, hostSlot,
+ hostFunction,
+ guestDomain,
+ guestBus,
+ guestSlot);
+ return ret;
}
@@ -938,11 +1068,17 @@ int qemuMonitorAddPCIDisk(qemuMonitorPtr mon,
unsigned *guestBus,
unsigned *guestSlot)
{
+ int ret;
DEBUG("mon=%p, fd=%d path=%s bus=%s",
mon, mon->fd, path, bus);
- return qemuMonitorTextAddPCIDisk(mon, path, bus,
- guestDomain, guestBus, guestSlot);
+ if (mon->json)
+ ret = qemuMonitorJSONAddPCIDisk(mon, path, bus,
+ guestDomain, guestBus, guestSlot);
+ else
+ ret = qemuMonitorTextAddPCIDisk(mon, path, bus,
+ guestDomain, guestBus, guestSlot);
+ return ret;
}
@@ -952,10 +1088,16 @@ int qemuMonitorAddPCINetwork(qemuMonitorPtr mon,
unsigned *guestBus,
unsigned *guestSlot)
{
+ int ret;
DEBUG("mon=%p, fd=%d nicstr=%s", mon, mon->fd, nicstr);
- return qemuMonitorTextAddPCINetwork(mon, nicstr, guestDomain,
- guestBus, guestSlot);
+ if (mon->json)
+ ret = qemuMonitorJSONAddPCINetwork(mon, nicstr, guestDomain,
+ guestBus, guestSlot);
+ else
+ ret = qemuMonitorTextAddPCINetwork(mon, nicstr, guestDomain,
+ guestBus, guestSlot);
+ return ret;
}
@@ -964,11 +1106,17 @@ int qemuMonitorRemovePCIDevice(qemuMonitorPtr mon,
unsigned guestBus,
unsigned guestSlot)
{
+ int ret;
DEBUG("mon=%p, fd=%d domain=%d bus=%d slot=%d",
mon, mon->fd, guestDomain, guestBus, guestSlot);
- return qemuMonitorTextRemovePCIDevice(mon, guestDomain,
- guestBus, guestSlot);
+ if (mon->json)
+ ret = qemuMonitorJSONRemovePCIDevice(mon, guestDomain,
+ guestBus, guestSlot);
+ else
+ ret = qemuMonitorTextRemovePCIDevice(mon, guestDomain,
+ guestBus, guestSlot);
+ return ret;
}
@@ -976,30 +1124,45 @@ int qemuMonitorSendFileHandle(qemuMonitorPtr mon,
const char *fdname,
int fd)
{
+ int ret;
DEBUG("mon=%p, fd=%d fdname=%s fd=%d",
mon, mon->fd, fdname, fd);
- return qemuMonitorTextSendFileHandle(mon, fdname, fd);
+ if (mon->json)
+ ret = qemuMonitorJSONSendFileHandle(mon, fdname, fd);
+ else
+ ret = qemuMonitorTextSendFileHandle(mon, fdname, fd);
+ return ret;
}
int qemuMonitorCloseFileHandle(qemuMonitorPtr mon,
const char *fdname)
{
+ int ret;
DEBUG("mon=%p, fd=%d fdname=%s",
mon, mon->fd, fdname);
- return qemuMonitorTextCloseFileHandle(mon, fdname);
+ if (mon->json)
+ ret = qemuMonitorJSONCloseFileHandle(mon, fdname);
+ else
+ ret = qemuMonitorTextCloseFileHandle(mon, fdname);
+ return ret;
}
int qemuMonitorAddHostNetwork(qemuMonitorPtr mon,
const char *netstr)
{
+ int ret;
DEBUG("mon=%p, fd=%d netstr=%s",
mon, mon->fd, netstr);
- return qemuMonitorTextAddHostNetwork(mon, netstr);
+ if (mon->json)
+ ret = qemuMonitorJSONAddHostNetwork(mon, netstr);
+ else
+ ret = qemuMonitorTextAddHostNetwork(mon, netstr);
+ return ret;
}
@@ -1007,8 +1170,13 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon,
int vlan,
const char *netname)
{
+ int ret;
DEBUG("mon=%p, fd=%d netname=%s",
mon, mon->fd, netname);
- return qemuMonitorTextRemoveHostNetwork(mon, vlan, netname);
+ if (mon->json)
+ ret = qemuMonitorJSONRemoveHostNetwork(mon, vlan, netname);
+ else
+ ret = qemuMonitorTextRemoveHostNetwork(mon, vlan, netname);
+ return ret;
}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 5f1a65d..0d9e315 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -80,6 +80,7 @@ char *qemuMonitorEscapeShell(const char *in);
qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm,
virDomainChrDefPtr config,
+ int json,
qemuMonitorEOFNotify eofCB);
int qemuMonitorClose(qemuMonitorPtr mon);
@@ -132,6 +133,9 @@ int qemuMonitorSetBalloon(qemuMonitorPtr mon,
/* XXX should we pass the virDomainDiskDefPtr instead
* and hide devname details inside monitor. Reconsider
* this when doing the QMP implementation
+ *
+ * XXXX 'eject' has gained a 'force' flag we might like
+ * to make use of...
*/
int qemuMonitorEjectMedia(qemuMonitorPtr mon,
const char *devname);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
new file mode 100644
index 0000000..9d71826
--- /dev/null
+++ b/src/qemu/qemu_monitor_json.c
@@ -0,0 +1,1423 @@
+/*
+ * qemu_monitor_json.c: interaction with QEMU monitor console
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <poll.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "qemu_monitor_json.h"
+#include "qemu_conf.h"
+#include "memory.h"
+#include "logging.h"
+#include "driver.h"
+#include "datatypes.h"
+#include "virterror_internal.h"
+#include "json.h"
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+
+#define LINE_ENDING "\r\n"
+
+static int
+qemuMonitorJSONIOProcessLine(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ const char *line,
+ qemuMonitorMessagePtr msg)
+{
+ virJSONValuePtr obj = NULL;
+ int ret = -1;
+
+ VIR_DEBUG("Line [%s]", line);
+
+ if (!(obj = virJSONValueFromString(line))) {
+ VIR_DEBUG0("Parsing JSON string failed");
+ errno = EINVAL;
+ goto cleanup;
+ }
+
+ if (obj->type != VIR_JSON_TYPE_OBJECT) {
+ VIR_DEBUG0("Parsed JSON string isn't an object");
+ errno = EINVAL;
+ }
+
+ if (virJSONValueObjectHasKey(obj, "QMP") == 1) {
+ VIR_DEBUG0("Got QMP capabilities data");
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectHasKey(obj, "event") == 1) {
+ VIR_DEBUG0("Got an event");
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (msg) {
+ msg->rxBuffer = strdup(line);
+ msg->rxLength = strlen(line);
+ msg->finished = 1;
+ } else {
+ VIR_DEBUG("Ignoring unexpected JSON message [%s]", line);
+ }
+
+ ret = 0;
+
+cleanup:
+ virJSONValueFree(obj);
+ return ret;
+}
+
+int qemuMonitorJSONIOProcess(qemuMonitorPtr mon,
+ const char *data,
+ size_t len,
+ qemuMonitorMessagePtr msg)
+{
+ int used = 0;
+ /*VIR_DEBUG("Data %d bytes [%s]", len, data);*/
+
+ while (used < len) {
+ char *nl = strstr(data + used, LINE_ENDING);
+
+ if (nl) {
+ int got = nl - (data + used);
+ char *line = strndup(data + used, got);
+ used += got + strlen(LINE_ENDING);
+ line[got] = '\0'; /* kill \n */
+ if (qemuMonitorJSONIOProcessLine(mon, line, msg) < 0) {
+ VIR_FREE(line);
+ return -1;
+ }
+
+ VIR_FREE(line);
+ } else {
+ break;
+ }
+ }
+
+ VIR_DEBUG("Total used %d bytes out of %d available in buffer", used, len);
+ return used;
+}
+
+static int
+qemuMonitorJSONCommandWithFd(qemuMonitorPtr mon,
+ virJSONValuePtr cmd,
+ int scm_fd,
+ virJSONValuePtr *reply)
+{
+ int ret = -1;
+ qemuMonitorMessage msg;
+ char *cmdstr = NULL;
+
+ *reply = NULL;
+
+ memset(&msg, 0, sizeof msg);
+
+ if (!(cmdstr = virJSONValueToString(cmd))) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+ if (virAsprintf(&msg.txBuffer, "%s\r\n", cmdstr) < 0) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+ msg.txLength = strlen(msg.txBuffer);
+ msg.txFD = scm_fd;
+
+ VIR_DEBUG("Send command '%s' for write with FD %d", cmdstr,
scm_fd);
+
+ ret = qemuMonitorSend(mon, &msg);
+
+ VIR_DEBUG("Receive command reply ret=%d errno=%d %d bytes '%s'",
+ ret, msg.lastErrno, msg.rxLength, msg.rxBuffer);
+
+
+ /* If we got ret==0, but not reply data something rather bad
+ * went wrong, so lets fake an EIO error */
+ if (!msg.rxBuffer && ret == 0) {
+ msg.lastErrno = EIO;
+ ret = -1;
+ }
+
+ if (ret == 0) {
+ if (!((*reply) = virJSONValueFromString(msg.rxBuffer))) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse JSON doc '%s'"),
msg.rxBuffer);
+ goto cleanup;
+ }
+ }
+
+ if (ret < 0)
+ virReportSystemError(NULL, msg.lastErrno,
+ _("cannot send monitor command '%s'"),
cmdstr);
+
+cleanup:
+ VIR_FREE(cmdstr);
+ VIR_FREE(msg.txBuffer);
+ VIR_FREE(msg.rxBuffer);
+
+ return ret;
+}
+
+
+static int
+qemuMonitorJSONCommand(qemuMonitorPtr mon,
+ virJSONValuePtr cmd,
+ virJSONValuePtr *reply) {
+ return qemuMonitorJSONCommandWithFd(mon, cmd, -1, reply);
+}
+
+/* Ignoring OOM in this method, since we're already reporting
+ * a more important error
+ *
+ * XXX see qerror.h for different klasses & fill out useful params
+ */
+static char *qemuMonitorJSONStringifyError(virJSONValuePtr error)
+{
+ char *klass = virJSONValueObjectGetString(error, "class");
+
+ if (klass) {
+ return strdup(klass);
+ } else {
+ return strdup(_("Missing QEMU error klass"));
+ }
+}
+
+static int
+qemuMonitorJSONCheckError(virJSONValuePtr cmd,
+ virJSONValuePtr reply)
+{
+ if (virJSONValueObjectHasKey(reply, "error")) {
+ virJSONValuePtr error = virJSONValueObjectGet(reply, "error");
+ char *cmdstr = virJSONValueToString(cmd);
+ char *replystr = virJSONValueToString(reply);
+
+ if (!error) {
+ VIR_DEBUG("Saw a JSON error, but value is null for %s: %s",
+ cmdstr, replystr);
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("error running QEMU command '%s':
'%s'"),
+ cmdstr, replystr);
+ } else {
+ VIR_DEBUG("Got a JSON error set for %s", cmdstr);
+ char *detail = qemuMonitorJSONStringifyError(error);
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("error running QEMU command '%s': %s
('%s')"),
+ cmdstr, detail, replystr);
+ VIR_FREE(detail);
+ }
+ VIR_FREE(cmdstr);
+ VIR_FREE(replystr);
+ return -1;
+ } else if (!virJSONValueObjectHasKey(reply, "return")) {
+ char *cmdstr = virJSONValueToString(cmd);
+ char *replystr = virJSONValueToString(reply);
+
+ VIR_DEBUG("Neither 'return' nor 'error' is set in the JSON
reply %s: %s",
+ cmdstr, replystr);
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("error running QEMU command '%s':
'%s'"), cmdstr, replystr);
+ VIR_FREE(cmdstr);
+ VIR_FREE(replystr);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+qemuMonitorJSONHasError(virJSONValuePtr reply,
+ const char *klass)
+{
+ virJSONValuePtr error;
+ char *thisklass;
+
+ if (!virJSONValueObjectHasKey(reply, "error"))
+ return 0;
+
+ error = virJSONValueObjectGet(reply, "error");
+ if (!error)
+ return 0;
+
+ if (!virJSONValueObjectHasKey(error, "class"))
+ return 0;
+
+ thisklass = virJSONValueObjectGetString(error, "class");
+
+ if (!thisklass)
+ return 0;
+
+ return STREQ(klass, thisklass);
+}
+
+static int
+qemuMonitorJSONCommandAddTimestamp(virJSONValuePtr obj)
+{
+ struct timeval tv;
+ virJSONValuePtr timestamp = NULL;
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ virReportSystemError(NULL, errno, "%s",
+ _("cannot query time of day"));
+ return -1;
+ }
+
+ if (!(timestamp = virJSONValueNewObject()))
+ goto no_memory;
+
+ if (virJSONValueObjectAppendNumberLong(timestamp, "seconds", tv.tv_sec)
< 0)
+ goto no_memory;
+ if (virJSONValueObjectAppendNumberLong(timestamp, "microseconds",
tv.tv_usec) < 0)
+ goto no_memory;
+
+ if (virJSONValueObjectAppend(obj, "timestamp", timestamp) < 0)
+ goto no_memory;
+
+ return 0;
+
+no_memory:
+ virReportOOMError(NULL);
+ virJSONValueFree(timestamp);
+ return -1;
+}
+
+static virJSONValuePtr
+qemuMonitorJSONMakeCommand(const char *cmdname,
+ ...)
+{
+ virJSONValuePtr obj;
+ virJSONValuePtr jargs = NULL;
+ va_list args;
+ char *key;
+
+ va_start(args, cmdname);
+
+ if (!(obj = virJSONValueNewObject()))
+ goto no_memory;
+
+ if (virJSONValueObjectAppendString(obj, "execute", cmdname) < 0)
+ goto no_memory;
+
+ if (qemuMonitorJSONCommandAddTimestamp(obj) < 0)
+ goto error;
+
+ while ((key = va_arg(args, char *)) != NULL) {
+ int ret;
+ char type;
+
+ if (strlen(key) < 3) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("argument key '%s' is too short, missing type
prefix"),
+ key);
+ goto error;
+ }
+
+ /* Keys look like s:name the first letter is a type code */
+ type = key[0];
+ key += 2;
+
+ if (!jargs &&
+ !(jargs = virJSONValueNewObject()))
+ goto no_memory;
+
+ /* This doesn't supports maps/arrays. This hasn't
+ * proved to be a problem..... yet :-) */
+ switch (type) {
+ case 's': {
+ char *val = va_arg(args, char *);
+ ret = virJSONValueObjectAppendString(jargs, key, val);
+ } break;
+ case 'i': {
+ int val = va_arg(args, int);
+ ret = virJSONValueObjectAppendNumberInt(jargs, key, val);
+ } break;
+ case 'u': {
+ unsigned int val = va_arg(args, unsigned int);
+ ret = virJSONValueObjectAppendNumberUint(jargs, key, val);
+ } break;
+ case 'I': {
+ long long val = va_arg(args, long long);
+ ret = virJSONValueObjectAppendNumberLong(jargs, key, val);
+ } break;
+ case 'U': {
+ unsigned long long val = va_arg(args, unsigned long long);
+ ret = virJSONValueObjectAppendNumberUlong(jargs, key, val);
+ } break;
+ case 'd': {
+ double val = va_arg(args, double);
+ ret = virJSONValueObjectAppendNumberDouble(jargs, key, val);
+ } break;
+ case 'b': {
+ int val = va_arg(args, int);
+ ret = virJSONValueObjectAppendBoolean(jargs, key, val);
+ } break;
+ case 'n': {
+ ret = virJSONValueObjectAppendNull(jargs, key);
+ } break;
+ default:
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported data type '%c' for arg
'%s'"), type, key - 2);
+ goto error;
+ }
+ if (ret < 0)
+ goto no_memory;
+ }
+
+ if (jargs &&
+ virJSONValueObjectAppend(obj, "arguments", jargs) < 0)
+ goto no_memory;
+
+ va_end(args);
+
+ return obj;
+
+no_memory:
+ virReportOOMError(NULL);
+error:
+ virJSONValueFree(obj);
+ virJSONValueFree(jargs);
+ va_end(args);
+ return NULL;
+}
+
+
+int
+qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
+ virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("cont", NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int
+qemuMonitorJSONStopCPUs(qemuMonitorPtr mon)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("stop", NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("system_powerdown",
NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon,
+ int **pids)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("info",
+ "s:item",
"cpus",
+ NULL);
+ virJSONValuePtr reply = NULL;
+
+ *pids = NULL;
+
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ /* XXX extract PIDs if present - QEMU hasn't implement this yet :-( */
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+/*
+ * Returns: 0 if balloon not supported, +1 if balloon query worked
+ * or -1 on failure
+ */
+int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
+ unsigned long *currmem)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("info",
+ "s:item",
"balloon",
+ NULL);
+ virJSONValuePtr reply = NULL;
+
+ *currmem = 0;
+
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0) {
+ /* See if balloon soft-failed */
+ if (qemuMonitorJSONHasError(reply, "DeviceNotActive") ||
+ qemuMonitorJSONHasError(reply, "KVMMissingCap"))
+ goto cleanup;
+
+ /* See if any other fatal error occurred */
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ /* Success */
+ if (ret == 0) {
+ unsigned long long mem;
+
+ if (virJSONValueObjectGetNumberUlong(reply, "return", &mem)
< 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
"%s",
+ _("info balloon reply was missing mem return
data"));
+ ret = -1;
+ goto cleanup;
+ }
+
+ *currmem = mem;
+ ret = 1;
+ }
+ }
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
+ const char *devname,
+ long long *rd_req,
+ long long *rd_bytes,
+ long long *wr_req,
+ long long *wr_bytes,
+ long long *errs)
+{
+ int ret;
+ int i;
+ int found = 0;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("info",
+ "s:item",
"blockstats",
+ NULL);
+ virJSONValuePtr reply = NULL;
+ virJSONValuePtr devices;
+
+ *rd_req = *rd_bytes = *wr_req = *wr_bytes = *errs = 0;
+
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0) {
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+ if (ret < 0)
+ goto cleanup;
+ }
+ ret = -1;
+
+ devices = virJSONValueObjectGet(reply, "return");
+ if (!devices || devices->type != VIR_JSON_TYPE_ARRAY) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("blockstats reply was missing device list"));
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < virJSONValueArraySize(devices) ; i++) {
+ virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
+ virJSONValuePtr stats;
+ const char *thisdev;
+ if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("blockstats device entry was not in expected
format"));
+ goto cleanup;
+ }
+
+ if ((thisdev = virJSONValueObjectGetString(dev, "device")) == NULL) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("blockstats device entry was not in expected
format"));
+ goto cleanup;
+ }
+
+ if (STRNEQ(thisdev, devname))
+ continue;
+
+ found = 1;
+ if ((stats = virJSONValueObjectGet(dev, "stats")) == NULL ||
+ stats->type != VIR_JSON_TYPE_OBJECT) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("blockstats stats entry was not in expected
format"));
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectGetNumberLong(stats, "rd_bytes", rd_bytes) <
0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s statistic"),
+ "rd_bytes");
+ goto cleanup;
+ }
+ if (virJSONValueObjectGetNumberLong(stats, "rd_operations", rd_req)
< 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s statistic"),
+ "rd_operations");
+ goto cleanup;
+ }
+ if (virJSONValueObjectGetNumberLong(stats, "wr_bytes", wr_bytes) <
0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s statistic"),
+ "wr_bytes");
+ goto cleanup;
+ }
+ if (virJSONValueObjectGetNumberLong(stats, "wr_operations", wr_req)
< 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s statistic"),
+ "wr_operations");
+ goto cleanup;
+ }
+ }
+
+ if (!found) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("cannot find statistics for device '%s'"),
devname);
+ goto cleanup;
+ }
+ ret = 0;
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon,
+ const char *password)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("change",
+ "s:device",
"vnc",
+ "s:target",
"password",
+ "s:arg", password,
+ NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+/*
+ * Returns: 0 if balloon not supported, +1 if balloon adjust worked
+ * or -1 on failure
+ */
+int qemuMonitorJSONSetBalloon(qemuMonitorPtr mon,
+ unsigned long newmem)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("balloon",
+ "U:value", (unsigned long
long)newmem,
+ NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0) {
+ /* See if balloon soft-failed */
+ if (qemuMonitorJSONHasError(reply, "DeviceNotActive") ||
+ qemuMonitorJSONHasError(reply, "KVMMissingCap"))
+ goto cleanup;
+
+ /* See if any other fatal error occurred */
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ /* Real success */
+ if (ret == 0)
+ ret = 1;
+ }
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONEjectMedia(qemuMonitorPtr mon,
+ const char *devname)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("eject",
+ "s:device", devname,
+ "i:force", 0,
+ NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONChangeMedia(qemuMonitorPtr mon,
+ const char *devname,
+ const char *newmedia,
+ const char *format)
+{
+ int ret;
+ virJSONValuePtr cmd;
+ if (format)
+ cmd = qemuMonitorJSONMakeCommand("change",
+ "s:device", devname,
+ "s:target", newmedia,
+ "s:arg", format,
+ NULL);
+ else
+ cmd = qemuMonitorJSONMakeCommand("change",
+ "s:device", devname,
+ "s:target", newmedia,
+ NULL);
+
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+static int qemuMonitorJSONSaveMemory(qemuMonitorPtr mon,
+ const char *cmdtype,
+ unsigned long long offset,
+ size_t length,
+ const char *path)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand(cmdtype,
+ "U:val", offset,
+ "u:size", length,
+ "s:filename", path,
+ NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONSaveVirtualMemory(qemuMonitorPtr mon,
+ unsigned long long offset,
+ size_t length,
+ const char *path)
+{
+ return qemuMonitorJSONSaveMemory(mon, "memsave", offset, length, path);
+}
+
+int qemuMonitorJSONSavePhysicalMemory(qemuMonitorPtr mon,
+ unsigned long long offset,
+ size_t length,
+ const char *path)
+{
+ return qemuMonitorJSONSaveMemory(mon, "pmemsave", offset, length, path);
+}
+
+
+int qemuMonitorJSONSetMigrationSpeed(qemuMonitorPtr mon,
+ unsigned long bandwidth)
+{
+ int ret;
+ char *bandwidthstr;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+ if (virAsprintf(&bandwidthstr, "%lum", bandwidth) < 0) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+ cmd = qemuMonitorJSONMakeCommand("migrate_set_speed",
+ "s:value", bandwidthstr,
+ NULL);
+ VIR_FREE(bandwidthstr);
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+static int
+qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply,
+ int *status,
+ unsigned long long *transferred,
+ unsigned long long *remaining,
+ unsigned long long *total)
+{
+ virJSONValuePtr ret;
+ char *statusstr;
+
+ if (!(ret = virJSONValueObjectGet(reply, "return"))) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("info migration reply was missing return data"));
+ return -1;
+ }
+
+ if (!(statusstr = virJSONValueObjectGetString(ret, "status"))) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("info migration reply was missing return status"));
+ return -1;
+ }
+
+ if ((*status = qemuMonitorMigrationStatusTypeFromString(statusstr)) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected migration status in %s"), statusstr);
+ return -1;
+ }
+
+ if (*status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE) {
+ virJSONValuePtr ram = virJSONValueObjectGet(ret, "ram");
+ if (!ram) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("migration was active, but no RAM info was
set"));
+ return -1;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(ram, "transferred", transferred)
< 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("migration was active, but RAM 'transferred'
data was missing"));
+ return -1;
+ }
+ if (virJSONValueObjectGetNumberUlong(ram, "remaining", remaining) <
0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("migration was active, but RAM 'remaining'
data was missing"));
+ return -1;
+ }
+ if (virJSONValueObjectGetNumberUlong(ram, "total", total) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("migration was active, but RAM 'total' data
was missing"));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon,
+ int *status,
+ unsigned long long *transferred,
+ unsigned long long *remaining,
+ unsigned long long *total)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("info",
+ "s:item",
"migration",
+ NULL);
+ virJSONValuePtr reply = NULL;
+
+ *status = 0;
+ *transferred = *remaining = *total = 0;
+
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ if (ret == 0 &&
+ qemuMonitorJSONGetMigrationStatusReply(reply,
+ status,
+ transferred,
+ remaining,
+ total) < 0)
+ ret = -1;
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+static int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
+ int background,
+ const char *uri)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("migrate",
+ "i:detach", background ? 1
: 0,
+ "s:uri", uri,
+ NULL);
+ virJSONValuePtr reply = NULL;
+
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONMigrateToHost(qemuMonitorPtr mon,
+ int background,
+ const char *hostname,
+ int port)
+{
+ char *uri = NULL;
+ int ret;
+
+ if (virAsprintf(&uri, "tcp:%s:%d", hostname, port) < 0) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ ret = qemuMonitorJSONMigrate(mon, background, uri);
+
+ VIR_FREE(uri);
+
+ return ret;
+}
+
+
+int qemuMonitorJSONMigrateToCommand(qemuMonitorPtr mon,
+ int background,
+ const char * const *argv,
+ const char *target)
+{
+ char *argstr;
+ char *dest = NULL;
+ int ret = -1;
+ char *safe_target = NULL;
+
+ argstr = virArgvToString(argv);
+ if (!argstr) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ /* Migrate to file */
+ safe_target = qemuMonitorEscapeShell(target);
+ if (!safe_target) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ if (virAsprintf(&dest, "exec:%s >>%s 2>/dev/null", argstr,
safe_target) < 0) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ ret = qemuMonitorJSONMigrate(mon, background, dest);
+
+cleanup:
+ VIR_FREE(safe_target);
+ VIR_FREE(argstr);
+ VIR_FREE(dest);
+ return ret;
+}
+
+int qemuMonitorJSONMigrateToUnix(qemuMonitorPtr mon,
+ int background,
+ const char *unixfile)
+{
+ char *dest = NULL;
+ int ret = -1;
+
+ if (virAsprintf(&dest, "unix:%s", unixfile) < 0) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ ret = qemuMonitorJSONMigrate(mon, background, dest);
+
+ VIR_FREE(dest);
+
+ return ret;
+}
+
+
+int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("migrate_cancel", NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+static int qemuMonitorJSONAddUSB(qemuMonitorPtr mon,
+ const char *dev)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("usb_add",
+ "s:devname", dev,
+ NULL);
+ virJSONValuePtr reply = NULL;
+
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONAddUSBDisk(qemuMonitorPtr mon,
+ const char *path)
+{
+ int ret;
+ char *disk;
+
+ if (virAsprintf(&disk, "disk:%s", path) < 0) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ ret = qemuMonitorJSONAddUSB(mon, disk);
+
+ VIR_FREE(disk);
+
+ return ret;
+}
+
+
+int qemuMonitorJSONAddUSBDeviceExact(qemuMonitorPtr mon,
+ int bus ATTRIBUTE_UNUSED,
+ int dev ATTRIBUTE_UNUSED)
+{
+ int ret;
+ char *addr;
+
+ if (virAsprintf(&addr, "host:%.3d.%.3d", bus, dev) < 0) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ ret = qemuMonitorJSONAddUSB(mon, addr);
+
+ VIR_FREE(addr);
+ return ret;
+}
+
+
+int qemuMonitorJSONAddUSBDeviceMatch(qemuMonitorPtr mon,
+ int vendor ATTRIBUTE_UNUSED,
+ int product ATTRIBUTE_UNUSED)
+{
+ int ret;
+ char *addr;
+
+ if (virAsprintf(&addr, "host:%.4x:%.4x", vendor, product) < 0) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ ret = qemuMonitorJSONAddUSB(mon, addr);
+
+ VIR_FREE(addr);
+ return ret;
+}
+
+
+/* XXX qemu also returns a 'function' number now */
+static int
+qemuMonitorJSONGetGuestAddress(virJSONValuePtr reply,
+ unsigned *guestDomain,
+ unsigned *guestBus,
+ unsigned *guestSlot)
+{
+ virJSONValuePtr addr;
+
+ addr = virJSONValueObjectGet(reply, "return");
+ if (!addr || addr->type != VIR_JSON_TYPE_OBJECT) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("pci_add reply was missing device address"));
+ return -1;
+ }
+
+ if (virJSONValueObjectGetNumberUint(addr, "domain", guestDomain) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("pci_add reply was missing device domain number"));
+ return -1;
+ }
+
+ if (virJSONValueObjectGetNumberUint(addr, "bus", guestBus) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("pci_add reply was missing device bus number"));
+ return -1;
+ }
+
+ if (virJSONValueObjectGetNumberUint(addr, "slot", guestSlot) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("pci_add reply was missing device slot number"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon,
+ unsigned hostDomain ATTRIBUTE_UNUSED,
+ unsigned hostBus,
+ unsigned hostSlot,
+ unsigned hostFunction,
+ unsigned *guestDomain,
+ unsigned *guestBus,
+ unsigned *guestSlot)
+{
+ int ret;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+ char *dev;
+
+ *guestDomain = *guestBus = *guestSlot = 0;
+
+ /* XXX hostDomain */
+ if (virAsprintf(&dev, "host=%.2x:%.2x.%.1x",
+ hostBus, hostSlot, hostFunction) < 0) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ cmd = qemuMonitorJSONMakeCommand("pci_add",
+ "s:pci_addr", "auto"
+ "s:type", "host",
+ "s:opts", dev,
+ NULL);
+ VIR_FREE(dev);
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ if (ret == 0 &&
+ qemuMonitorJSONGetGuestAddress(reply, guestDomain, guestBus, guestSlot) < 0)
+ ret = -1;
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon,
+ const char *path,
+ const char *bus,
+ unsigned *guestDomain,
+ unsigned *guestBus,
+ unsigned *guestSlot) {
+ int ret;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+ char *dev;
+
+ *guestDomain = *guestBus = *guestSlot = 0;
+
+ if (virAsprintf(&dev, "file=%s,if=%s", path, bus) < 0) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ cmd = qemuMonitorJSONMakeCommand("pci_add",
+ "s:pci_addr", "auto",
+ "s:type", "storage",
+ "s:opts", dev,
+ NULL);
+ VIR_FREE(dev);
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ if (ret == 0 &&
+ qemuMonitorJSONGetGuestAddress(reply, guestDomain, guestBus, guestSlot) < 0)
+ ret = -1;
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon,
+ const char *nicstr,
+ unsigned *guestDomain,
+ unsigned *guestBus,
+ unsigned *guestSlot)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("pci_add",
+ "s:pci_addr",
"auto",
+ "s:type",
"nic",
+ "s:opts", nicstr,
+ NULL);
+ virJSONValuePtr reply = NULL;
+
+ *guestDomain = *guestBus = *guestSlot = 0;
+
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ if (ret == 0 &&
+ qemuMonitorJSONGetGuestAddress(reply, guestDomain, guestBus, guestSlot) < 0)
+ ret = -1;
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONRemovePCIDevice(qemuMonitorPtr mon,
+ unsigned guestDomain,
+ unsigned guestBus,
+ unsigned guestSlot)
+{
+ int ret;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+ char *addr;
+
+ if (virAsprintf(&addr, "%.4x:%.2x:%.2x",
+ guestDomain, guestBus, guestSlot) < 0) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ cmd = qemuMonitorJSONMakeCommand("pci_del",
+ "s:pci_addr", addr,
+ NULL);
+ VIR_FREE(addr);
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONSendFileHandle(qemuMonitorPtr mon,
+ const char *fdname,
+ int fd)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("getfd",
+ "s:fdname", fdname,
+ NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommandWithFd(mon, cmd, fd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONCloseFileHandle(qemuMonitorPtr mon,
+ const char *fdname)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("closefd",
+ "s:fdname", fdname,
+ NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONAddHostNetwork(qemuMonitorPtr mon,
+ const char *netstr)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("host_net_add",
+ "s:device", netstr,
+ NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int qemuMonitorJSONRemoveHostNetwork(qemuMonitorPtr mon,
+ int vlan,
+ const char *netname)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("host_net_remove",
+ "i:vlan", vlan,
+ "s:device", netname,
+ NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
new file mode 100644
index 0000000..62a88c0
--- /dev/null
+++ b/src/qemu/qemu_monitor_json.h
@@ -0,0 +1,156 @@
+/*
+ * qemu_monitor_json.h: interaction with QEMU monitor console
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+
+#ifndef QEMU_MONITOR_JSON_H
+#define QEMU_MONITOR_JSON_H
+
+#include "internal.h"
+
+#include "qemu_monitor.h"
+
+int qemuMonitorJSONIOProcess(qemuMonitorPtr mon,
+ const char *data,
+ size_t len,
+ qemuMonitorMessagePtr msg);
+
+int qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
+ virConnectPtr conn);
+int qemuMonitorJSONStopCPUs(qemuMonitorPtr mon);
+
+int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
+
+int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon,
+ int **pids);
+int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
+ unsigned long *currmem);
+int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
+ const char *devname,
+ long long *rd_req,
+ long long *rd_bytes,
+ long long *wr_req,
+ long long *wr_bytes,
+ long long *errs);
+
+
+int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon,
+ const char *password);
+int qemuMonitorJSONSetBalloon(qemuMonitorPtr mon,
+ unsigned long newmem);
+
+int qemuMonitorJSONEjectMedia(qemuMonitorPtr mon,
+ const char *devname);
+int qemuMonitorJSONChangeMedia(qemuMonitorPtr mon,
+ const char *devname,
+ const char *newmedia,
+ const char *format);
+
+
+int qemuMonitorJSONSaveVirtualMemory(qemuMonitorPtr mon,
+ unsigned long long offset,
+ size_t length,
+ const char *path);
+int qemuMonitorJSONSavePhysicalMemory(qemuMonitorPtr mon,
+ unsigned long long offset,
+ size_t length,
+ const char *path);
+
+int qemuMonitorJSONSetMigrationSpeed(qemuMonitorPtr mon,
+ unsigned long bandwidth);
+
+int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon,
+ int *status,
+ unsigned long long *transferred,
+ unsigned long long *remaining,
+ unsigned long long *total);
+
+int qemuMonitorJSONMigrateToHost(qemuMonitorPtr mon,
+ int background,
+ const char *hostname,
+ int port);
+
+int qemuMonitorJSONMigrateToCommand(qemuMonitorPtr mon,
+ int background,
+ const char * const *argv,
+ const char *target);
+
+int qemuMonitorJSONMigrateToUnix(qemuMonitorPtr mon,
+ int background,
+ const char *unixfile);
+
+int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon);
+
+int qemuMonitorJSONAddUSBDisk(qemuMonitorPtr mon,
+ const char *path);
+
+int qemuMonitorJSONAddUSBDeviceExact(qemuMonitorPtr mon,
+ int bus,
+ int dev);
+int qemuMonitorJSONAddUSBDeviceMatch(qemuMonitorPtr mon,
+ int vendor,
+ int product);
+
+
+int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon,
+ unsigned hostDomain,
+ unsigned hostBus,
+ unsigned hostSlot,
+ unsigned hostFunction,
+ unsigned *guestDomain,
+ unsigned *guestBus,
+ unsigned *guestSlot);
+
+int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon,
+ const char *path,
+ const char *bus,
+ unsigned *guestDomain,
+ unsigned *guestBus,
+ unsigned *guestSlot);
+
+int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon,
+ const char *nicstr,
+ unsigned *guestDomain,
+ unsigned *guestBus,
+ unsigned *guestSlot);
+
+int qemuMonitorJSONRemovePCIDevice(qemuMonitorPtr mon,
+ unsigned guestDomain,
+ unsigned guestBus,
+ unsigned guestSlot);
+
+
+int qemuMonitorJSONSendFileHandle(qemuMonitorPtr mon,
+ const char *fdname,
+ int fd);
+
+int qemuMonitorJSONCloseFileHandle(qemuMonitorPtr mon,
+ const char *fdname);
+
+int qemuMonitorJSONAddHostNetwork(qemuMonitorPtr mon,
+ const char *netstr);
+
+int qemuMonitorJSONRemoveHostNetwork(qemuMonitorPtr mon,
+ int vlan,
+ const char *netname);
+
+#endif /* QEMU_MONITOR_JSON_H */
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 677c5b4..c39cbbc 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -60,7 +60,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
goto fail;
if (qemudBuildCommandLine(NULL, &driver,
- vmdef, &monitor_chr, flags,
+ vmdef, &monitor_chr, 0, flags,
&argv, &qenv,
NULL, NULL, migrateFrom) < 0)
goto fail;
--
1.6.5.2