1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
/*
* 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.
*/
#include <stdio.h>
#include <windows.h>
#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) {
fprintf(stderr, "Warning: Running under WOW64\n");
}
#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;
}
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);
}
/* Call VSS requester and freeze/thaw filesystems and applications */
void qga_vss_fsfreeze(int *nr_volume, Error **errp, bool freeze)
{
const char *func_name = freeze ? "requester_freeze" : "requester_thaw";
QGAVSSRequesterFunc func;
ErrorSet errset = {
.error_set = (ErrorSetFunc)error_set_win32,
.errp = (void **)errp,
.err_class = ERROR_CLASS_GENERIC_ERROR
};
func = (QGAVSSRequesterFunc)GetProcAddress(provider_lib, func_name);
if (!func) {
error_setg_win32(errp, GetLastError(), "failed to load %s from %s",
func_name, QGA_VSS_DLL);
return;
}
func(nr_volume, &errset);
}
|