Use the new virDomainUpdateDeviceFlags API to allow the VNC password
to be changed on the fly
* src/internal.h: Define STREQ_NULLABLE() which is like STREQ()
but does not crash if either argument is NULL, and treats two
NULLs as equal.
* src/libvirt_private.syms: Export virDomainGraphicsTypeToString
* src/qemu/qemu_driver.c: Support VNC password change on a live
machine
* src/qemu/qemu_monitor.c: Disable crazy debugging info. Treat a
NULL password as "" (empty string), allowing passwords to be
disabled in the monitor
---
src/internal.h | 6 +++
src/libvirt_private.syms | 1 +
src/qemu/qemu_driver.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor.c | 17 ++++++++-
4 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/src/internal.h b/src/internal.h
index 4ec6edc..f82fbd2 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -58,6 +58,12 @@
# define STRCASENEQLEN(a,b,n) (strncasecmp(a,b,n) != 0)
# define STRPREFIX(a,b) (strncmp(a,b,strlen(b)) == 0)
+# define STREQ_NULLABLE(a, b) \
+ ((!(a) && !(b)) || ((a) && (b) && STREQ((a), (b))))
+# define STRNEQ_NULLABLE(a, b) \
+ ((!(a) ^ !(b)) || ((a) && (b) && STRNEQ((a), (b))))
+
+
# define NUL_TERMINATE(buf) do { (buf)[sizeof(buf)-1] = '\0'; } while (0)
# define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index f1ad6db..fe78743 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -139,6 +139,7 @@ virDomainFindByName;
virDomainFindByUUID;
virDomainGetRootFilesystem;
virDomainGraphicsTypeFromString;
+virDomainGraphicsTypeToString;
virDomainGraphicsDefFree;
virDomainHostdevDefFree;
virDomainHostdevModeTypeToString;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b9cfae0..57fb941 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6820,6 +6820,83 @@ static int qemudDomainAttachDeviceFlags(virDomainPtr dom,
}
+static virDomainGraphicsDefPtr qemuDomainFindGraphics(virDomainObjPtr vm,
+ virDomainGraphicsDefPtr dev)
+{
+ int i;
+
+ for (i = 0 ; i < vm->def->ngraphics ; i++) {
+ if (vm->def->graphics[i]->type == dev->type)
+ return vm->def->graphics[i];
+ }
+
+ return NULL;
+}
+
+
+static int
+qemuDomainChangeGraphics(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainGraphicsDefPtr dev)
+{
+ virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ int ret = -1;
+
+ if (!olddev) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot find existing graphics device to modify"));
+ return -1;
+ }
+
+ switch (dev->type) {
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ if ((olddev->data.vnc.autoport != dev->data.vnc.autoport) ||
+ (!dev->data.vnc.autoport && (olddev->data.vnc.port !=
dev->data.vnc.port))) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot change port settings on vnc graphics"));
+ return -1;
+ }
+ if (STRNEQ_NULLABLE(olddev->data.vnc.listenAddr, dev->data.vnc.listenAddr))
{
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot change listen address setting on vnc
graphics"));
+ return -1;
+ }
+ if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot change keymap setting on vnc
graphics"));
+ return -1;
+ }
+
+ if (STRNEQ_NULLABLE(olddev->data.vnc.passwd, dev->data.vnc.passwd)) {
+ VIR_DEBUG("Updating password on VNC server %p %p",
dev->data.vnc.passwd, driver->vncPassword);
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ ret = qemuMonitorSetVNCPassword(priv->mon,
+ dev->data.vnc.passwd ?
+ dev->data.vnc.passwd :
+ driver->vncPassword);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+ /* Steal the new dev's char * reference */
+ VIR_FREE(olddev->data.vnc.passwd);
+ olddev->data.vnc.passwd = dev->data.vnc.passwd;
+ dev->data.vnc.passwd = NULL;
+ } else {
+ ret = 0;
+ }
+ break;
+
+ default:
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unable to change config on '%s' graphics
type"),
+ virDomainGraphicsTypeToString(dev->type));
+ break;
+ }
+
+ return ret;
+}
+
+
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
const char *xml,
unsigned int flags)
@@ -6908,6 +6985,10 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
}
break;
+ case VIR_DOMAIN_DEVICE_GRAPHICS:
+ ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
+ break;
+
default:
qemuReportError(VIR_ERR_NO_SUPPORT,
_("disk device type '%s' cannot be updated"),
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 6b68db8..fe95afd 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -39,7 +39,8 @@
#define VIR_FROM_THIS VIR_FROM_QEMU
-#define QEMU_DEBUG_RAW_IO 0
+#define DEBUG_IO 0
+#define DEBUG_RAW_IO 0
struct _qemuMonitor {
virMutex lock;
@@ -302,7 +303,8 @@ qemuMonitorIOProcess(qemuMonitorPtr mon)
if (mon->msg && mon->msg->txOffset == mon->msg->txLength)
msg = mon->msg;
-#if QEMU_DEBUG_RAW_IO
+#if DEBUG_IO
+#if DEBUG_RAW_IO
char *str1 = qemuMonitorEscapeNonPrintable(msg ? msg->txBuffer : "");
char *str2 = qemuMonitorEscapeNonPrintable(mon->buffer);
VIR_ERROR("Process %d %p %p [[[[%s]]][[[%s]]]", (int)mon->bufferOffset,
mon->msg, msg, str1, str2);
@@ -311,6 +313,8 @@ qemuMonitorIOProcess(qemuMonitorPtr mon)
#else
VIR_DEBUG("Process %d", (int)mon->bufferOffset);
#endif
+#endif
+
if (mon->json)
len = qemuMonitorJSONIOProcess(mon,
mon->buffer, mon->bufferOffset,
@@ -332,7 +336,9 @@ qemuMonitorIOProcess(qemuMonitorPtr mon)
VIR_FREE(mon->buffer);
mon->bufferOffset = mon->bufferLength = 0;
}
+#if DEBUG_IO
VIR_DEBUG("Process done %d used %d", (int)mon->bufferOffset, len);
+#endif
if (msg && msg->finished)
virCondBroadcast(&mon->notify);
return len;
@@ -455,7 +461,9 @@ qemuMonitorIORead(qemuMonitorPtr mon)
mon->buffer[mon->bufferOffset] = '\0';
}
+#if DEBUG_IO
VIR_DEBUG("Now read %d bytes of data", (int)mon->bufferOffset);
+#endif
return ret;
}
@@ -485,7 +493,9 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque) {
qemuMonitorLock(mon);
qemuMonitorRef(mon);
+#if DEBUG_IO
VIR_DEBUG("Monitor %p I/O on watch %d fd %d events %d", mon, watch, fd,
events);
+#endif
if (mon->fd != fd || mon->watch != watch) {
VIR_ERROR("event from unexpected fd %d!=%d / watch %d!=%d", mon->fd,
fd, mon->watch, watch);
@@ -904,6 +914,9 @@ int qemuMonitorSetVNCPassword(qemuMonitorPtr mon,
int ret;
DEBUG("mon=%p, fd=%d", mon, mon->fd);
+ if (!password)
+ password = "";
+
if (mon->json)
ret = qemuMonitorJSONSetVNCPassword(mon, password);
else
--
1.6.6.1