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..a636fe5 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) || (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 c5ee23d..989152d 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..8ebbbe2 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", 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list