diff --git a/src/internal.h b/src/internal.h index 4ec6edcda2e9fa4f9af10ca899d75a703fa74453..f82fbd253387585a04f70f3d12de6f3216fa52de 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 cf6670dd06a2d1ceaba69d0677507f8a0925f6ce..0033d2a3733cc4603ce249b9da24152966b10341 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 75ee98b8747a4f81911a47b75b92462ed9892f6c..5b263a7d8e2b9642c08ae24a921452affe735cc2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7046,6 +7046,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) @@ -7134,6 +7211,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 f998d77d7b5b7335ecde0a583842b87994e011d1..2877a00135033b6d51efea9a7bd95cdaa3a8923b 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); @@ -981,6 +991,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