xref: /openbmc/qemu/qga/vss-win32.c (revision 69e2d038)
164c00317STomoki Sekiyama /*
264c00317STomoki Sekiyama  * QEMU Guest Agent VSS utility functions
364c00317STomoki Sekiyama  *
464c00317STomoki Sekiyama  * Copyright Hitachi Data Systems Corp. 2013
564c00317STomoki Sekiyama  *
664c00317STomoki Sekiyama  * Authors:
764c00317STomoki Sekiyama  *  Tomoki Sekiyama   <tomoki.sekiyama@hds.com>
864c00317STomoki Sekiyama  *
964c00317STomoki Sekiyama  * This work is licensed under the terms of the GNU GPL, version 2 or later.
1064c00317STomoki Sekiyama  * See the COPYING file in the top-level directory.
1164c00317STomoki Sekiyama  */
1264c00317STomoki Sekiyama 
134459bf38SPeter Maydell #include "qemu/osdep.h"
1464c00317STomoki Sekiyama #include <windows.h>
15e688df6bSMarkus Armbruster #include "qapi/error.h"
162ab4b135SAlistair Francis #include "qemu/error-report.h"
17dc03272dSMichael S. Tsirkin #include "guest-agent-core.h"
18dc03272dSMichael S. Tsirkin #include "vss-win32.h"
19dc03272dSMichael S. Tsirkin #include "vss-win32/requester.h"
2064c00317STomoki Sekiyama 
2164c00317STomoki Sekiyama #define QGA_VSS_DLL "qga-vss.dll"
2264c00317STomoki Sekiyama 
2364c00317STomoki Sekiyama static HMODULE provider_lib;
2464c00317STomoki Sekiyama 
2564c00317STomoki Sekiyama /* Call a function in qga-vss.dll with the specified name */
call_vss_provider_func(const char * func_name)2664c00317STomoki Sekiyama static HRESULT call_vss_provider_func(const char *func_name)
2764c00317STomoki Sekiyama {
2864c00317STomoki Sekiyama     FARPROC WINAPI func;
2964c00317STomoki Sekiyama 
3064c00317STomoki Sekiyama     g_assert(provider_lib);
3164c00317STomoki Sekiyama 
3264c00317STomoki Sekiyama     func = GetProcAddress(provider_lib, func_name);
3364c00317STomoki Sekiyama     if (!func) {
3464c00317STomoki Sekiyama         char *msg;
3564c00317STomoki Sekiyama         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
3664c00317STomoki Sekiyama                       FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
3764c00317STomoki Sekiyama                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
3864c00317STomoki Sekiyama                       (char *)&msg, 0, NULL);
3964c00317STomoki Sekiyama         fprintf(stderr, "failed to load %s from %s: %s",
4064c00317STomoki Sekiyama                 func_name, QGA_VSS_DLL, msg);
4164c00317STomoki Sekiyama         LocalFree(msg);
4264c00317STomoki Sekiyama         return E_FAIL;
4364c00317STomoki Sekiyama     }
4464c00317STomoki Sekiyama 
4564c00317STomoki Sekiyama     return func();
4664c00317STomoki Sekiyama }
4764c00317STomoki Sekiyama 
4864c00317STomoki Sekiyama /* Check whether this OS version supports VSS providers */
vss_check_os_version(void)4964c00317STomoki Sekiyama static bool vss_check_os_version(void)
5064c00317STomoki Sekiyama {
5164c00317STomoki Sekiyama     OSVERSIONINFO OSver;
5264c00317STomoki Sekiyama 
5364c00317STomoki Sekiyama     OSver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
5464c00317STomoki Sekiyama     GetVersionEx(&OSver);
5564c00317STomoki Sekiyama     if ((OSver.dwMajorVersion == 5 && OSver.dwMinorVersion >= 2) ||
5664c00317STomoki Sekiyama        OSver.dwMajorVersion > 5) {
5764c00317STomoki Sekiyama         BOOL wow64 = false;
5864c00317STomoki Sekiyama #ifndef _WIN64
5964c00317STomoki Sekiyama         /* Provider doesn't work under WOW64 (32bit agent on 64bit OS) */
6064c00317STomoki Sekiyama         if (!IsWow64Process(GetCurrentProcess(), &wow64)) {
6164c00317STomoki Sekiyama             fprintf(stderr, "failed to IsWow64Process (Error: %lx\n)\n",
6264c00317STomoki Sekiyama                     GetLastError());
6364c00317STomoki Sekiyama             return false;
6464c00317STomoki Sekiyama         }
6564c00317STomoki Sekiyama         if (wow64) {
662ab4b135SAlistair Francis             warn_report("Running under WOW64");
6764c00317STomoki Sekiyama         }
6864c00317STomoki Sekiyama #endif
6964c00317STomoki Sekiyama         return !wow64;
7064c00317STomoki Sekiyama     }
7164c00317STomoki Sekiyama     return false;
7264c00317STomoki Sekiyama }
7364c00317STomoki Sekiyama 
7464c00317STomoki Sekiyama /* Load qga-vss.dll */
vss_init(bool init_requester)7564c00317STomoki Sekiyama bool vss_init(bool init_requester)
7664c00317STomoki Sekiyama {
7764c00317STomoki Sekiyama     if (!vss_check_os_version()) {
7864c00317STomoki Sekiyama         /* Do nothing if OS doesn't support providers. */
7964c00317STomoki Sekiyama         fprintf(stderr, "VSS provider is not supported in this OS version: "
8064c00317STomoki Sekiyama                 "fsfreeze is disabled.\n");
8164c00317STomoki Sekiyama         return false;
8264c00317STomoki Sekiyama     }
8364c00317STomoki Sekiyama 
8464c00317STomoki Sekiyama     provider_lib = LoadLibraryA(QGA_VSS_DLL);
8564c00317STomoki Sekiyama     if (!provider_lib) {
8664c00317STomoki Sekiyama         char *msg;
8764c00317STomoki Sekiyama         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
8864c00317STomoki Sekiyama                       FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
8964c00317STomoki Sekiyama                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
9064c00317STomoki Sekiyama                       (char *)&msg, 0, NULL);
9164c00317STomoki Sekiyama         fprintf(stderr, "failed to load %s: %sfsfreeze is disabled\n",
9264c00317STomoki Sekiyama                 QGA_VSS_DLL, msg);
9364c00317STomoki Sekiyama         LocalFree(msg);
9464c00317STomoki Sekiyama         return false;
9564c00317STomoki Sekiyama     }
9664c00317STomoki Sekiyama 
9764c00317STomoki Sekiyama     if (init_requester) {
9864c00317STomoki Sekiyama         HRESULT hr = call_vss_provider_func("requester_init");
9964c00317STomoki Sekiyama         if (FAILED(hr)) {
10064c00317STomoki Sekiyama             fprintf(stderr, "fsfreeze is disabled.\n");
10164c00317STomoki Sekiyama             vss_deinit(false);
10264c00317STomoki Sekiyama             return false;
10364c00317STomoki Sekiyama         }
10464c00317STomoki Sekiyama     }
10564c00317STomoki Sekiyama 
10664c00317STomoki Sekiyama     return true;
10764c00317STomoki Sekiyama }
10864c00317STomoki Sekiyama 
10964c00317STomoki Sekiyama /* Unload qga-provider.dll */
vss_deinit(bool deinit_requester)11064c00317STomoki Sekiyama void vss_deinit(bool deinit_requester)
11164c00317STomoki Sekiyama {
11264c00317STomoki Sekiyama     if (deinit_requester) {
11364c00317STomoki Sekiyama         call_vss_provider_func("requester_deinit");
11464c00317STomoki Sekiyama     }
11564c00317STomoki Sekiyama     FreeLibrary(provider_lib);
11664c00317STomoki Sekiyama     provider_lib = NULL;
11764c00317STomoki Sekiyama }
11864c00317STomoki Sekiyama 
vss_initialized(void)11964c00317STomoki Sekiyama bool vss_initialized(void)
12064c00317STomoki Sekiyama {
12164c00317STomoki Sekiyama     return !!provider_lib;
12264c00317STomoki Sekiyama }
12364c00317STomoki Sekiyama 
ga_install_vss_provider(void)124f311f2c2STomoki Sekiyama int ga_install_vss_provider(void)
125f311f2c2STomoki Sekiyama {
126f311f2c2STomoki Sekiyama     HRESULT hr;
127f311f2c2STomoki Sekiyama 
128f311f2c2STomoki Sekiyama     if (!vss_init(false)) {
129f311f2c2STomoki Sekiyama         fprintf(stderr, "Installation of VSS provider is skipped. "
130f311f2c2STomoki Sekiyama                 "fsfreeze will be disabled.\n");
131f311f2c2STomoki Sekiyama         return 0;
132f311f2c2STomoki Sekiyama     }
133f311f2c2STomoki Sekiyama     hr = call_vss_provider_func("COMRegister");
134f311f2c2STomoki Sekiyama     vss_deinit(false);
135f311f2c2STomoki Sekiyama 
136f311f2c2STomoki Sekiyama     return SUCCEEDED(hr) ? 0 : EXIT_FAILURE;
137f311f2c2STomoki Sekiyama }
138f311f2c2STomoki Sekiyama 
ga_uninstall_vss_provider(void)139f311f2c2STomoki Sekiyama void ga_uninstall_vss_provider(void)
140f311f2c2STomoki Sekiyama {
141f311f2c2STomoki Sekiyama     if (!vss_init(false)) {
142f311f2c2STomoki Sekiyama         fprintf(stderr, "Removal of VSS provider is skipped.\n");
143f311f2c2STomoki Sekiyama         return;
144f311f2c2STomoki Sekiyama     }
145f311f2c2STomoki Sekiyama     call_vss_provider_func("COMUnregister");
146f311f2c2STomoki Sekiyama     vss_deinit(false);
147f311f2c2STomoki Sekiyama }
148f311f2c2STomoki Sekiyama 
14964c00317STomoki Sekiyama /* Call VSS requester and freeze/thaw filesystems and applications */
qga_vss_fsfreeze(int * nr_volume,bool freeze,strList * mountpoints,Error ** errp)150*0692b03eSChen Hanxiao void qga_vss_fsfreeze(int *nr_volume, bool freeze,
151*0692b03eSChen Hanxiao                       strList *mountpoints, Error **errp)
15264c00317STomoki Sekiyama {
15364c00317STomoki Sekiyama     const char *func_name = freeze ? "requester_freeze" : "requester_thaw";
15464c00317STomoki Sekiyama     QGAVSSRequesterFunc func;
15564c00317STomoki Sekiyama     ErrorSet errset = {
156e55eb806SMichael Roth         .error_setg_win32_wrapper = error_setg_win32_internal,
157e7cf59e8SMarkus Armbruster         .errp = errp,
15864c00317STomoki Sekiyama     };
15964c00317STomoki Sekiyama 
16008e64640SMarkus Armbruster     g_assert(errp);             /* requester.cpp requires it */
16164c00317STomoki Sekiyama     func = (QGAVSSRequesterFunc)GetProcAddress(provider_lib, func_name);
16264c00317STomoki Sekiyama     if (!func) {
16377dbc81bSMarkus Armbruster         error_setg_win32(errp, GetLastError(), "failed to load %s from %s",
16464c00317STomoki Sekiyama                          func_name, QGA_VSS_DLL);
16564c00317STomoki Sekiyama         return;
16664c00317STomoki Sekiyama     }
16764c00317STomoki Sekiyama 
168*0692b03eSChen Hanxiao     func(nr_volume, mountpoints, &errset);
16964c00317STomoki Sekiyama }
170