mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 03:12:22 +00:00
vbox: Rewrite vboxDomainScreenshot
This commit is contained in:
parent
4fab8d3f07
commit
72f92bce44
@ -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"
|
||||
@ -7121,3 +7124,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;
|
||||
}
|
||||
|
@ -301,5 +301,6 @@ typedef nsISupports IMediumAttachment;
|
||||
typedef nsISupports IStorageController;
|
||||
typedef nsISupports ISharedFolder;
|
||||
typedef nsISupports ISnapshot;
|
||||
typedef nsISupports IDisplay;
|
||||
|
||||
#endif /* VBOX_COMMON_H */
|
||||
|
@ -3733,141 +3733,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
|
||||
#endif /* VBOX_API_VERSION >= 3001000 */
|
||||
}
|
||||
|
||||
static nsresult
|
||||
_consoleGetDisplay(IConsole *console, IDisplay **display)
|
||||
{
|
||||
return console->vtbl->GetDisplay(console, display);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
_progressWaitForCompletion(IProgress *progress, PRInt32 timeout)
|
||||
{
|
||||
@ -6340,6 +6211,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) &&
|
||||
@ -6487,6 +6398,7 @@ static vboxUniformedIConsole _UIConsole = {
|
||||
.Reset = _consoleReset,
|
||||
.TakeSnapshot = _consoleTakeSnapshot,
|
||||
.DeleteSnapshot = _consoleDeleteSnapshot,
|
||||
.GetDisplay = _consoleGetDisplay,
|
||||
};
|
||||
|
||||
static vboxUniformedIProgress _UIProgress = {
|
||||
@ -6635,6 +6547,11 @@ static vboxUniformedISnapshot _UISnapshot = {
|
||||
.GetOnline = _snapshotGetOnline,
|
||||
};
|
||||
|
||||
static vboxUniformedIDisplay _UIDisplay = {
|
||||
.GetScreenResolution = _displayGetScreenResolution,
|
||||
.TakeScreenShotPNGToArray = _displayTakeScreenShotPNGToArray,
|
||||
};
|
||||
|
||||
static uniformedMachineStateChecker _machineStateChecker = {
|
||||
.Online = _machineStateOnline,
|
||||
.Inactive = _machineStateInactive,
|
||||
@ -6686,6 +6603,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
|
||||
@ -6705,10 +6623,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
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user