2013-08-07 23:40:25 +08:00
|
|
|
/*
|
|
|
|
* QEMU Guest Agent VSS utility functions
|
|
|
|
*
|
|
|
|
* Copyright Hitachi Data Systems Corp. 2013
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Tomoki Sekiyama <tomoki.sekiyama@hds.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
|
|
* See the COPYING file in the top-level directory.
|
|
|
|
*/
|
|
|
|
|
2016-01-30 01:49:58 +08:00
|
|
|
#include "qemu/osdep.h"
|
2013-08-07 23:40:25 +08:00
|
|
|
#include <windows.h>
|
2018-02-01 19:18:31 +08:00
|
|
|
#include "qapi/error.h"
|
2017-09-12 03:52:50 +08:00
|
|
|
#include "qemu/error-report.h"
|
2013-08-07 23:40:25 +08:00
|
|
|
#include "qga/guest-agent-core.h"
|
|
|
|
#include "qga/vss-win32.h"
|
|
|
|
#include "qga/vss-win32/requester.h"
|
|
|
|
|
|
|
|
#define QGA_VSS_DLL "qga-vss.dll"
|
|
|
|
|
|
|
|
static HMODULE provider_lib;
|
|
|
|
|
|
|
|
/* Call a function in qga-vss.dll with the specified name */
|
|
|
|
static HRESULT call_vss_provider_func(const char *func_name)
|
|
|
|
{
|
|
|
|
FARPROC WINAPI func;
|
|
|
|
|
|
|
|
g_assert(provider_lib);
|
|
|
|
|
|
|
|
func = GetProcAddress(provider_lib, func_name);
|
|
|
|
if (!func) {
|
|
|
|
char *msg;
|
|
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
(char *)&msg, 0, NULL);
|
|
|
|
fprintf(stderr, "failed to load %s from %s: %s",
|
|
|
|
func_name, QGA_VSS_DLL, msg);
|
|
|
|
LocalFree(msg);
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return func();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check whether this OS version supports VSS providers */
|
|
|
|
static bool vss_check_os_version(void)
|
|
|
|
{
|
|
|
|
OSVERSIONINFO OSver;
|
|
|
|
|
|
|
|
OSver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
GetVersionEx(&OSver);
|
|
|
|
if ((OSver.dwMajorVersion == 5 && OSver.dwMinorVersion >= 2) ||
|
|
|
|
OSver.dwMajorVersion > 5) {
|
|
|
|
BOOL wow64 = false;
|
|
|
|
#ifndef _WIN64
|
|
|
|
/* Provider doesn't work under WOW64 (32bit agent on 64bit OS) */
|
|
|
|
if (!IsWow64Process(GetCurrentProcess(), &wow64)) {
|
|
|
|
fprintf(stderr, "failed to IsWow64Process (Error: %lx\n)\n",
|
|
|
|
GetLastError());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (wow64) {
|
2017-09-12 03:52:50 +08:00
|
|
|
warn_report("Running under WOW64");
|
2013-08-07 23:40:25 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return !wow64;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load qga-vss.dll */
|
|
|
|
bool vss_init(bool init_requester)
|
|
|
|
{
|
|
|
|
if (!vss_check_os_version()) {
|
|
|
|
/* Do nothing if OS doesn't support providers. */
|
|
|
|
fprintf(stderr, "VSS provider is not supported in this OS version: "
|
|
|
|
"fsfreeze is disabled.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
provider_lib = LoadLibraryA(QGA_VSS_DLL);
|
|
|
|
if (!provider_lib) {
|
|
|
|
char *msg;
|
|
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
(char *)&msg, 0, NULL);
|
|
|
|
fprintf(stderr, "failed to load %s: %sfsfreeze is disabled\n",
|
|
|
|
QGA_VSS_DLL, msg);
|
|
|
|
LocalFree(msg);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (init_requester) {
|
|
|
|
HRESULT hr = call_vss_provider_func("requester_init");
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
fprintf(stderr, "fsfreeze is disabled.\n");
|
|
|
|
vss_deinit(false);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unload qga-provider.dll */
|
|
|
|
void vss_deinit(bool deinit_requester)
|
|
|
|
{
|
|
|
|
if (deinit_requester) {
|
|
|
|
call_vss_provider_func("requester_deinit");
|
|
|
|
}
|
|
|
|
FreeLibrary(provider_lib);
|
|
|
|
provider_lib = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool vss_initialized(void)
|
|
|
|
{
|
|
|
|
return !!provider_lib;
|
|
|
|
}
|
|
|
|
|
2013-08-07 23:40:32 +08:00
|
|
|
int ga_install_vss_provider(void)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
if (!vss_init(false)) {
|
|
|
|
fprintf(stderr, "Installation of VSS provider is skipped. "
|
|
|
|
"fsfreeze will be disabled.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
hr = call_vss_provider_func("COMRegister");
|
|
|
|
vss_deinit(false);
|
|
|
|
|
|
|
|
return SUCCEEDED(hr) ? 0 : EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ga_uninstall_vss_provider(void)
|
|
|
|
{
|
|
|
|
if (!vss_init(false)) {
|
|
|
|
fprintf(stderr, "Removal of VSS provider is skipped.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
call_vss_provider_func("COMUnregister");
|
|
|
|
vss_deinit(false);
|
|
|
|
}
|
|
|
|
|
2013-08-07 23:40:25 +08:00
|
|
|
/* Call VSS requester and freeze/thaw filesystems and applications */
|
2017-04-21 20:27:09 +08:00
|
|
|
void qga_vss_fsfreeze(int *nr_volume, bool freeze, Error **errp)
|
2013-08-07 23:40:25 +08:00
|
|
|
{
|
|
|
|
const char *func_name = freeze ? "requester_freeze" : "requester_thaw";
|
|
|
|
QGAVSSRequesterFunc func;
|
|
|
|
ErrorSet errset = {
|
2016-02-25 08:14:52 +08:00
|
|
|
.error_setg_win32_wrapper = error_setg_win32_internal,
|
qga: Clean up unnecessarily dirty casts
qga_vss_fsfreeze() casts error_set_win32() from
void (*)(Error **, int, ErrorClass, const char *, ...)
to
void (*)(void **, int, int, const char *, ...)
The result is later called. Since the two types are not compatible,
the call is undefined behavior. It works in practice anyway.
However, there's no real need for trickery here. Clean it up as
follows:
* Declare struct Error, and fix the first parameter.
* Switch to error_setg_win32(). This gets rid of the troublesome
ErrorClass parameter. Requires converting error_setg_win32() from
macro to function, but that's trivially easy, because this is the
only user of error_set_win32().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-06-20 02:44:54 +08:00
|
|
|
.errp = errp,
|
2013-08-07 23:40:25 +08:00
|
|
|
};
|
|
|
|
|
2015-06-20 15:33:56 +08:00
|
|
|
g_assert(errp); /* requester.cpp requires it */
|
2013-08-07 23:40:25 +08:00
|
|
|
func = (QGAVSSRequesterFunc)GetProcAddress(provider_lib, func_name);
|
|
|
|
if (!func) {
|
2014-05-02 19:26:30 +08:00
|
|
|
error_setg_win32(errp, GetLastError(), "failed to load %s from %s",
|
2013-08-07 23:40:25 +08:00
|
|
|
func_name, QGA_VSS_DLL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
func(nr_volume, &errset);
|
|
|
|
}
|