hmm, I'm not using the enum everywhere, I'll send again after fixing (and use --patience). ----- Original Message ----- > From: Alon Levy <alevy@xxxxxxxxxx> > > The check for a single display remains so no new functionality is > added. > --- > > No change to the patch itself, just the use of the --patience flag > to make review much easier. > > src/qemu/qemu_command.c | 647 > +++++++++++++++++++++++++----------------------- > src/qemu/qemu_process.c | 70 +++--- > 2 files changed, 370 insertions(+), 347 deletions(-) > > diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c > index 1e96982..f9e4d4d 100644 > --- a/src/qemu/qemu_command.c > +++ b/src/qemu/qemu_command.c > @@ -4410,6 +4410,334 @@ error: > return -1; > } > > +enum { > + OK=0, > + ERROR=1, > + NO_MEMORY=2, > +}; > + > +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")); > + return 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) { > + return 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")); > + return 1; > + } > + if (ret < 0) { > + virReportError(VIR_ERR_XML_ERROR, > + _("listen network '%s' had no > usable address"), > + listenNetwork); > + return 1; > + } > + 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) > + return 1; > + 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); > + return 1; > + } > + > + 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")); > + return 1; > + } > + > + 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; > + } > + 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")); > + return 1; > + } > + if (ret < 0) { > + virReportError(VIR_ERR_XML_ERROR, > + _("listen network '%s' had no usable > address"), > + listenNetwork); > + return 1; > + } > + 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) > + return 1; > + 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; > + } > + 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)); > + return 1; > + } > + return 0; > +} > + > /* > * Constructs a argv suitable for launching qemu with config defined > * for a given virtual machine. > @@ -5863,322 +6191,15 @@ 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) { > + switch (qemuBuildGraphicsCommandLine(driver, cmd, def, caps, > + def->graphics[i])) { > + case ERROR: > goto error; > + case NO_MEMORY: > + goto no_memory; > } > - > - 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 5bd042d..7a671dd 100644 > --- a/src/qemu/qemu_process.c > +++ b/src/qemu/qemu_process.c > @@ -2079,16 +2079,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); > } > } > @@ -3482,21 +3483,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) { > @@ -3505,13 +3507,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")); > @@ -3519,20 +3521,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); > @@ -4148,19 +4149,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; > -- > 1.7.11.7 > > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list