On Sat, Nov 10, 2012 at 02:40:23 +0100, Alon Levy wrote: > The check for a single display remains so no new functionality is added. > --- > v2 changes: > removed enum, use virReportOOMError directly. > use --patience > added a one line label fix patch. > > The second patch changes a string that needs to be translated - how do I go about it? > > src/qemu/qemu_command.c | 641 +++++++++++++++++++++++++----------------------- > src/qemu/qemu_process.c | 70 +++--- > 2 files changed, 364 insertions(+), 347 deletions(-) > > diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c > index 1e96982..ba99c7a 100644 > --- a/src/qemu/qemu_command.c > +++ b/src/qemu/qemu_command.c > @@ -4410,6 +4410,331 @@ error: > return -1; > } > > +static int > +qemuBuildGraphicsCommandLine(struct qemud_driver *driver, > + virCommandPtr cmd, > + virDomainDefPtr def, > + qemuCapsPtr caps, > + virDomainGraphicsDefPtr graphics) > +{ > + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { > + virBuffer opt = VIR_BUFFER_INITIALIZER; > + > + if (!qemuCapsGet(caps, QEMU_CAPS_VNC)) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > + _("vnc graphics are not supported with this QEMU")); > + goto error; > + } > + > + if (graphics->data.vnc.socket || > + driver->vncAutoUnixSocket) { > + > + if (!graphics->data.vnc.socket && > + virAsprintf(&graphics->data.vnc.socket, > + "%s/%s.vnc", driver->libDir, def->name) == -1) { > + goto no_memory; > + } > + > + virBufferAsprintf(&opt, "unix:%s", > + graphics->data.vnc.socket); > + > + } else if (qemuCapsGet(caps, QEMU_CAPS_VNC_COLON)) { > + const char *listenNetwork; > + const char *listenAddr = NULL; > + char *netAddr = NULL; > + bool escapeAddr; > + int ret; > + > + switch (virDomainGraphicsListenGetType(graphics, 0)) { > + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: > + listenAddr = virDomainGraphicsListenGetAddress(graphics, 0); > + break; > + > + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: > + listenNetwork = virDomainGraphicsListenGetNetwork(graphics, 0); > + if (!listenNetwork) > + break; > + ret = networkGetNetworkAddress(listenNetwork, &netAddr); > + if (ret <= -2) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + "%s", _("network-based listen not possible, " > + "network driver not present")); > + goto error; > + } > + if (ret < 0) { > + virReportError(VIR_ERR_XML_ERROR, > + _("listen network '%s' had no usable address"), > + listenNetwork); > + goto error; > + } > + listenAddr = netAddr; > + /* store the address we found in the <graphics> element so it will > + * show up in status. */ > + if (virDomainGraphicsListenSetAddress(graphics, 0, > + listenAddr, -1, false) < 0) > + goto error; > + break; > + } > + > + if (!listenAddr) > + listenAddr = driver->vncListen; > + > + escapeAddr = strchr(listenAddr, ':') != NULL; > + if (escapeAddr) > + virBufferAsprintf(&opt, "[%s]", listenAddr); > + else > + virBufferAdd(&opt, listenAddr, -1); > + virBufferAsprintf(&opt, ":%d", > + graphics->data.vnc.port - 5900); > + > + VIR_FREE(netAddr); > + } else { > + virBufferAsprintf(&opt, "%d", > + graphics->data.vnc.port - 5900); > + } > + > + if (qemuCapsGet(caps, QEMU_CAPS_VNC_COLON)) { > + if (graphics->data.vnc.auth.passwd || > + driver->vncPassword) > + virBufferAddLit(&opt, ",password"); > + > + if (driver->vncTLS) { > + virBufferAddLit(&opt, ",tls"); > + if (driver->vncTLSx509verify) { > + virBufferAsprintf(&opt, ",x509verify=%s", > + driver->vncTLSx509certdir); > + } else { > + virBufferAsprintf(&opt, ",x509=%s", > + driver->vncTLSx509certdir); > + } > + } > + > + if (driver->vncSASL) { > + virBufferAddLit(&opt, ",sasl"); > + > + if (driver->vncSASLdir) > + virCommandAddEnvPair(cmd, "SASL_CONF_DIR", > + driver->vncSASLdir); > + > + /* TODO: Support ACLs later */ > + } > + } > + > + virCommandAddArg(cmd, "-vnc"); > + virCommandAddArgBuffer(cmd, &opt); > + if (graphics->data.vnc.keymap) { > + virCommandAddArgList(cmd, "-k", graphics->data.vnc.keymap, > + NULL); > + } > + > + /* Unless user requested it, set the audio backend to none, to > + * prevent it opening the host OS audio devices, since that causes > + * security issues and might not work when using VNC. > + */ > + if (driver->vncAllowHostAudio) { > + virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV"); > + } else { > + virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=none"); > + } > + } else if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) { > + if (qemuCapsGet(caps, QEMU_CAPS_0_10) && > + !qemuCapsGet(caps, QEMU_CAPS_SDL)) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("sdl not supported by '%s'"), > + def->emulator); > + goto error; > + } > + > + if (graphics->data.sdl.xauth) > + virCommandAddEnvPair(cmd, "XAUTHORITY", > + graphics->data.sdl.xauth); > + if (graphics->data.sdl.display) > + virCommandAddEnvPair(cmd, "DISPLAY", > + graphics->data.sdl.display); > + if (graphics->data.sdl.fullscreen) > + virCommandAddArg(cmd, "-full-screen"); > + > + /* If using SDL for video, then we should just let it > + * use QEMU's host audio drivers, possibly SDL too > + * User can set these two before starting libvirtd > + */ > + virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV"); > + virCommandAddEnvPass(cmd, "SDL_AUDIODRIVER"); > + > + /* New QEMU has this flag to let us explicitly ask for > + * SDL graphics. This is better than relying on the > + * default, since the default changes :-( */ > + if (qemuCapsGet(caps, QEMU_CAPS_SDL)) > + virCommandAddArg(cmd, "-sdl"); > + > + } else if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { > + virBuffer opt = VIR_BUFFER_INITIALIZER; > + const char *listenNetwork; > + const char *listenAddr = NULL; > + char *netAddr = NULL; > + int ret; > + int defaultMode = graphics->data.spice.defaultMode; > + > + if (!qemuCapsGet(caps, QEMU_CAPS_SPICE)) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > + _("spice graphics are not supported with this QEMU")); > + goto error; > + } > + > + virBufferAsprintf(&opt, "port=%u", graphics->data.spice.port); > + > + if (graphics->data.spice.tlsPort > 0) { > + if (!driver->spiceTLS) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > + _("spice TLS port set in XML configuration," > + " but TLS is disabled in qemu.conf")); > + return 1; This should be goto error; > + } > + virBufferAsprintf(&opt, ",tls-port=%u", > + graphics->data.spice.tlsPort); > + } > + > + switch (virDomainGraphicsListenGetType(graphics, 0)) { > + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: > + listenAddr = virDomainGraphicsListenGetAddress(graphics, 0); > + break; > + > + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: > + listenNetwork = virDomainGraphicsListenGetNetwork(graphics, 0); > + if (!listenNetwork) > + break; > + ret = networkGetNetworkAddress(listenNetwork, &netAddr); > + if (ret <= -2) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + "%s", _("network-based listen not possible, " > + "network driver not present")); > + goto error; > + } > + if (ret < 0) { > + virReportError(VIR_ERR_XML_ERROR, > + _("listen network '%s' had no usable address"), > + listenNetwork); > + goto error; > + } > + listenAddr = netAddr; > + /* store the address we found in the <graphics> element so it will > + * show up in status. */ > + if (virDomainGraphicsListenSetAddress(graphics, 0, > + listenAddr, -1, false) < 0) > + goto error; > + break; > + } > + > + if (!listenAddr) > + listenAddr = driver->spiceListen; > + if (listenAddr) > + virBufferAsprintf(&opt, ",addr=%s", listenAddr); > + > + VIR_FREE(netAddr); > + > + int mm = graphics->data.spice.mousemode; > + if (mm) { > + switch (mm) { > + case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_SERVER: > + virBufferAsprintf(&opt, ",agent-mouse=off"); > + break; > + case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_CLIENT: > + virBufferAsprintf(&opt, ",agent-mouse=on"); > + break; > + default: > + break; > + } > + } > + > + /* In the password case we set it via monitor command, to avoid > + * making it visible on CLI, so there's no use of password=XXX > + * in this bit of the code */ > + if (!graphics->data.spice.auth.passwd && > + !driver->spicePassword) > + virBufferAddLit(&opt, ",disable-ticketing"); > + > + if (driver->spiceTLS) > + virBufferAsprintf(&opt, ",x509-dir=%s", > + driver->spiceTLSx509certdir); > + > + switch (defaultMode) { > + case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE: > + virBufferAsprintf(&opt, ",tls-channel=default"); > + break; > + case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE: > + virBufferAsprintf(&opt, ",plaintext-channel=default"); > + break; > + case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY: > + /* nothing */ > + break; > + } > + > + for (int i = 0 ; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST ; i++) { > + int mode = graphics->data.spice.channels[i]; > + switch (mode) { > + case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE: > + if (!driver->spiceTLS) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > + _("spice secure channels set in XML configuration, but TLS is disabled in qemu.conf")); > + return 1; goto error; > + } > + virBufferAsprintf(&opt, ",tls-channel=%s", > + virDomainGraphicsSpiceChannelNameTypeToString(i)); > + break; > + case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE: > + virBufferAsprintf(&opt, ",plaintext-channel=%s", > + virDomainGraphicsSpiceChannelNameTypeToString(i)); > + break; > + } > + } > + if (graphics->data.spice.image) > + virBufferAsprintf(&opt, ",image-compression=%s", > + virDomainGraphicsSpiceImageCompressionTypeToString(graphics->data.spice.image)); > + if (graphics->data.spice.jpeg) > + virBufferAsprintf(&opt, ",jpeg-wan-compression=%s", > + virDomainGraphicsSpiceJpegCompressionTypeToString(graphics->data.spice.jpeg)); > + if (graphics->data.spice.zlib) > + virBufferAsprintf(&opt, ",zlib-glz-wan-compression=%s", > + virDomainGraphicsSpiceZlibCompressionTypeToString(graphics->data.spice.zlib)); > + if (graphics->data.spice.playback) > + virBufferAsprintf(&opt, ",playback-compression=%s", > + virDomainGraphicsSpicePlaybackCompressionTypeToString(graphics->data.spice.playback)); > + if (graphics->data.spice.streaming) > + virBufferAsprintf(&opt, ",streaming-video=%s", > + virDomainGraphicsSpiceStreamingModeTypeToString(graphics->data.spice.streaming)); > + if (graphics->data.spice.copypaste == VIR_DOMAIN_GRAPHICS_SPICE_CLIPBOARD_COPYPASTE_NO) > + virBufferAddLit(&opt, ",disable-copy-paste"); > + > + if (qemuCapsGet(caps, QEMU_CAPS_SEAMLESS_MIGRATION)) { > + /* If qemu supports seamless migration turn it > + * unconditionally on. If migration destination > + * doesn't support it, it fallbacks to previous > + * migration algorithm silently. */ > + virBufferAddLit(&opt, ",seamless-migration=on"); > + } > + > + virCommandAddArg(cmd, "-spice"); > + virCommandAddArgBuffer(cmd, &opt); > + if (graphics->data.spice.keymap) > + virCommandAddArgList(cmd, "-k", > + graphics->data.spice.keymap, NULL); > + /* SPICE includes native support for tunnelling audio, so we > + * set the audio backend to point at SPICE's own driver > + */ > + virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=spice"); > + > + } else { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("unsupported graphics type '%s'"), > + virDomainGraphicsTypeToString(graphics->type)); > + goto error; > + } > +no_memory: > + virReportOOMError(); > +error: > + return 0; > +} > + The end of this function is wrong, it would always report no memory and return success. The following is how it should like: return 0; no_memory: virReportOOMError(); error: return -1; Alternatively, all ``goto error'' statements could be replaced with ``return -1'' but this way minimizes modifications to the code being moved so I'm fine with it as-is. > /* > * Constructs a argv suitable for launching qemu with config defined > * for a given virtual machine. > @@ -5863,322 +6188,12 @@ qemuBuildCommandLine(virConnectPtr conn, > goto error; > } > > - if ((def->ngraphics == 1) && > - def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { > - virBuffer opt = VIR_BUFFER_INITIALIZER; > - > - if (!qemuCapsGet(caps, QEMU_CAPS_VNC)) { > - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > - _("vnc graphics are not supported with this QEMU")); > + for (i = 0 ; i < def->ngraphics ; ++i) { > + if (qemuBuildGraphicsCommandLine(driver, cmd, def, caps, > + def->graphics[i]) == -1) { "def->graphics[i]" should be aligned with "driver" above. > goto error; > } > - > - if (def->graphics[0]->data.vnc.socket || > - driver->vncAutoUnixSocket) { > - > - if (!def->graphics[0]->data.vnc.socket && > - virAsprintf(&def->graphics[0]->data.vnc.socket, > - "%s/%s.vnc", driver->libDir, def->name) == -1) { > - goto no_memory; > - } > - > - virBufferAsprintf(&opt, "unix:%s", > - def->graphics[0]->data.vnc.socket); > - > - } else if (qemuCapsGet(caps, QEMU_CAPS_VNC_COLON)) { > - const char *listenNetwork; > - const char *listenAddr = NULL; > - char *netAddr = NULL; > - bool escapeAddr; > - int ret; > - > - switch (virDomainGraphicsListenGetType(def->graphics[0], 0)) { > - case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: > - listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0); > - break; > - > - case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: > - listenNetwork = virDomainGraphicsListenGetNetwork(def->graphics[0], 0); > - if (!listenNetwork) > - break; > - ret = networkGetNetworkAddress(listenNetwork, &netAddr); > - if (ret <= -2) { > - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > - "%s", _("network-based listen not possible, " > - "network driver not present")); > - goto error; > - } > - if (ret < 0) { > - virReportError(VIR_ERR_XML_ERROR, > - _("listen network '%s' had no usable address"), > - listenNetwork); > - goto error; > - } > - listenAddr = netAddr; > - /* store the address we found in the <graphics> element so it will > - * show up in status. */ > - if (virDomainGraphicsListenSetAddress(def->graphics[0], 0, > - listenAddr, -1, false) < 0) > - goto error; > - break; > - } > - > - if (!listenAddr) > - listenAddr = driver->vncListen; > - > - escapeAddr = strchr(listenAddr, ':') != NULL; > - if (escapeAddr) > - virBufferAsprintf(&opt, "[%s]", listenAddr); > - else > - virBufferAdd(&opt, listenAddr, -1); > - virBufferAsprintf(&opt, ":%d", > - def->graphics[0]->data.vnc.port - 5900); > - > - VIR_FREE(netAddr); > - } else { > - virBufferAsprintf(&opt, "%d", > - def->graphics[0]->data.vnc.port - 5900); > - } > - > - if (qemuCapsGet(caps, QEMU_CAPS_VNC_COLON)) { > - if (def->graphics[0]->data.vnc.auth.passwd || > - driver->vncPassword) > - virBufferAddLit(&opt, ",password"); > - > - if (driver->vncTLS) { > - virBufferAddLit(&opt, ",tls"); > - if (driver->vncTLSx509verify) { > - virBufferAsprintf(&opt, ",x509verify=%s", > - driver->vncTLSx509certdir); > - } else { > - virBufferAsprintf(&opt, ",x509=%s", > - driver->vncTLSx509certdir); > - } > - } > - > - if (driver->vncSASL) { > - virBufferAddLit(&opt, ",sasl"); > - > - if (driver->vncSASLdir) > - virCommandAddEnvPair(cmd, "SASL_CONF_DIR", > - driver->vncSASLdir); > - > - /* TODO: Support ACLs later */ > - } > - } > - > - virCommandAddArg(cmd, "-vnc"); > - virCommandAddArgBuffer(cmd, &opt); > - if (def->graphics[0]->data.vnc.keymap) { > - virCommandAddArgList(cmd, "-k", def->graphics[0]->data.vnc.keymap, > - NULL); > - } > - > - /* Unless user requested it, set the audio backend to none, to > - * prevent it opening the host OS audio devices, since that causes > - * security issues and might not work when using VNC. > - */ > - if (driver->vncAllowHostAudio) { > - virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV"); > - } else { > - virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=none"); > - } > - } else if ((def->ngraphics == 1) && > - def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) { > - if (qemuCapsGet(caps, QEMU_CAPS_0_10) && > - !qemuCapsGet(caps, QEMU_CAPS_SDL)) { > - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > - _("sdl not supported by '%s'"), > - def->emulator); > - goto error; > - } > - > - if (def->graphics[0]->data.sdl.xauth) > - virCommandAddEnvPair(cmd, "XAUTHORITY", > - def->graphics[0]->data.sdl.xauth); > - if (def->graphics[0]->data.sdl.display) > - virCommandAddEnvPair(cmd, "DISPLAY", > - def->graphics[0]->data.sdl.display); > - if (def->graphics[0]->data.sdl.fullscreen) > - virCommandAddArg(cmd, "-full-screen"); > - > - /* If using SDL for video, then we should just let it > - * use QEMU's host audio drivers, possibly SDL too > - * User can set these two before starting libvirtd > - */ > - virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV"); > - virCommandAddEnvPass(cmd, "SDL_AUDIODRIVER"); > - > - /* New QEMU has this flag to let us explicitly ask for > - * SDL graphics. This is better than relying on the > - * default, since the default changes :-( */ > - if (qemuCapsGet(caps, QEMU_CAPS_SDL)) > - virCommandAddArg(cmd, "-sdl"); > - > - } else if ((def->ngraphics == 1) && > - def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { > - virBuffer opt = VIR_BUFFER_INITIALIZER; > - const char *listenNetwork; > - const char *listenAddr = NULL; > - char *netAddr = NULL; > - int ret; > - int defaultMode = def->graphics[0]->data.spice.defaultMode; > - > - if (!qemuCapsGet(caps, QEMU_CAPS_SPICE)) { > - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > - _("spice graphics are not supported with this QEMU")); > - goto error; > - } > - > - virBufferAsprintf(&opt, "port=%u", def->graphics[0]->data.spice.port); > - > - if (def->graphics[0]->data.spice.tlsPort > 0) { > - if (!driver->spiceTLS) { > - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > - _("spice TLS port set in XML configuration," > - " but TLS is disabled in qemu.conf")); > - goto error; > - } > - virBufferAsprintf(&opt, ",tls-port=%u", > - def->graphics[0]->data.spice.tlsPort); > - } > - > - switch (virDomainGraphicsListenGetType(def->graphics[0], 0)) { > - case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: > - listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0); > - break; > - > - case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: > - listenNetwork = virDomainGraphicsListenGetNetwork(def->graphics[0], 0); > - if (!listenNetwork) > - break; > - ret = networkGetNetworkAddress(listenNetwork, &netAddr); > - if (ret <= -2) { > - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > - "%s", _("network-based listen not possible, " > - "network driver not present")); > - goto error; > - } > - if (ret < 0) { > - virReportError(VIR_ERR_XML_ERROR, > - _("listen network '%s' had no usable address"), > - listenNetwork); > - goto error; > - } > - listenAddr = netAddr; > - /* store the address we found in the <graphics> element so it will > - * show up in status. */ > - if (virDomainGraphicsListenSetAddress(def->graphics[0], 0, > - listenAddr, -1, false) < 0) > - goto error; > - break; > - } > - > - if (!listenAddr) > - listenAddr = driver->spiceListen; > - if (listenAddr) > - virBufferAsprintf(&opt, ",addr=%s", listenAddr); > - > - VIR_FREE(netAddr); > - > - int mm = def->graphics[0]->data.spice.mousemode; > - if (mm) { > - switch (mm) { > - case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_SERVER: > - virBufferAsprintf(&opt, ",agent-mouse=off"); > - break; > - case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_CLIENT: > - virBufferAsprintf(&opt, ",agent-mouse=on"); > - break; > - default: > - break; > - } > - } > - > - /* In the password case we set it via monitor command, to avoid > - * making it visible on CLI, so there's no use of password=XXX > - * in this bit of the code */ > - if (!def->graphics[0]->data.spice.auth.passwd && > - !driver->spicePassword) > - virBufferAddLit(&opt, ",disable-ticketing"); > - > - if (driver->spiceTLS) > - virBufferAsprintf(&opt, ",x509-dir=%s", > - driver->spiceTLSx509certdir); > - > - switch (defaultMode) { > - case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE: > - virBufferAsprintf(&opt, ",tls-channel=default"); > - break; > - case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE: > - virBufferAsprintf(&opt, ",plaintext-channel=default"); > - break; > - case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY: > - /* nothing */ > - break; > - } > - > - for (i = 0 ; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST ; i++) { > - int mode = def->graphics[0]->data.spice.channels[i]; > - switch (mode) { > - case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE: > - if (!driver->spiceTLS) { > - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > - _("spice secure channels set in XML configuration, but TLS is disabled in qemu.conf")); > - goto error; > - } > - virBufferAsprintf(&opt, ",tls-channel=%s", > - virDomainGraphicsSpiceChannelNameTypeToString(i)); > - break; > - case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE: > - virBufferAsprintf(&opt, ",plaintext-channel=%s", > - virDomainGraphicsSpiceChannelNameTypeToString(i)); > - break; > - } > - } > - if (def->graphics[0]->data.spice.image) > - virBufferAsprintf(&opt, ",image-compression=%s", > - virDomainGraphicsSpiceImageCompressionTypeToString(def->graphics[0]->data.spice.image)); > - if (def->graphics[0]->data.spice.jpeg) > - virBufferAsprintf(&opt, ",jpeg-wan-compression=%s", > - virDomainGraphicsSpiceJpegCompressionTypeToString(def->graphics[0]->data.spice.jpeg)); > - if (def->graphics[0]->data.spice.zlib) > - virBufferAsprintf(&opt, ",zlib-glz-wan-compression=%s", > - virDomainGraphicsSpiceZlibCompressionTypeToString(def->graphics[0]->data.spice.zlib)); > - if (def->graphics[0]->data.spice.playback) > - virBufferAsprintf(&opt, ",playback-compression=%s", > - virDomainGraphicsSpicePlaybackCompressionTypeToString(def->graphics[0]->data.spice.playback)); > - if (def->graphics[0]->data.spice.streaming) > - virBufferAsprintf(&opt, ",streaming-video=%s", > - virDomainGraphicsSpiceStreamingModeTypeToString(def->graphics[0]->data.spice.streaming)); > - if (def->graphics[0]->data.spice.copypaste == VIR_DOMAIN_GRAPHICS_SPICE_CLIPBOARD_COPYPASTE_NO) > - virBufferAddLit(&opt, ",disable-copy-paste"); > - > - if (qemuCapsGet(caps, QEMU_CAPS_SEAMLESS_MIGRATION)) { > - /* If qemu supports seamless migration turn it > - * unconditionally on. If migration destination > - * doesn't support it, it fallbacks to previous > - * migration algorithm silently. */ > - virBufferAddLit(&opt, ",seamless-migration=on"); > - } > - > - virCommandAddArg(cmd, "-spice"); > - virCommandAddArgBuffer(cmd, &opt); > - if (def->graphics[0]->data.spice.keymap) > - virCommandAddArgList(cmd, "-k", > - def->graphics[0]->data.spice.keymap, NULL); > - /* SPICE includes native support for tunnelling audio, so we > - * set the audio backend to point at SPICE's own driver > - */ > - virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=spice"); > - > - } else if ((def->ngraphics == 1)) { > - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > - _("unsupported graphics type '%s'"), > - virDomainGraphicsTypeToString(def->graphics[0]->type)); > - goto error; > } > - > if (def->nvideos > 0) { > if (qemuCapsGet(caps, QEMU_CAPS_VGA)) { > if (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_XEN) { > diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c > index d8cf4c3..2a77290 100644 > --- a/src/qemu/qemu_process.c > +++ b/src/qemu/qemu_process.c > @@ -2081,16 +2081,17 @@ qemuProcessInitPasswords(virConnectPtr conn, > int ret = 0; > qemuDomainObjPrivatePtr priv = vm->privateData; > > - if (vm->def->ngraphics == 1) { > - if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { > + for (int i = 0 ; i < vm->def->ngraphics; ++i) { > + virDomainGraphicsDefPtr graphics = vm->def->graphics[i]; > + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { > ret = qemuDomainChangeGraphicsPasswords(driver, vm, > VIR_DOMAIN_GRAPHICS_TYPE_VNC, > - &vm->def->graphics[0]->data.vnc.auth, > + &graphics->data.vnc.auth, > driver->vncPassword); > - } else if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { > + } else if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { > ret = qemuDomainChangeGraphicsPasswords(driver, vm, > VIR_DOMAIN_GRAPHICS_TYPE_SPICE, > - &vm->def->graphics[0]->data.spice.auth, > + &graphics->data.spice.auth, > driver->spicePassword); > } > } > @@ -3484,21 +3485,22 @@ int qemuProcessStart(virConnectPtr conn, > VIR_DEBUG("Ensuring no historical cgroup is lying around"); > qemuRemoveCgroup(driver, vm, 1); > > - if (vm->def->ngraphics == 1) { > - if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && > - !vm->def->graphics[0]->data.vnc.socket && > - vm->def->graphics[0]->data.vnc.autoport) { > + for (i = 0 ; i < vm->def->ngraphics; ++i) { > + virDomainGraphicsDefPtr graphics = vm->def->graphics[i]; > + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && > + !graphics->data.vnc.socket && > + graphics->data.vnc.autoport) { > int port = qemuProcessNextFreePort(driver, driver->remotePortMin); > if (port < 0) { > virReportError(VIR_ERR_INTERNAL_ERROR, > "%s", _("Unable to find an unused port for VNC")); > goto cleanup; > } > - vm->def->graphics[0]->data.vnc.port = port; > - } else if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { > + graphics->data.vnc.port = port; > + } else if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { > int port = -1; > - if (vm->def->graphics[0]->data.spice.autoport || > - vm->def->graphics[0]->data.spice.port == -1) { > + if (graphics->data.spice.autoport || > + graphics->data.spice.port == -1) { > port = qemuProcessNextFreePort(driver, driver->remotePortMin); > > if (port < 0) { > @@ -3507,13 +3509,13 @@ int qemuProcessStart(virConnectPtr conn, > goto cleanup; > } > > - vm->def->graphics[0]->data.spice.port = port; > + graphics->data.spice.port = port; > } > if (driver->spiceTLS && > - (vm->def->graphics[0]->data.spice.autoport || > - vm->def->graphics[0]->data.spice.tlsPort == -1)) { > + (graphics->data.spice.autoport || > + graphics->data.spice.tlsPort == -1)) { > int tlsPort = qemuProcessNextFreePort(driver, > - vm->def->graphics[0]->data.spice.port + 1); > + graphics->data.spice.port + 1); > if (tlsPort < 0) { > virReportError(VIR_ERR_INTERNAL_ERROR, > "%s", _("Unable to find an unused port for SPICE TLS")); > @@ -3521,20 +3523,19 @@ int qemuProcessStart(virConnectPtr conn, > goto cleanup; > } > > - vm->def->graphics[0]->data.spice.tlsPort = tlsPort; > + graphics->data.spice.tlsPort = tlsPort; > } > } > > - if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC || > - vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { > - virDomainGraphicsDefPtr graphics = vm->def->graphics[0]; > + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC || > + graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { > if (graphics->nListens == 0) { > if (VIR_EXPAND_N(graphics->listens, graphics->nListens, 1) < 0) { > virReportOOMError(); > goto cleanup; > } > graphics->listens[0].type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS; > - if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) > + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) > graphics->listens[0].address = strdup(driver->vncListen); > else > graphics->listens[0].address = strdup(driver->spiceListen); > @@ -4150,19 +4151,20 @@ retry: > > qemuProcessRemoveDomainStatus(driver, vm); > > - /* Remove VNC port from port reservation bitmap, but only if it was > - reserved by the driver (autoport=yes) > + /* Remove VNC and Spice ports from port reservation bitmap, but only if > + they were reserved by the driver (autoport=yes) > */ > - if ((vm->def->ngraphics == 1) && > - vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && > - vm->def->graphics[0]->data.vnc.autoport) { > - qemuProcessReturnPort(driver, vm->def->graphics[0]->data.vnc.port); > - } > - if ((vm->def->ngraphics == 1) && > - vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE && > - vm->def->graphics[0]->data.spice.autoport) { > - qemuProcessReturnPort(driver, vm->def->graphics[0]->data.spice.port); > - qemuProcessReturnPort(driver, vm->def->graphics[0]->data.spice.tlsPort); > + for (i = 0 ; i < vm->def->ngraphics; ++i) { > + virDomainGraphicsDefPtr graphics = vm->def->graphics[i]; > + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && > + graphics->data.vnc.autoport) { > + qemuProcessReturnPort(driver, graphics->data.vnc.port); > + } > + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE && > + graphics->data.spice.autoport) { > + qemuProcessReturnPort(driver, graphics->data.spice.port); > + qemuProcessReturnPort(driver, graphics->data.spice.tlsPort); > + } > } > > vm->taint = 0; I'd prefer if the refactoring of qemuBuildCommandLine was separated from removing the limit for number of graphics cards. But since I already reviewed the patch and I don't want to do that again, I'm giving a formal ACK to this version (with the small issues fixed, of course). Since you don't have commit rights, I'll fix the issues and push the patches. Jirka -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list