mirror of https://github.com/xemu-project/xemu.git
qemu-ga patch queue
* new commands: guest-get-timezone, guest-get-users, guest-get-host-name * fix hang on w32 when stopping qemu-ga service while fs frozen * fix missing setting of can-offline in guest-get-vcpus * make qemu-ga VSS w32 service on-demand rather than on-startup * fix unecessary errors to EventLog on w32 * improvements to fsfreeze documentation v2: * document 'zone' field of guest-get-timezone as informational-only (Daniel, Eric) * fix build error for glib < 2.32 (Peter) -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJZAYUOAAoJEDNTyc7xCLWEILEH/iyom0A3PQ/OnAX51ep+J3EK 2k8hU207bynbASv3rVo+RZORQAJ3LncU+ZnS27iRhAZI3MUjMM0YzLROfBqO5lSl aMWjX5mDcEsJgiHWkmN6t01tUyxayShn228xP8VsTKNEVHq+xwC0QSHv8fDMCPmc qD51GVC53DO2HSpDFMBFOI8uVFxMIuaB/yBCpOQKtTuW+2HDmJm8797ypvIqhrmN 0PXldJaRcsPbApwv6K/9qa3cESb1IKRLAoerUjhtXa3uaHXth/n8h3VNaFuTtO1X aQygV/6SlowTZwdiJi3Jpv7q3OL+OpK9BrUbMfg3ag49BmsZfkrq5T/sn5w5JR4= =hhMj -----END PGP SIGNATURE----- Merge remote-tracking branch 'mdroth/tags/qga-pull-2017-04-25-v2-tag' into staging qemu-ga patch queue * new commands: guest-get-timezone, guest-get-users, guest-get-host-name * fix hang on w32 when stopping qemu-ga service while fs frozen * fix missing setting of can-offline in guest-get-vcpus * make qemu-ga VSS w32 service on-demand rather than on-startup * fix unecessary errors to EventLog on w32 * improvements to fsfreeze documentation v2: * document 'zone' field of guest-get-timezone as informational-only (Daniel, Eric) * fix build error for glib < 2.32 (Peter) # gpg: Signature made Thu 27 Apr 2017 06:43:42 AM BST # gpg: using RSA key 0x3353C9CEF108B584 # gpg: Good signature from "Michael Roth <flukshun@gmail.com>" # gpg: aka "Michael Roth <mdroth@utexas.edu>" # gpg: aka "Michael Roth <mdroth@linux.vnet.ibm.com>" # Primary key fingerprint: CEAC C9E1 5534 EBAB B82D 3FA0 3353 C9CE F108 B584 * mdroth/tags/qga-pull-2017-04-25-v2-tag: qga: Add `guest-get-timezone` command qga: Add 'guest-get-users' command qga: improve fsfreeze documentations qga: Add 'guest-get-host-name' command qga-win: Fix Event Viewer errors caused by qemu-ga qga-win: Fix a bug where qemu-ga service is stuck during stop operation qga-win: Enable 'can-offline' field in 'guest-get-vcpus' reply qemu-ga: Make QGA VSS provider service run only when needed Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
7ad691ec98
|
@ -743,7 +743,7 @@ if test "$mingw32" = "yes" ; then
|
||||||
sysconfdir="\${prefix}"
|
sysconfdir="\${prefix}"
|
||||||
local_statedir=
|
local_statedir=
|
||||||
confsuffix=""
|
confsuffix=""
|
||||||
libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi -lnetapi32 $libs_qga"
|
libs_qga="-lws2_32 -lwinmm -lpowrprof -lwtsapi32 -liphlpapi -lnetapi32 $libs_qga"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
werror=""
|
werror=""
|
||||||
|
|
|
@ -217,6 +217,12 @@ static inline void g_hash_table_add(GHashTable *hash_table, gpointer key)
|
||||||
{
|
{
|
||||||
g_hash_table_replace(hash_table, key, key);
|
g_hash_table_replace(hash_table, key, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline gboolean g_hash_table_contains(GHashTable *hash_table,
|
||||||
|
gpointer key)
|
||||||
|
{
|
||||||
|
return g_hash_table_lookup_extended(hash_table, key, NULL, NULL);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef g_assert_true
|
#ifndef g_assert_true
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <utmpx.h>
|
||||||
#include "qga/guest-agent-core.h"
|
#include "qga/guest-agent-core.h"
|
||||||
#include "qga-qmp-commands.h"
|
#include "qga-qmp-commands.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
|
@ -2517,3 +2518,62 @@ void ga_command_state_init(GAState *s, GACommandState *cs)
|
||||||
ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
|
ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define QGA_MICRO_SECOND_TO_SECOND 1000000
|
||||||
|
|
||||||
|
static double ga_get_login_time(struct utmpx *user_info)
|
||||||
|
{
|
||||||
|
double seconds = (double)user_info->ut_tv.tv_sec;
|
||||||
|
double useconds = (double)user_info->ut_tv.tv_usec;
|
||||||
|
useconds /= QGA_MICRO_SECOND_TO_SECOND;
|
||||||
|
return seconds + useconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
GuestUserList *qmp_guest_get_users(Error **err)
|
||||||
|
{
|
||||||
|
GHashTable *cache = NULL;
|
||||||
|
GuestUserList *head = NULL, *cur_item = NULL;
|
||||||
|
struct utmpx *user_info = NULL;
|
||||||
|
gpointer value = NULL;
|
||||||
|
GuestUser *user = NULL;
|
||||||
|
GuestUserList *item = NULL;
|
||||||
|
double login_time = 0;
|
||||||
|
|
||||||
|
cache = g_hash_table_new(g_str_hash, g_str_equal);
|
||||||
|
setutxent();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
user_info = getutxent();
|
||||||
|
if (user_info == NULL) {
|
||||||
|
break;
|
||||||
|
} else if (user_info->ut_type != USER_PROCESS) {
|
||||||
|
continue;
|
||||||
|
} else if (g_hash_table_contains(cache, user_info->ut_user)) {
|
||||||
|
value = g_hash_table_lookup(cache, user_info->ut_user);
|
||||||
|
user = (GuestUser *)value;
|
||||||
|
login_time = ga_get_login_time(user_info);
|
||||||
|
/* We're ensuring the earliest login time to be sent */
|
||||||
|
if (login_time < user->login_time) {
|
||||||
|
user->login_time = login_time;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = g_new0(GuestUserList, 1);
|
||||||
|
item->value = g_new0(GuestUser, 1);
|
||||||
|
item->value->user = g_strdup(user_info->ut_user);
|
||||||
|
item->value->login_time = ga_get_login_time(user_info);
|
||||||
|
|
||||||
|
g_hash_table_insert(cache, item->value->user, item->value);
|
||||||
|
|
||||||
|
if (!cur_item) {
|
||||||
|
head = cur_item = item;
|
||||||
|
} else {
|
||||||
|
cur_item->next = item;
|
||||||
|
cur_item = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endutxent();
|
||||||
|
g_hash_table_destroy(cache);
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
* See the COPYING file in the top-level directory.
|
* See the COPYING file in the top-level directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
# define _WIN32_WINNT 0x0600
|
||||||
|
#endif
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include <wtypes.h>
|
#include <wtypes.h>
|
||||||
#include <powrprof.h>
|
#include <powrprof.h>
|
||||||
|
@ -25,6 +28,7 @@
|
||||||
#include <initguid.h>
|
#include <initguid.h>
|
||||||
#endif
|
#endif
|
||||||
#include <lm.h>
|
#include <lm.h>
|
||||||
|
#include <wtsapi32.h>
|
||||||
|
|
||||||
#include "qga/guest-agent-core.h"
|
#include "qga/guest-agent-core.h"
|
||||||
#include "qga/vss-win32.h"
|
#include "qga/vss-win32.h"
|
||||||
|
@ -1344,7 +1348,7 @@ GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
|
||||||
vcpu = g_malloc0(sizeof *vcpu);
|
vcpu = g_malloc0(sizeof *vcpu);
|
||||||
vcpu->logical_id = current++;
|
vcpu->logical_id = current++;
|
||||||
vcpu->online = true;
|
vcpu->online = true;
|
||||||
vcpu->has_can_offline = false;
|
vcpu->has_can_offline = true;
|
||||||
|
|
||||||
entry = g_malloc0(sizeof *entry);
|
entry = g_malloc0(sizeof *entry);
|
||||||
entry->value = vcpu;
|
entry->value = vcpu;
|
||||||
|
@ -1536,3 +1540,102 @@ void ga_command_state_init(GAState *s, GACommandState *cs)
|
||||||
ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
|
ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* MINGW is missing two fields: IncomingFrames & OutgoingFrames */
|
||||||
|
typedef struct _GA_WTSINFOA {
|
||||||
|
WTS_CONNECTSTATE_CLASS State;
|
||||||
|
DWORD SessionId;
|
||||||
|
DWORD IncomingBytes;
|
||||||
|
DWORD OutgoingBytes;
|
||||||
|
DWORD IncomingFrames;
|
||||||
|
DWORD OutgoingFrames;
|
||||||
|
DWORD IncomingCompressedBytes;
|
||||||
|
DWORD OutgoingCompressedBy;
|
||||||
|
CHAR WinStationName[WINSTATIONNAME_LENGTH];
|
||||||
|
CHAR Domain[DOMAIN_LENGTH];
|
||||||
|
CHAR UserName[USERNAME_LENGTH + 1];
|
||||||
|
LARGE_INTEGER ConnectTime;
|
||||||
|
LARGE_INTEGER DisconnectTime;
|
||||||
|
LARGE_INTEGER LastInputTime;
|
||||||
|
LARGE_INTEGER LogonTime;
|
||||||
|
LARGE_INTEGER CurrentTime;
|
||||||
|
|
||||||
|
} GA_WTSINFOA;
|
||||||
|
|
||||||
|
GuestUserList *qmp_guest_get_users(Error **err)
|
||||||
|
{
|
||||||
|
#if (_WIN32_WINNT >= 0x0600)
|
||||||
|
#define QGA_NANOSECONDS 10000000
|
||||||
|
|
||||||
|
GHashTable *cache = NULL;
|
||||||
|
GuestUserList *head = NULL, *cur_item = NULL;
|
||||||
|
|
||||||
|
DWORD buffer_size = 0, count = 0, i = 0;
|
||||||
|
GA_WTSINFOA *info = NULL;
|
||||||
|
WTS_SESSION_INFOA *entries = NULL;
|
||||||
|
GuestUserList *item = NULL;
|
||||||
|
GuestUser *user = NULL;
|
||||||
|
gpointer value = NULL;
|
||||||
|
INT64 login = 0;
|
||||||
|
double login_time = 0;
|
||||||
|
|
||||||
|
cache = g_hash_table_new(g_str_hash, g_str_equal);
|
||||||
|
|
||||||
|
if (WTSEnumerateSessionsA(NULL, 0, 1, &entries, &count)) {
|
||||||
|
for (i = 0; i < count; ++i) {
|
||||||
|
buffer_size = 0;
|
||||||
|
info = NULL;
|
||||||
|
if (WTSQuerySessionInformationA(
|
||||||
|
NULL,
|
||||||
|
entries[i].SessionId,
|
||||||
|
WTSSessionInfo,
|
||||||
|
(LPSTR *)&info,
|
||||||
|
&buffer_size
|
||||||
|
)) {
|
||||||
|
|
||||||
|
if (strlen(info->UserName) == 0) {
|
||||||
|
WTSFreeMemory(info);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
login = info->LogonTime.QuadPart;
|
||||||
|
login -= W32_FT_OFFSET;
|
||||||
|
login_time = ((double)login) / QGA_NANOSECONDS;
|
||||||
|
|
||||||
|
if (g_hash_table_contains(cache, info->UserName)) {
|
||||||
|
value = g_hash_table_lookup(cache, info->UserName);
|
||||||
|
user = (GuestUser *)value;
|
||||||
|
if (user->login_time > login_time) {
|
||||||
|
user->login_time = login_time;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item = g_new0(GuestUserList, 1);
|
||||||
|
item->value = g_new0(GuestUser, 1);
|
||||||
|
|
||||||
|
item->value->user = g_strdup(info->UserName);
|
||||||
|
item->value->domain = g_strdup(info->Domain);
|
||||||
|
item->value->has_domain = true;
|
||||||
|
|
||||||
|
item->value->login_time = login_time;
|
||||||
|
|
||||||
|
g_hash_table_add(cache, item->value->user);
|
||||||
|
|
||||||
|
if (!cur_item) {
|
||||||
|
head = cur_item = item;
|
||||||
|
} else {
|
||||||
|
cur_item->next = item;
|
||||||
|
cur_item = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WTSFreeMemory(info);
|
||||||
|
}
|
||||||
|
WTSFreeMemory(entries);
|
||||||
|
}
|
||||||
|
g_hash_table_destroy(cache);
|
||||||
|
return head;
|
||||||
|
#else
|
||||||
|
error_setg(err, QERR_UNSUPPORTED);
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -499,3 +499,52 @@ int ga_parse_whence(GuestFileWhence *whence, Error **errp)
|
||||||
error_setg(errp, "invalid whence code %"PRId64, whence->u.value);
|
error_setg(errp, "invalid whence code %"PRId64, whence->u.value);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GuestHostName *qmp_guest_get_host_name(Error **err)
|
||||||
|
{
|
||||||
|
GuestHostName *result = NULL;
|
||||||
|
gchar const *hostname = g_get_host_name();
|
||||||
|
if (hostname != NULL) {
|
||||||
|
result = g_new0(GuestHostName, 1);
|
||||||
|
result->host_name = g_strdup(hostname);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
GuestTimezone *qmp_guest_get_timezone(Error **errp)
|
||||||
|
{
|
||||||
|
#if GLIB_CHECK_VERSION(2, 28, 0)
|
||||||
|
GuestTimezone *info = NULL;
|
||||||
|
GTimeZone *tz = NULL;
|
||||||
|
gint64 now = 0;
|
||||||
|
gint32 intv = 0;
|
||||||
|
gchar const *name = NULL;
|
||||||
|
|
||||||
|
info = g_new0(GuestTimezone, 1);
|
||||||
|
tz = g_time_zone_new_local();
|
||||||
|
if (tz == NULL) {
|
||||||
|
error_setg(errp, QERR_QGA_COMMAND_FAILED,
|
||||||
|
"Couldn't retrieve local timezone");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
now = g_get_real_time() / G_USEC_PER_SEC;
|
||||||
|
intv = g_time_zone_find_interval(tz, G_TIME_TYPE_UNIVERSAL, now);
|
||||||
|
info->offset = g_time_zone_get_offset(tz, intv);
|
||||||
|
name = g_time_zone_get_abbreviation(tz, intv);
|
||||||
|
if (name != NULL) {
|
||||||
|
info->has_zone = true;
|
||||||
|
info->zone = g_strdup(name);
|
||||||
|
}
|
||||||
|
g_time_zone_unref(tz);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_free(info);
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
|
error_setg(errp, QERR_UNSUPPORTED);
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
23
qga/main.c
23
qga/main.c
|
@ -131,9 +131,32 @@ static void quit_handler(int sig)
|
||||||
* unless all log/pid files are on unfreezable filesystems. there's
|
* unless all log/pid files are on unfreezable filesystems. there's
|
||||||
* also a very likely chance killing the agent before unfreezing
|
* also a very likely chance killing the agent before unfreezing
|
||||||
* the filesystems is a mistake (or will be viewed as one later).
|
* the filesystems is a mistake (or will be viewed as one later).
|
||||||
|
* On Windows the freeze interval is limited to 10 seconds, so
|
||||||
|
* we should quit, but first we should wait for the timeout, thaw
|
||||||
|
* the filesystem and quit.
|
||||||
*/
|
*/
|
||||||
if (ga_is_frozen(ga_state)) {
|
if (ga_is_frozen(ga_state)) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
int i = 0;
|
||||||
|
Error *err = NULL;
|
||||||
|
HANDLE hEventTimeout;
|
||||||
|
|
||||||
|
g_debug("Thawing filesystems before exiting");
|
||||||
|
|
||||||
|
hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT);
|
||||||
|
if (hEventTimeout) {
|
||||||
|
WaitForSingleObject(hEventTimeout, 0);
|
||||||
|
CloseHandle(hEventTimeout);
|
||||||
|
}
|
||||||
|
qga_vss_fsfreeze(&i, false, &err);
|
||||||
|
if (err) {
|
||||||
|
g_debug("Error unfreezing filesystems prior to exiting: %s",
|
||||||
|
error_get_pretty(err));
|
||||||
|
error_free(err);
|
||||||
|
}
|
||||||
|
#else
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
g_debug("received signal num %d, quitting", sig);
|
g_debug("received signal num %d, quitting", sig);
|
||||||
|
|
||||||
|
|
|
@ -426,7 +426,13 @@
|
||||||
##
|
##
|
||||||
# @guest-fsfreeze-freeze:
|
# @guest-fsfreeze-freeze:
|
||||||
#
|
#
|
||||||
# Sync and freeze all freezable, local guest filesystems
|
# Sync and freeze all freezable, local guest filesystems. If this
|
||||||
|
# command succeeded, you may call @guest-fsfreeze-thaw later to
|
||||||
|
# unfreeze.
|
||||||
|
#
|
||||||
|
# Note: On Windows, the command is implemented with the help of a
|
||||||
|
# Volume Shadow-copy Service DLL helper. The frozen state is limited
|
||||||
|
# for up to 10 seconds by VSS.
|
||||||
#
|
#
|
||||||
# Returns: Number of file systems currently frozen. On error, all filesystems
|
# Returns: Number of file systems currently frozen. On error, all filesystems
|
||||||
# will be thawed.
|
# will be thawed.
|
||||||
|
@ -439,10 +445,12 @@
|
||||||
##
|
##
|
||||||
# @guest-fsfreeze-freeze-list:
|
# @guest-fsfreeze-freeze-list:
|
||||||
#
|
#
|
||||||
# Sync and freeze specified guest filesystems
|
# Sync and freeze specified guest filesystems.
|
||||||
|
# See also @guest-fsfreeze-freeze.
|
||||||
#
|
#
|
||||||
# @mountpoints: an array of mountpoints of filesystems to be frozen.
|
# @mountpoints: an array of mountpoints of filesystems to be frozen.
|
||||||
# If omitted, every mounted filesystem is frozen.
|
# If omitted, every mounted filesystem is frozen.
|
||||||
|
# Invalid mount points are ignored.
|
||||||
#
|
#
|
||||||
# Returns: Number of file systems currently frozen. On error, all filesystems
|
# Returns: Number of file systems currently frozen. On error, all filesystems
|
||||||
# will be thawed.
|
# will be thawed.
|
||||||
|
@ -1042,3 +1050,79 @@
|
||||||
'data': { 'path': 'str', '*arg': ['str'], '*env': ['str'],
|
'data': { 'path': 'str', '*arg': ['str'], '*env': ['str'],
|
||||||
'*input-data': 'str', '*capture-output': 'bool' },
|
'*input-data': 'str', '*capture-output': 'bool' },
|
||||||
'returns': 'GuestExec' }
|
'returns': 'GuestExec' }
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# @GuestHostName:
|
||||||
|
# @host-name: Fully qualified domain name of the guest OS
|
||||||
|
#
|
||||||
|
# Since: 2.10
|
||||||
|
##
|
||||||
|
{ 'struct': 'GuestHostName',
|
||||||
|
'data': { 'host-name': 'str' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @guest-get-host-name:
|
||||||
|
#
|
||||||
|
# Return a name for the machine.
|
||||||
|
#
|
||||||
|
# The returned name is not necessarily a fully-qualified domain name, or even
|
||||||
|
# present in DNS or some other name service at all. It need not even be unique
|
||||||
|
# on your local network or site, but usually it is.
|
||||||
|
#
|
||||||
|
# Returns: the host name of the machine on success
|
||||||
|
#
|
||||||
|
# Since: 2.10
|
||||||
|
##
|
||||||
|
{ 'command': 'guest-get-host-name',
|
||||||
|
'returns': 'GuestHostName' }
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# @GuestUser:
|
||||||
|
# @user: Username
|
||||||
|
# @domain: Logon domain (windows only)
|
||||||
|
# @login-time: Time of login of this user on the computer. If multiple
|
||||||
|
# instances of the user are logged in, the earliest login time is
|
||||||
|
# reported. The value is in fractional seconds since epoch time.
|
||||||
|
#
|
||||||
|
# Since: 2.10
|
||||||
|
##
|
||||||
|
{ 'struct': 'GuestUser',
|
||||||
|
'data': { 'user': 'str', 'login-time': 'number', '*domain': 'str' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @guest-get-users:
|
||||||
|
# Retrieves a list of currently active users on the VM.
|
||||||
|
#
|
||||||
|
# Returns: A unique list of users.
|
||||||
|
#
|
||||||
|
# Since: 2.10
|
||||||
|
##
|
||||||
|
{ 'command': 'guest-get-users',
|
||||||
|
'returns': ['GuestUser'] }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @GuestTimezone:
|
||||||
|
#
|
||||||
|
# @zone: Timezone name. These values may differ depending on guest/OS and
|
||||||
|
# should only be used for informational purposes.
|
||||||
|
# @offset: Offset to UTC in seconds, negative numbers for time zones west of
|
||||||
|
# GMT, positive numbers for east
|
||||||
|
#
|
||||||
|
# Since: 2.10
|
||||||
|
##
|
||||||
|
{ 'struct': 'GuestTimezone',
|
||||||
|
'data': { '*zone': 'str', 'offset': 'int' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @guest-get-timezone:
|
||||||
|
#
|
||||||
|
# Retrieves the timezone information from the guest.
|
||||||
|
#
|
||||||
|
# Returns: A GuestTimezone dictionary.
|
||||||
|
#
|
||||||
|
# Since: 2.10
|
||||||
|
##
|
||||||
|
{ 'command': 'guest-get-timezone',
|
||||||
|
'returns': 'GuestTimezone' }
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#ifndef VSS_WIN32_H
|
#ifndef VSS_WIN32_H
|
||||||
#define VSS_WIN32_H
|
#define VSS_WIN32_H
|
||||||
|
|
||||||
|
#include "qga/vss-win32/vss-handles.h"
|
||||||
|
|
||||||
bool vss_init(bool init_requester);
|
bool vss_init(bool init_requester);
|
||||||
void vss_deinit(bool deinit_requester);
|
void vss_deinit(bool deinit_requester);
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include "vss-common.h"
|
#include "vss-common.h"
|
||||||
#include <inc/win2003/vscoordint.h>
|
#include <inc/win2003/vscoordint.h>
|
||||||
#include <comadmin.h>
|
#include "install.h"
|
||||||
#include <wbemidl.h>
|
#include <wbemidl.h>
|
||||||
#include <comdef.h>
|
#include <comdef.h>
|
||||||
#include <comutil.h>
|
#include <comutil.h>
|
||||||
|
@ -276,7 +276,7 @@ STDAPI COMRegister(void)
|
||||||
|
|
||||||
chk(pCatalog->CreateServiceForApplication(
|
chk(pCatalog->CreateServiceForApplication(
|
||||||
_bstr_t(QGA_PROVIDER_LNAME), _bstr_t(QGA_PROVIDER_LNAME),
|
_bstr_t(QGA_PROVIDER_LNAME), _bstr_t(QGA_PROVIDER_LNAME),
|
||||||
_bstr_t(L"SERVICE_AUTO_START"), _bstr_t(L"SERVICE_ERROR_NORMAL"),
|
_bstr_t(L"SERVICE_DEMAND_START"), _bstr_t(L"SERVICE_ERROR_NORMAL"),
|
||||||
_bstr_t(L""), _bstr_t(L".\\localsystem"), _bstr_t(L""), FALSE));
|
_bstr_t(L""), _bstr_t(L".\\localsystem"), _bstr_t(L""), FALSE));
|
||||||
chk(pCatalog->InstallComponent(_bstr_t(QGA_PROVIDER_LNAME),
|
chk(pCatalog->InstallComponent(_bstr_t(QGA_PROVIDER_LNAME),
|
||||||
_bstr_t(dllPath), _bstr_t(tlbPath),
|
_bstr_t(dllPath), _bstr_t(tlbPath),
|
||||||
|
@ -461,3 +461,27 @@ namespace _com_util
|
||||||
return bstr;
|
return bstr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stop QGA VSS provider service from COM+ Application Admin Catalog */
|
||||||
|
|
||||||
|
STDAPI StopService(void)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
COMInitializer initializer;
|
||||||
|
COMPointer<IUnknown> pUnknown;
|
||||||
|
COMPointer<ICOMAdminCatalog2> pCatalog;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
chk(QGAProviderFind(QGAProviderCount, (void *)&count));
|
||||||
|
if (count) {
|
||||||
|
chk(CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER,
|
||||||
|
IID_IUnknown, (void **)pUnknown.replace()));
|
||||||
|
chk(pUnknown->QueryInterface(IID_ICOMAdminCatalog2,
|
||||||
|
(void **)pCatalog.replace()));
|
||||||
|
chk(pCatalog->ShutdownApplication(_bstr_t(QGA_PROVIDER_LNAME)));
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* QEMU Guest Agent VSS requester declarations
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INSTALL_H
|
||||||
|
#define INSTALL_H
|
||||||
|
|
||||||
|
#include <comadmin.h>
|
||||||
|
|
||||||
|
STDAPI StopService(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -377,7 +377,6 @@ STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId)
|
||||||
if (WaitForSingleObject(hEventThaw, VSS_TIMEOUT_MSEC) != WAIT_OBJECT_0) {
|
if (WaitForSingleObject(hEventThaw, VSS_TIMEOUT_MSEC) != WAIT_OBJECT_0) {
|
||||||
/* Send event to qemu-ga to notify the provider is timed out */
|
/* Send event to qemu-ga to notify the provider is timed out */
|
||||||
SetEvent(hEventTimeout);
|
SetEvent(hEventTimeout);
|
||||||
hr = E_ABORT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(hEventThaw);
|
CloseHandle(hEventThaw);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "vss-common.h"
|
#include "vss-common.h"
|
||||||
#include "requester.h"
|
#include "requester.h"
|
||||||
|
#include "install.h"
|
||||||
#include <inc/win2003/vswriter.h>
|
#include <inc/win2003/vswriter.h>
|
||||||
#include <inc/win2003/vsbackup.h>
|
#include <inc/win2003/vsbackup.h>
|
||||||
|
|
||||||
|
@ -501,4 +502,5 @@ void requester_thaw(int *num_vols, ErrorSet *errset)
|
||||||
requester_cleanup();
|
requester_cleanup();
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
|
StopService();
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,21 +51,12 @@
|
||||||
* http://www.microsoft.com/en-us/download/details.aspx?id=23490
|
* http://www.microsoft.com/en-us/download/details.aspx?id=23490
|
||||||
*/
|
*/
|
||||||
#include <inc/win2003/vss.h>
|
#include <inc/win2003/vss.h>
|
||||||
|
#include "vss-handles.h"
|
||||||
|
|
||||||
/* Macros to convert char definitions to wchar */
|
/* Macros to convert char definitions to wchar */
|
||||||
#define _L(a) L##a
|
#define _L(a) L##a
|
||||||
#define L(a) _L(a)
|
#define L(a) _L(a)
|
||||||
|
|
||||||
/* Constants for QGA VSS Provider */
|
|
||||||
|
|
||||||
#define QGA_PROVIDER_NAME "QEMU Guest Agent VSS Provider"
|
|
||||||
#define QGA_PROVIDER_LNAME L(QGA_PROVIDER_NAME)
|
|
||||||
#define QGA_PROVIDER_VERSION L(QEMU_VERSION)
|
|
||||||
|
|
||||||
#define EVENT_NAME_FROZEN "Global\\QGAVSSEvent-frozen"
|
|
||||||
#define EVENT_NAME_THAW "Global\\QGAVSSEvent-thaw"
|
|
||||||
#define EVENT_NAME_TIMEOUT "Global\\QGAVSSEvent-timeout"
|
|
||||||
|
|
||||||
const GUID g_gProviderId = { 0x3629d4ed, 0xee09, 0x4e0e,
|
const GUID g_gProviderId = { 0x3629d4ed, 0xee09, 0x4e0e,
|
||||||
{0x9a, 0x5c, 0x6d, 0x8b, 0xa2, 0x87, 0x2a, 0xef} };
|
{0x9a, 0x5c, 0x6d, 0x8b, 0xa2, 0x87, 0x2a, 0xef} };
|
||||||
const GUID g_gProviderVersion = { 0x11ef8b15, 0xcac6, 0x40d6,
|
const GUID g_gProviderVersion = { 0x11ef8b15, 0xcac6, 0x40d6,
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef VSS_HANDLES
|
||||||
|
#define VSS_HANDLES
|
||||||
|
|
||||||
|
/* Constants for QGA VSS Provider */
|
||||||
|
|
||||||
|
#define QGA_PROVIDER_NAME "QEMU Guest Agent VSS Provider"
|
||||||
|
#define QGA_PROVIDER_LNAME L(QGA_PROVIDER_NAME)
|
||||||
|
#define QGA_PROVIDER_VERSION L(QEMU_VERSION)
|
||||||
|
|
||||||
|
#define EVENT_NAME_FROZEN "Global\\QGAVSSEvent-frozen"
|
||||||
|
#define EVENT_NAME_THAW "Global\\QGAVSSEvent-thaw"
|
||||||
|
#define EVENT_NAME_TIMEOUT "Global\\QGAVSSEvent-timeout"
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue