From 9a337767155b077b81bed66098672eb94e71ff06 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Thu, 17 May 2018 13:53:34 +0200 Subject: [PATCH] qemu: Implement multiple screen support for virDomainScreenshot According to virDomainScreenshot() documentation, screens are numbered sequentially. e.g. having two graphics cards, both with four heads, screen ID 5 addresses the second head on the second card. But apart from that, there's nothing special happening here. Signed-off-by: Michal Privoznik --- src/qemu/qemu_driver.c | 38 +++++++++++++++++++++++++++++------- src/qemu/qemu_monitor.c | 4 +++- src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_monitor_json.c | 4 ++++ src/qemu/qemu_monitor_json.h | 2 ++ tests/qemumonitorjsontest.c | 2 +- 6 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b697838070..e61af23870 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3999,6 +3999,8 @@ qemuDomainScreenshot(virDomainPtr dom, qemuDomainObjPrivatePtr priv; char *tmp = NULL; int tmp_fd = -1; + size_t i; + const char *videoAlias = NULL; char *ret = NULL; bool unlink_tmp = false; virQEMUDriverConfigPtr cfg = NULL; @@ -4020,15 +4022,37 @@ qemuDomainScreenshot(virDomainPtr dom, if (virDomainObjCheckActive(vm) < 0) goto endjob; - /* Well, even if qemu allows multiple graphic cards, heads, whatever, - * screenshot command does not */ - if (screen) { - virReportError(VIR_ERR_INVALID_ARG, - "%s", _("currently is supported only taking " - "screenshots of screen ID 0")); + if (!vm->def->nvideos) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("no screens to take screenshot from")); goto endjob; } + if (screen) { + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_SCREENDUMP_DEVICE)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("qemu does not allow specifying screen ID")); + goto endjob; + } + + for (i = 0; i < vm->def->nvideos; i++) { + const virDomainVideoDef *video = vm->def->videos[i]; + + if (screen < video->heads) { + videoAlias = video->info.alias; + break; + } + + screen -= video->heads; + } + + if (i == vm->def->nvideos) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("no such screen ID")); + goto endjob; + } + } + if (virAsprintf(&tmp, "%s/qemu.screendump.XXXXXX", cfg->cacheDir) < 0) goto endjob; @@ -4041,7 +4065,7 @@ qemuDomainScreenshot(virDomainPtr dom, qemuSecuritySetSavedStateLabel(driver->securityManager, vm->def, tmp); qemuDomainObjEnterMonitor(driver, vm); - if (qemuMonitorScreendump(priv->mon, tmp) < 0) { + if (qemuMonitorScreendump(priv->mon, videoAlias, screen, tmp) < 0) { ignore_value(qemuDomainObjExitMonitor(driver, vm)); goto endjob; } diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 3d7ca3ccfc..f21bf7000d 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3477,6 +3477,8 @@ qemuMonitorSendKey(qemuMonitorPtr mon, int qemuMonitorScreendump(qemuMonitorPtr mon, + const char *device, + unsigned int head, const char *file) { VIR_DEBUG("file=%s", file); @@ -3484,7 +3486,7 @@ qemuMonitorScreendump(qemuMonitorPtr mon, QEMU_CHECK_MONITOR(mon); if (mon->json) - return qemuMonitorJSONScreendump(mon, file); + return qemuMonitorJSONScreendump(mon, device, head, file); else return qemuMonitorTextScreendump(mon, file); } diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 33dc521e83..6cba37c281 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -886,6 +886,8 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, int qemuMonitorInjectNMI(qemuMonitorPtr mon); int qemuMonitorScreendump(qemuMonitorPtr mon, + const char *device, + unsigned int head, const char *file); int qemuMonitorSendKey(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index e2e0004e4d..6dcded9369 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4483,6 +4483,8 @@ int qemuMonitorJSONSendKey(qemuMonitorPtr mon, } int qemuMonitorJSONScreendump(qemuMonitorPtr mon, + const char *device, + unsigned int head, const char *file) { int ret = -1; @@ -4490,6 +4492,8 @@ int qemuMonitorJSONScreendump(qemuMonitorPtr mon, cmd = qemuMonitorJSONMakeCommand("screendump", "s:filename", file, + "S:device", device, + "p:head", head, NULL); if (!cmd) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index e86b58f7ea..8461932cac 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -296,6 +296,8 @@ int qemuMonitorJSONSendKey(qemuMonitorPtr mon, unsigned int nkeycodes); int qemuMonitorJSONScreendump(qemuMonitorPtr mon, + const char *device, + unsigned int head, const char *file); int qemuMonitorJSONBlockStream(qemuMonitorPtr mon, diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index edd57067bd..add5ff0f19 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1348,7 +1348,7 @@ GEN_TEST_FUNC(qemuMonitorJSONDriveMirror, "vdb", "/foo/bar", NULL, 1024, 0, 0, VIR_DOMAIN_BLOCK_REBASE_SHALLOW | VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT) GEN_TEST_FUNC(qemuMonitorJSONBlockCommit, "vdb", "/foo/bar1", "/foo/bar2", NULL, 1024) GEN_TEST_FUNC(qemuMonitorJSONDrivePivot, "vdb") -GEN_TEST_FUNC(qemuMonitorJSONScreendump, "/foo/bar") +GEN_TEST_FUNC(qemuMonitorJSONScreendump, NULL, 0, "/foo/bar") GEN_TEST_FUNC(qemuMonitorJSONOpenGraphics, "spice", "spicefd", false) GEN_TEST_FUNC(qemuMonitorJSONNBDServerStart, "localhost", 12345, "test-alias") GEN_TEST_FUNC(qemuMonitorJSONNBDServerAdd, "vda", true) -- GitLab