--- src/vbox/vbox_common.c | 130 ++++++++++++++++++++++++++++ src/vbox/vbox_common.h | 1 + src/vbox/vbox_tmpl.c | 190 ++++++++++++----------------------------- src/vbox/vbox_uniformed_api.h | 23 ++++- 4 files changed, 208 insertions(+), 136 deletions(-) diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c index 505f1cd..d3735ac 100644 --- a/src/vbox/vbox_common.c +++ b/src/vbox/vbox_common.c @@ -19,6 +19,7 @@ #include <config.h> #include <unistd.h> +#include <fcntl.h> #include "internal.h" #include "datatypes.h" @@ -32,6 +33,8 @@ #include "virtime.h" #include "snapshot_conf.h" #include "vbox_snapshot_conf.h" +#include "fdstream.h" +#include "configmake.h" #include "vbox_common.h" #include "vbox_uniformed_api.h" @@ -7133,3 +7136,130 @@ int vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, gVBoxAPI.UISession.Close(data->vboxSession); return ret; } + +char * +vboxDomainScreenshot(virDomainPtr dom, + virStreamPtr st, + unsigned int screen, + unsigned int flags) +{ + VBOX_OBJECT_CHECK(dom->conn, char *, NULL); + IConsole *console = NULL; + vboxIIDUnion iid; + IMachine *machine = NULL; + nsresult rc; + char *tmp; + int tmp_fd = -1; + unsigned int max_screen; + + if (!gVBoxAPI.supportScreenshot) { + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("virDomainScreenshot don't support for current vbox version")); + return NULL; + } + + virCheckFlags(0, NULL); + + if (openSessionForMachine(data, dom->uuid, &iid, &machine, false) < 0) + return NULL; + + rc = gVBoxAPI.UIMachine.GetMonitorCount(machine, &max_screen); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("unable to get monitor count")); + VBOX_RELEASE(machine); + return NULL; + } + + if (screen >= max_screen) { + virReportError(VIR_ERR_INVALID_ARG, + _("screen ID higher than monitor " + "count (%d)"), max_screen); + VBOX_RELEASE(machine); + return NULL; + } + + if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) { + VBOX_RELEASE(machine); + return NULL; + } + + if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) { + virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp); + VIR_FREE(tmp); + VBOX_RELEASE(machine); + return NULL; + } + + + rc = gVBoxAPI.UISession.OpenExisting(data, &iid, machine); + if (NS_SUCCEEDED(rc)) { + rc = gVBoxAPI.UISession.GetConsole(data->vboxSession, &console); + if (NS_SUCCEEDED(rc) && console) { + IDisplay *display = NULL; + + gVBoxAPI.UIConsole.GetDisplay(console, &display); + + if (display) { + PRUint32 width, height, bitsPerPixel; + PRUint32 screenDataSize; + PRUint8 *screenData; + PRInt32 xOrigin, yOrigin; + + rc = gVBoxAPI.UIDisplay.GetScreenResolution(display, screen, + &width, &height, + &bitsPerPixel, + &xOrigin, &yOrigin); + + if (NS_FAILED(rc) || !width || !height) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("unable to get screen resolution")); + goto endjob; + } + + rc = gVBoxAPI.UIDisplay.TakeScreenShotPNGToArray(display, screen, + width, height, + &screenDataSize, + &screenData); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("failed to take screenshot")); + goto endjob; + } + + if (safewrite(tmp_fd, (char *) screenData, + screenDataSize) < 0) { + virReportSystemError(errno, _("unable to write data " + "to '%s'"), tmp); + goto endjob; + } + + if (VIR_CLOSE(tmp_fd) < 0) { + virReportSystemError(errno, _("unable to close %s"), tmp); + goto endjob; + } + + if (VIR_STRDUP(ret, "image/png") < 0) + goto endjob; + + if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("unable to open stream")); + VIR_FREE(ret); + } + endjob: + VIR_FREE(screenData); + VBOX_RELEASE(display); + } + VBOX_RELEASE(console); + } + gVBoxAPI.UISession.Close(data->vboxSession); + } + + VIR_FORCE_CLOSE(tmp_fd); + unlink(tmp); + VIR_FREE(tmp); + VBOX_RELEASE(machine); + vboxIIDUnalloc(&iid); + return ret; +} diff --git a/src/vbox/vbox_common.h b/src/vbox/vbox_common.h index 15bf8e2..b5a0353 100644 --- a/src/vbox/vbox_common.h +++ b/src/vbox/vbox_common.h @@ -301,5 +301,6 @@ typedef nsISupports IMediumAttachment; typedef nsISupports IStorageController; typedef nsISupports ISharedFolder; typedef nsISupports ISnapshot; +typedef nsISupports IDisplay; #endif /* VBOX_COMMON_H */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 044e6d6..82c45ad 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -3732,141 +3732,6 @@ static char *vboxStorageVolGetPath(virStorageVolPtr vol) { return ret; } -#if VBOX_API_VERSION >= 4000000 -static char * -vboxDomainScreenshot(virDomainPtr dom, - virStreamPtr st, - unsigned int screen, - unsigned int flags) -{ - VBOX_OBJECT_CHECK(dom->conn, char *, NULL); - IConsole *console = NULL; - vboxIID iid = VBOX_IID_INITIALIZER; - IMachine *machine = NULL; - nsresult rc; - char *tmp; - int tmp_fd = -1; - unsigned int max_screen; - - virCheckFlags(0, NULL); - - vboxIIDFromUUID(&iid, dom->uuid); - rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_NO_DOMAIN, "%s", - _("no domain with matching uuid")); - return NULL; - } - - rc = machine->vtbl->GetMonitorCount(machine, &max_screen); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_OPERATION_FAILED, "%s", - _("unable to get monitor count")); - VBOX_RELEASE(machine); - return NULL; - } - - if (screen >= max_screen) { - virReportError(VIR_ERR_INVALID_ARG, - _("screen ID higher than monitor " - "count (%d)"), max_screen); - VBOX_RELEASE(machine); - return NULL; - } - - if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) { - VBOX_RELEASE(machine); - return NULL; - } - - if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) { - virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp); - VIR_FREE(tmp); - VBOX_RELEASE(machine); - return NULL; - } - - - rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine); - if (NS_SUCCEEDED(rc)) { - rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); - if (NS_SUCCEEDED(rc) && console) { - IDisplay *display = NULL; - - console->vtbl->GetDisplay(console, &display); - - if (display) { - PRUint32 width, height, bitsPerPixel; - PRUint32 screenDataSize; - PRUint8 *screenData; -# if VBOX_API_VERSION >= 4003000 - PRInt32 xOrigin, yOrigin; -# endif - - rc = display->vtbl->GetScreenResolution(display, screen, - &width, &height, -# if VBOX_API_VERSION < 4003000 - &bitsPerPixel); -# else - &bitsPerPixel, - &xOrigin, &yOrigin); -# endif - - if (NS_FAILED(rc) || !width || !height) { - virReportError(VIR_ERR_OPERATION_FAILED, "%s", - _("unable to get screen resolution")); - goto endjob; - } - - rc = display->vtbl->TakeScreenShotPNGToArray(display, screen, - width, height, - &screenDataSize, - &screenData); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_OPERATION_FAILED, "%s", - _("failed to take screenshot")); - goto endjob; - } - - if (safewrite(tmp_fd, (char *) screenData, - screenDataSize) < 0) { - virReportSystemError(errno, _("unable to write data " - "to '%s'"), tmp); - goto endjob; - } - - if (VIR_CLOSE(tmp_fd) < 0) { - virReportSystemError(errno, _("unable to close %s"), tmp); - goto endjob; - } - - if (VIR_STRDUP(ret, "image/png") < 0) - goto endjob; - - if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) { - virReportError(VIR_ERR_OPERATION_FAILED, "%s", - _("unable to open stream")); - VIR_FREE(ret); - } - endjob: - VIR_FREE(screenData); - VBOX_RELEASE(display); - } - VBOX_RELEASE(console); - } - VBOX_SESSION_CLOSE(); - } - - VIR_FORCE_CLOSE(tmp_fd); - unlink(tmp); - VIR_FREE(tmp); - VBOX_RELEASE(machine); - vboxIIDUnalloc(&iid); - return ret; -} -#endif /* VBOX_API_VERSION >= 4000000 */ - - #define MATCH(FLAG) (flags & (FLAG)) static int vboxConnectListAllDomains(virConnectPtr conn, @@ -5474,6 +5339,12 @@ _consoleDeleteSnapshot(IConsole *console, vboxIIDUnion *iidu, IProgress **progre } static nsresult +_consoleGetDisplay(IConsole *console, IDisplay **display) +{ + return console->vtbl->GetDisplay(console, display); +} + +static nsresult _progressWaitForCompletion(IProgress *progress, PRInt32 timeout) { return progress->vtbl->WaitForCompletion(progress, timeout); @@ -6339,6 +6210,46 @@ _snapshotGetOnline(ISnapshot *snapshot, PRBool *online) return snapshot->vtbl->GetOnline(snapshot, online); } +static nsresult +_displayGetScreenResolution(IDisplay *display ATTRIBUTE_UNUSED, + PRUint32 screenId ATTRIBUTE_UNUSED, + PRUint32 *width ATTRIBUTE_UNUSED, + PRUint32 *height ATTRIBUTE_UNUSED, + PRUint32 *bitsPerPixel ATTRIBUTE_UNUSED, + PRInt32 *xOrigin ATTRIBUTE_UNUSED, + PRInt32 *yOrigin ATTRIBUTE_UNUSED) +{ +#if VBOX_API_VERSION < 3002000 + vboxUnsupported(); + return 0; +#elif VBOX_API_VERSION < 4003000 + return display->vtbl->GetScreenResolution(display, screenId, width, + height, bitsPerPixel); +#else /* VBOX_API_VERSION >= 4003000 */ + return display->vtbl->GetScreenResolution(display, screenId, width, + height, bitsPerPixel, + xOrigin, yOrigin); +#endif /* VBOX_API_VERSION >= 4003000 */ +} + +static nsresult +_displayTakeScreenShotPNGToArray(IDisplay *display ATTRIBUTE_UNUSED, + PRUint32 screenId ATTRIBUTE_UNUSED, + PRUint32 width ATTRIBUTE_UNUSED, + PRUint32 height ATTRIBUTE_UNUSED, + PRUint32 *screenDataSize ATTRIBUTE_UNUSED, + PRUint8** screenData ATTRIBUTE_UNUSED) +{ +#if VBOX_API_VERSION < 4000000 + vboxUnsupported(); + return 0; +#else /* VBOX_API_VERSION >= 4000000 */ + return display->vtbl->TakeScreenShotPNGToArray(display, screenId, width, + height, screenDataSize, + screenData); +#endif /* VBOX_API_VERSION >= 4000000 */ +} + static bool _machineStateOnline(PRUint32 state) { return ((state >= MachineState_FirstOnline) && @@ -6486,6 +6397,7 @@ static vboxUniformedIConsole _UIConsole = { .Reset = _consoleReset, .TakeSnapshot = _consoleTakeSnapshot, .DeleteSnapshot = _consoleDeleteSnapshot, + .GetDisplay = _consoleGetDisplay, }; static vboxUniformedIProgress _UIProgress = { @@ -6634,6 +6546,11 @@ static vboxUniformedISnapshot _UISnapshot = { .GetOnline = _snapshotGetOnline, }; +static vboxUniformedIDisplay _UIDisplay = { + .GetScreenResolution = _displayGetScreenResolution, + .TakeScreenShotPNGToArray = _displayTakeScreenShotPNGToArray, +}; + static uniformedMachineStateChecker _machineStateChecker = { .Online = _machineStateOnline, .Inactive = _machineStateInactive, @@ -6685,6 +6602,7 @@ void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI) pVBoxAPI->UIStorageController = _UIStorageController; pVBoxAPI->UISharedFolder = _UISharedFolder; pVBoxAPI->UISnapshot = _UISnapshot; + pVBoxAPI->UIDisplay = _UIDisplay; pVBoxAPI->machineStateChecker = _machineStateChecker; #if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 @@ -6704,10 +6622,12 @@ void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI) pVBoxAPI->getMachineForSession = 1; pVBoxAPI->detachDevicesExplicitly = 0; pVBoxAPI->vboxAttachDrivesUseOld = 0; + pVBoxAPI->supportScreenshot = 1; #else /* VBOX_API_VERSION < 4000000 */ pVBoxAPI->getMachineForSession = 0; pVBoxAPI->detachDevicesExplicitly = 1; pVBoxAPI->vboxAttachDrivesUseOld = 1; + pVBoxAPI->supportScreenshot = 0; #endif /* VBOX_API_VERSION < 4000000 */ #if VBOX_API_VERSION >= 4001000 diff --git a/src/vbox/vbox_uniformed_api.h b/src/vbox/vbox_uniformed_api.h index 2800b60..7e8f677 100644 --- a/src/vbox/vbox_uniformed_api.h +++ b/src/vbox/vbox_uniformed_api.h @@ -273,6 +273,7 @@ typedef struct { nsresult (*TakeSnapshot)(IConsole *console, PRUnichar *name, PRUnichar *description, IProgress **progress); nsresult (*DeleteSnapshot)(IConsole *console, vboxIIDUnion *iidu, IProgress **progress); + nsresult (*GetDisplay)(IConsole *console, IDisplay **display); } vboxUniformedIConsole; /* Functions for IProgress */ @@ -446,6 +447,23 @@ typedef struct { nsresult (*GetOnline)(ISnapshot *snapshot, PRBool *online); } vboxUniformedISnapshot; +/* Functions for IDisplay */ +typedef struct { + nsresult (*GetScreenResolution)(IDisplay *display, + PRUint32 screenId, + PRUint32 *width, + PRUint32 *height, + PRUint32 *bitsPerPixel, + PRInt32 *xOrigin, + PRInt32 *yOrigin); + nsresult (*TakeScreenShotPNGToArray)(IDisplay *display, + PRUint32 screenId, + PRUint32 width, + PRUint32 height, + PRUint32 *screenDataSize, + PRUint8** screenData); +} vboxUniformedIDisplay; + typedef struct { bool (*Online)(PRUint32 state); bool (*Inactive)(PRUint32 state); @@ -498,6 +516,7 @@ typedef struct { vboxUniformedIStorageController UIStorageController; vboxUniformedISharedFolder UISharedFolder; vboxUniformedISnapshot UISnapshot; + vboxUniformedIDisplay UIDisplay; uniformedMachineStateChecker machineStateChecker; /* vbox API features */ bool domainEventCallbacks; @@ -509,6 +528,7 @@ typedef struct { bool vboxAttachDrivesUseOld; bool oldMediumInterface; bool vboxSnapshotRedefine; + bool supportScreenshot; } vboxUniformedAPI; /* libvirt API @@ -599,7 +619,8 @@ int vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags); int vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags); - +char *vboxDomainScreenshot(virDomainPtr dom, virStreamPtr st, + unsigned int screen, unsigned int flags); /* Version specified functions for installing uniformed API */ void vbox22InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI); -- 1.7.9.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list