qga-pull-2024-07-23

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEwsLBCepDxjwUI+uE711egWG6hOcFAmafUs0ACgkQ711egWG6
 hOffwQ/+PMFMOq3jwV11Na0GnrFHT0SLlcxNWYGQjE0Q/nwuYWMTKdo2iB9rVC7T
 qxaT6PLtTZPgRsJudJ5kkvLFw88Nr6BuWl31tCVeALUO7C0oTg/oRDfYVeH4/jfG
 PS5TiM6ie27SvI5lhGZhd9sRAy8N6NGgT6Fh+pS2tVVfftcfVYKVmnzgtvk314A+
 MpeW8ukVruSW+9G+suXaE750g/drZJAoepC5pW1HXdHE+IuzXNdMWZqwMqBZSM5T
 X8VcLvMjFrFrfLOP2el6mloriw67aJyKe9Uwsp548HdXfZKrLCmaR7cZK5zKVQDK
 Rzolyuw19wNNi0TZAwmP+MBioDiIHcM4nNhVDCHIVCbXzQHa4BhAr/cr8uucyfM5
 hdCWmaTl4Tksk4q4ooHurDWshV26QNRbLRD1Vx1Rhrwz42MmU2VG13PsSWqLj00I
 fj1LzhQOmr26cewgayIL7ODwHDXiwKi+6lKS1OyTjXXubucScgxSyTNC785T6Rvk
 T58KAnBRD3vDhE7Dn/4KdRClRFY+7R2/jcHdFnA4vfvOVV8ZXp/m0O0wfLEikH6/
 dGDDVBLNG5gqV477++0wdqkYFq6MmON3PH/EA6rgZYc4At5kS+HFNASBvnFRYMGf
 dgtyj8jV5uoffqYOqyXxClP6eTgV1EZ0/wKZ8uJipivB7azjnkE=
 =xzjT
 -----END PGP SIGNATURE-----

Merge tag 'qga-pull-2024-07-23' of https://github.com/kostyanf14/qemu into staging

qga-pull-2024-07-23

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwsLBCepDxjwUI+uE711egWG6hOcFAmafUs0ACgkQ711egWG6
# hOffwQ/+PMFMOq3jwV11Na0GnrFHT0SLlcxNWYGQjE0Q/nwuYWMTKdo2iB9rVC7T
# qxaT6PLtTZPgRsJudJ5kkvLFw88Nr6BuWl31tCVeALUO7C0oTg/oRDfYVeH4/jfG
# PS5TiM6ie27SvI5lhGZhd9sRAy8N6NGgT6Fh+pS2tVVfftcfVYKVmnzgtvk314A+
# MpeW8ukVruSW+9G+suXaE750g/drZJAoepC5pW1HXdHE+IuzXNdMWZqwMqBZSM5T
# X8VcLvMjFrFrfLOP2el6mloriw67aJyKe9Uwsp548HdXfZKrLCmaR7cZK5zKVQDK
# Rzolyuw19wNNi0TZAwmP+MBioDiIHcM4nNhVDCHIVCbXzQHa4BhAr/cr8uucyfM5
# hdCWmaTl4Tksk4q4ooHurDWshV26QNRbLRD1Vx1Rhrwz42MmU2VG13PsSWqLj00I
# fj1LzhQOmr26cewgayIL7ODwHDXiwKi+6lKS1OyTjXXubucScgxSyTNC785T6Rvk
# T58KAnBRD3vDhE7Dn/4KdRClRFY+7R2/jcHdFnA4vfvOVV8ZXp/m0O0wfLEikH6/
# dGDDVBLNG5gqV477++0wdqkYFq6MmON3PH/EA6rgZYc4At5kS+HFNASBvnFRYMGf
# dgtyj8jV5uoffqYOqyXxClP6eTgV1EZ0/wKZ8uJipivB7azjnkE=
# =xzjT
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 23 Jul 2024 04:50:53 PM AEST
# gpg:                using RSA key C2C2C109EA43C63C1423EB84EF5D5E8161BA84E7
# gpg: Good signature from "Kostiantyn Kostiuk (Upstream PR sign) <kkostiuk@redhat.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: C2C2 C109 EA43 C63C 1423  EB84 EF5D 5E81 61BA 84E7

* tag 'qga-pull-2024-07-23' of https://github.com/kostyanf14/qemu: (25 commits)
  qga/linux: Add new api 'guest-network-get-route'
  guest-agent: document allow-rpcs in config file section
  qga/commands-posix: Make ga_wait_child() return boolean
  qga: centralize logic for disabling/enabling commands
  qga: allow configuration file path via the cli
  qga: remove pointless 'blockrpcs_key' variable
  qga: move declare of QGAConfig struct to top of file
  qga: don't disable fsfreeze commands if vss_init fails
  qga: conditionalize schema for commands not supported on other UNIX
  qga: conditionalize schema for commands requiring utmpx
  qga: conditionalize schema for commands requiring libudev
  qga: conditionalize schema for commands requiring fstrim
  qga: conditionalize schema for commands requiring fsfreeze
  qga: conditionalize schema for commands only supported on Windows
  qga: conditionalize schema for commands requiring linux/win32
  qga: conditionalize schema for commands requiring getifaddrs
  qga: conditionalize schema for commands unsupported on non-Linux POSIX
  qga: conditionalize schema for commands unsupported on Windows
  qga: move CONFIG_FSFREEZE/TRIM to be meson defined options
  qga: move linux memory block command impls to commands-linux.c
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2024-07-24 01:00:22 +10:00
commit 3b5efc553e
9 changed files with 2274 additions and 2288 deletions

View File

@ -28,11 +28,30 @@ configuration options on the command line. For the same key, the last
option wins, but the lists accumulate (see below for configuration
file format).
If an allowed RPCs list is defined in the configuration, then all
RPCs will be blocked by default, except for the allowed list.
If a blocked RPCs list is defined in the configuration, then all
RPCs will be allowed by default, except for the blocked list.
If both allowed and blocked RPCs lists are defined in the configuration,
then all RPCs will be blocked by default, then the allowed list will
be applied, followed by the blocked list.
While filesystems are frozen, all except for a designated safe set
of RPCs will blocked, regardless of what the general configuration
declares.
Options
-------
.. program:: qemu-ga
.. option:: -c, --config=PATH
Configuration file path (the default is |CONFDIR|\ ``/qemu-ga.conf``,
unless overriden by the QGA_CONF environment variable)
.. option:: -m, --method=METHOD
Transport method: one of ``unix-listen``, ``virtio-serial``, or
@ -131,6 +150,7 @@ fsfreeze-hook string
statedir string
verbose boolean
block-rpcs string list
allow-rpcs string list
============= ===========
See also

View File

@ -2187,6 +2187,19 @@ have_virtfs_proxy_helper = get_option('virtfs_proxy_helper') \
.require(libcap_ng.found(), error_message: 'the virtfs proxy helper requires libcap-ng') \
.allowed()
qga_fsfreeze = false
qga_fstrim = false
if host_os == 'linux'
if cc.has_header_symbol('linux/fs.h', 'FIFREEZE')
qga_fsfreeze = true
endif
if cc.has_header_symbol('linux/fs.h', 'FITRIM')
qga_fstrim = true
endif
elif host_os == 'freebsd' and cc.has_header_symbol('ufs/ffs/fs.h', 'UFSSUSPEND')
qga_fsfreeze = true
endif
if get_option('block_drv_ro_whitelist') == ''
config_host_data.set('CONFIG_BDRV_RO_WHITELIST', '')
else
@ -2263,6 +2276,7 @@ config_host_data.set('CONFIG_ATTR', libattr.found())
config_host_data.set('CONFIG_BDRV_WHITELIST_TOOLS', get_option('block_drv_whitelist_in_tools'))
config_host_data.set('CONFIG_BRLAPI', brlapi.found())
config_host_data.set('CONFIG_BSD', host_os in bsd_oses)
config_host_data.set('CONFIG_FREEBSD', host_os == 'freebsd')
config_host_data.set('CONFIG_CAPSTONE', capstone.found())
config_host_data.set('CONFIG_COCOA', cocoa.found())
config_host_data.set('CONFIG_DARWIN', host_os == 'darwin')
@ -2423,6 +2437,8 @@ config_host_data.set('CONFIG_DEBUG_TCG', get_option('debug_tcg'))
config_host_data.set('CONFIG_DEBUG_REMAP', get_option('debug_remap'))
config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug'))
config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed())
config_host_data.set('CONFIG_FSFREEZE', qga_fsfreeze)
config_host_data.set('CONFIG_FSTRIM', qga_fstrim)
# has_header
config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h'))

View File

@ -149,30 +149,6 @@ int qmp_guest_fsfreeze_do_thaw(Error **errp)
}
return ret;
}
GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
return NULL;
}
GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
return NULL;
}
GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
return NULL;
}
GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
return NULL;
}
#endif /* CONFIG_FSFREEZE */
#ifdef HAVE_GETIFADDRS

View File

@ -15,19 +15,10 @@
#if defined(__linux__)
#include <linux/fs.h>
#ifdef FIFREEZE
#define CONFIG_FSFREEZE
#endif
#ifdef FITRIM
#define CONFIG_FSTRIM
#endif
#endif /* __linux__ */
#ifdef __FreeBSD__
#include <ufs/ffs/fs.h>
#ifdef UFSSUSPEND
#define CONFIG_FSFREEZE
#endif
#endif /* __FreeBSD__ */
#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1203,7 +1203,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
{
if (!vss_initialized()) {
error_setg(errp, QERR_UNSUPPORTED);
error_setg(errp, "fsfreeze not possible as VSS failed to initialize");
return 0;
}
@ -1231,7 +1231,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
Error *local_err = NULL;
if (!vss_initialized()) {
error_setg(errp, QERR_UNSUPPORTED);
error_setg(errp, "fsfreeze not possible as VSS failed to initialize");
return 0;
}
@ -1266,7 +1266,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
int i;
if (!vss_initialized()) {
error_setg(errp, QERR_UNSUPPORTED);
error_setg(errp, "fsfreeze not possible as VSS failed to initialize");
return 0;
}
@ -1494,11 +1494,6 @@ out:
}
}
void qmp_guest_suspend_hybrid(Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
}
static IP_ADAPTER_ADDRESSES *guest_get_adapters_addresses(Error **errp)
{
IP_ADAPTER_ADDRESSES *adptr_addrs = NULL;
@ -1862,12 +1857,6 @@ GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
return NULL;
}
int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
return -1;
}
static gchar *
get_net_error_message(gint error)
{
@ -1969,55 +1958,6 @@ done:
g_free(rawpasswddata);
}
GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
return NULL;
}
GuestMemoryBlockResponseList *
qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
return NULL;
}
GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
return NULL;
}
/* add unsupported commands to the list of blocked RPCs */
GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
{
const char *list_unsupported[] = {
"guest-suspend-hybrid",
"guest-set-vcpus",
"guest-get-memory-blocks", "guest-set-memory-blocks",
"guest-get-memory-block-size", "guest-get-memory-block-info",
NULL};
char **p = (char **)list_unsupported;
while (*p) {
blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
}
if (!vss_init(true)) {
g_debug("vss_init failed, vss commands are going to be disabled");
const char *list[] = {
"guest-get-fsinfo", "guest-fsfreeze-status",
"guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL};
p = (char **)list;
while (*p) {
blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
}
}
return blockedrpcs;
}
/* register init/cleanup routines for stateful command groups */
void ga_command_state_init(GAState *s, GACommandState *cs)
{
@ -2505,15 +2445,3 @@ char *qga_get_host_name(Error **errp)
return g_utf16_to_utf8(tmp, size, NULL, NULL, NULL);
}
GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
return NULL;
}
GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
return NULL;
}

View File

@ -70,6 +70,28 @@ typedef struct GAPersistentState {
typedef struct GAConfig GAConfig;
struct GAConfig {
char *channel_path;
char *method;
char *log_filepath;
char *pid_filepath;
#ifdef CONFIG_FSFREEZE
char *fsfreeze_hook;
#endif
char *state_dir;
#ifdef _WIN32
const char *service;
#endif
gchar *bliststr; /* blockedrpcs may point to this string */
gchar *aliststr; /* allowedrpcs may point to this string */
GList *blockedrpcs;
GList *allowedrpcs;
int daemonize;
GLogLevelFlags log_level;
int dumpconf;
bool retry_path;
};
struct GAState {
JSONMessageParser parser;
GMainLoop *main_loop;
@ -226,12 +248,16 @@ static void usage(const char *cmd)
#ifdef CONFIG_FSFREEZE
g_autofree char *fsfreeze_hook = get_relocated_path(QGA_FSFREEZE_HOOK_DEFAULT);
#endif
g_autofree char *conf_path = get_relocated_path(QGA_CONF_DEFAULT);
printf(
"Usage: %s [-m <method> -p <path>] [<options>]\n"
"QEMU Guest Agent " QEMU_FULL_VERSION "\n"
QEMU_COPYRIGHT "\n"
"\n"
" -c, --config=PATH configuration file path (default is\n"
" %s/qemu-ga.conf\n"
" unless overriden by the QGA_CONF environment variable)\n"
" -m, --method transport method: one of unix-listen, virtio-serial,\n"
" isa-serial, or vsock-listen (virtio-serial is the default)\n"
" -p, --path device/socket path (the default for virtio-serial is:\n"
@ -272,8 +298,8 @@ QEMU_COPYRIGHT "\n"
" plug/unplug, etc.)\n"
" -h, --help display this help and exit\n"
"\n"
QEMU_HELP_BOTTOM "\n"
, cmd, QGA_VIRTIO_PATH_DEFAULT, QGA_SERIAL_PATH_DEFAULT,
QEMU_HELP_BOTTOM "\n",
cmd, conf_path, QGA_VIRTIO_PATH_DEFAULT, QGA_SERIAL_PATH_DEFAULT,
dfl_pathnames.pidfile,
#ifdef CONFIG_FSFREEZE
fsfreeze_hook,
@ -397,58 +423,77 @@ static gint ga_strcmp(gconstpointer str1, gconstpointer str2)
return strcmp(str1, str2);
}
/* disable commands that aren't safe for fsfreeze */
static void ga_disable_not_allowed_freeze(const QmpCommand *cmd, void *opaque)
static bool ga_command_is_allowed(const QmpCommand *cmd, GAState *state)
{
bool allowed = false;
int i = 0;
GAConfig *config = state->config;
const char *name = qmp_command_name(cmd);
/* Fallback policy is allow everything */
bool allowed = true;
while (ga_freeze_allowlist[i] != NULL) {
if (strcmp(name, ga_freeze_allowlist[i]) == 0) {
if (config->allowedrpcs) {
/*
* If an allow-list is given, this changes the fallback
* policy to deny everything
*/
allowed = false;
if (g_list_find_custom(config->allowedrpcs, name, ga_strcmp) != NULL) {
allowed = true;
}
i++;
}
if (!allowed) {
g_debug("disabling command: %s", name);
qmp_disable_command(&ga_commands, name, "the agent is in frozen state");
/*
* If both allowedrpcs and blockedrpcs are set, the blocked
* list will take priority
*/
if (config->blockedrpcs) {
if (g_list_find_custom(config->blockedrpcs, name, ga_strcmp) != NULL) {
allowed = false;
}
}
/*
* If frozen, this filtering must take priority over
* absolutely everything
*/
if (state->frozen) {
allowed = false;
while (ga_freeze_allowlist[i] != NULL) {
if (strcmp(name, ga_freeze_allowlist[i]) == 0) {
allowed = true;
}
i++;
}
}
return allowed;
}
/* [re-]enable all commands, except those explicitly blocked by user */
static void ga_enable_non_blocked(const QmpCommand *cmd, void *opaque)
static void ga_apply_command_filters_iter(const QmpCommand *cmd, void *opaque)
{
GAState *s = opaque;
GList *blockedrpcs = s->blockedrpcs;
GList *allowedrpcs = s->allowedrpcs;
GAState *state = opaque;
bool want = ga_command_is_allowed(cmd, state);
bool have = qmp_command_is_enabled(cmd);
const char *name = qmp_command_name(cmd);
if (g_list_find_custom(blockedrpcs, name, ga_strcmp) == NULL) {
if (qmp_command_is_enabled(cmd)) {
return;
}
if (allowedrpcs &&
g_list_find_custom(allowedrpcs, name, ga_strcmp) == NULL) {
return;
}
if (want == have) {
return;
}
if (have) {
g_debug("disabling command: %s", name);
qmp_disable_command(&ga_commands, name, "the command is not allowed");
} else {
g_debug("enabling command: %s", name);
qmp_enable_command(&ga_commands, name);
}
}
/* disable commands that aren't allowed */
static void ga_disable_not_allowed(const QmpCommand *cmd, void *opaque)
static void ga_apply_command_filters(GAState *state)
{
GList *allowedrpcs = opaque;
const char *name = qmp_command_name(cmd);
if (g_list_find_custom(allowedrpcs, name, ga_strcmp) == NULL) {
g_debug("disabling command: %s", name);
qmp_disable_command(&ga_commands, name, "the command is not allowed");
}
qmp_for_each_command(&ga_commands, ga_apply_command_filters_iter, state);
}
static bool ga_create_file(const char *path)
@ -483,15 +528,14 @@ void ga_set_frozen(GAState *s)
if (ga_is_frozen(s)) {
return;
}
/* disable all forbidden (for frozen state) commands */
qmp_for_each_command(&ga_commands, ga_disable_not_allowed_freeze, NULL);
g_warning("disabling logging due to filesystem freeze");
ga_disable_logging(s);
s->frozen = true;
if (!ga_create_file(s->state_filepath_isfrozen)) {
g_warning("unable to create %s, fsfreeze may not function properly",
s->state_filepath_isfrozen);
}
ga_apply_command_filters(s);
ga_disable_logging(s);
}
void ga_unset_frozen(GAState *s)
@ -523,12 +567,12 @@ void ga_unset_frozen(GAState *s)
}
/* enable all disabled, non-blocked and allowed commands */
qmp_for_each_command(&ga_commands, ga_enable_non_blocked, s);
s->frozen = false;
if (!ga_delete_file(s->state_filepath_isfrozen)) {
g_warning("unable to delete %s, fsfreeze may not function properly",
s->state_filepath_isfrozen);
}
ga_apply_command_filters(s);
}
#ifdef CONFIG_FSFREEZE
@ -996,38 +1040,14 @@ static GList *split_list(const gchar *str, const gchar *delim)
return list;
}
struct GAConfig {
char *channel_path;
char *method;
char *log_filepath;
char *pid_filepath;
#ifdef CONFIG_FSFREEZE
char *fsfreeze_hook;
#endif
char *state_dir;
#ifdef _WIN32
const char *service;
#endif
gchar *bliststr; /* blockedrpcs may point to this string */
gchar *aliststr; /* allowedrpcs may point to this string */
GList *blockedrpcs;
GList *allowedrpcs;
int daemonize;
GLogLevelFlags log_level;
int dumpconf;
bool retry_path;
};
static void config_load(GAConfig *config)
static void config_load(GAConfig *config, const char *confpath, bool required)
{
GError *gerr = NULL;
GKeyFile *keyfile;
g_autofree char *conf = g_strdup(g_getenv("QGA_CONF")) ?: get_relocated_path(QGA_CONF_DEFAULT);
const gchar *blockrpcs_key = "block-rpcs";
/* read system config */
keyfile = g_key_file_new();
if (!g_key_file_load_from_file(keyfile, conf, 0, &gerr)) {
if (!g_key_file_load_from_file(keyfile, confpath, 0, &gerr)) {
goto end;
}
if (g_key_file_has_key(keyfile, "general", "daemon", NULL)) {
@ -1071,9 +1091,9 @@ static void config_load(GAConfig *config)
g_key_file_get_boolean(keyfile, "general", "retry-path", &gerr);
}
if (g_key_file_has_key(keyfile, "general", blockrpcs_key, NULL)) {
if (g_key_file_has_key(keyfile, "general", "block-rpcs", NULL)) {
config->bliststr =
g_key_file_get_string(keyfile, "general", blockrpcs_key, &gerr);
g_key_file_get_string(keyfile, "general", "block-rpcs", &gerr);
config->blockedrpcs = g_list_concat(config->blockedrpcs,
split_list(config->bliststr, ","));
}
@ -1084,19 +1104,12 @@ static void config_load(GAConfig *config)
split_list(config->aliststr, ","));
}
if (g_key_file_has_key(keyfile, "general", blockrpcs_key, NULL) &&
g_key_file_has_key(keyfile, "general", "allow-rpcs", NULL)) {
g_critical("wrong config, using 'block-rpcs' and 'allow-rpcs' keys at"
" the same time is not allowed");
exit(EXIT_FAILURE);
}
end:
g_key_file_free(keyfile);
if (gerr &&
!(gerr->domain == G_FILE_ERROR && gerr->code == G_FILE_ERROR_NOENT)) {
if (gerr && (required ||
!(gerr->domain == G_FILE_ERROR && gerr->code == G_FILE_ERROR_NOENT))) {
g_critical("error loading configuration from path: %s, %s",
conf, gerr->message);
confpath, gerr->message);
exit(EXIT_FAILURE);
}
g_clear_error(&gerr);
@ -1168,12 +1181,12 @@ static void config_dump(GAConfig *config)
static void config_parse(GAConfig *config, int argc, char **argv)
{
const char *sopt = "hVvdm:p:l:f:F::b:a:s:t:Dr";
const char *sopt = "hVvdc:m:p:l:f:F::b:a:s:t:Dr";
int opt_ind = 0, ch;
bool block_rpcs = false, allow_rpcs = false;
const struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
{ "config", 1, NULL, 'c' },
{ "dump-conf", 0, NULL, 'D' },
{ "logfile", 1, NULL, 'l' },
{ "pidfile", 1, NULL, 'f' },
@ -1193,6 +1206,26 @@ static void config_parse(GAConfig *config, int argc, char **argv)
{ "retry-path", 0, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
g_autofree char *confpath = g_strdup(g_getenv("QGA_CONF")) ?:
get_relocated_path(QGA_CONF_DEFAULT);
bool confrequired = false;
while ((ch = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
switch (ch) {
case 'c':
g_free(confpath);
confpath = g_strdup(optarg);
confrequired = true;
break;
default:
break;
}
}
config_load(config, confpath, confrequired);
/* Reset for second pass */
optind = 1;
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
switch (ch) {
@ -1245,7 +1278,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
}
config->blockedrpcs = g_list_concat(config->blockedrpcs,
split_list(optarg, ","));
block_rpcs = true;
break;
}
case 'a': {
@ -1255,7 +1287,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
}
config->allowedrpcs = g_list_concat(config->allowedrpcs,
split_list(optarg, ","));
allow_rpcs = true;
break;
}
#ifdef _WIN32
@ -1296,12 +1327,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
exit(EXIT_FAILURE);
}
}
if (block_rpcs && allow_rpcs) {
g_critical("wrong commandline, using --block-rpcs and --allow-rpcs at the"
" same time is not allowed");
exit(EXIT_FAILURE);
}
}
static void config_free(GAConfig *config)
@ -1395,6 +1420,10 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
" '%s': %s", config->state_dir, strerror(errno));
return NULL;
}
if (!vss_init(true)) {
g_debug("vss_init failed, vss commands will not function");
}
#endif
if (ga_is_frozen(s)) {
@ -1408,7 +1437,6 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
s->deferred_options.log_filepath = config->log_filepath;
}
ga_disable_logging(s);
qmp_for_each_command(&ga_commands, ga_disable_not_allowed_freeze, NULL);
} else {
if (config->daemonize) {
become_daemon(config->pid_filepath);
@ -1432,25 +1460,6 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
return NULL;
}
if (config->allowedrpcs) {
qmp_for_each_command(&ga_commands, ga_disable_not_allowed, config->allowedrpcs);
s->allowedrpcs = config->allowedrpcs;
}
/*
* Some commands can be blocked due to system limitation.
* Initialize blockedrpcs list even if allowedrpcs specified.
*/
config->blockedrpcs = ga_command_init_blockedrpcs(config->blockedrpcs);
if (config->blockedrpcs) {
GList *l = config->blockedrpcs;
s->blockedrpcs = config->blockedrpcs;
do {
g_debug("disabling command: %s", (char *)l->data);
qmp_disable_command(&ga_commands, l->data, NULL);
l = g_list_next(l);
} while (l);
}
s->command_state = ga_command_state_new();
ga_command_state_init(s, s->command_state);
ga_command_state_init_all(s->command_state);
@ -1476,6 +1485,8 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
}
#endif
ga_apply_command_filters(s);
ga_state = s;
return s;
}
@ -1579,7 +1590,6 @@ int main(int argc, char **argv)
qga_qmp_init_marshal(&ga_commands);
init_dfl_pathnames();
config_load(config);
config_parse(config, argc, argv);
if (config->pid_filepath == NULL) {

View File

@ -412,7 +412,8 @@
# Since: 0.15.0
##
{ 'enum': 'GuestFsfreezeStatus',
'data': [ 'thawed', 'frozen' ] }
'data': [ 'thawed', 'frozen' ],
'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-status:
@ -429,7 +430,8 @@
# Since: 0.15.0
##
{ 'command': 'guest-fsfreeze-status',
'returns': 'GuestFsfreezeStatus' }
'returns': 'GuestFsfreezeStatus',
'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-freeze:
@ -451,7 +453,8 @@
# Since: 0.15.0
##
{ 'command': 'guest-fsfreeze-freeze',
'returns': 'int' }
'returns': 'int',
'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-freeze-list:
@ -471,7 +474,8 @@
##
{ 'command': 'guest-fsfreeze-freeze-list',
'data': { '*mountpoints': ['str'] },
'returns': 'int' }
'returns': 'int',
'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-thaw:
@ -488,7 +492,8 @@
# Since: 0.15.0
##
{ 'command': 'guest-fsfreeze-thaw',
'returns': 'int' }
'returns': 'int',
'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @GuestFilesystemTrimResult:
@ -505,7 +510,8 @@
##
{ 'struct': 'GuestFilesystemTrimResult',
'data': {'path': 'str',
'*trimmed': 'int', '*minimum': 'int', '*error': 'str'} }
'*trimmed': 'int', '*minimum': 'int', '*error': 'str'},
'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSTRIM'] } }
##
# @GuestFilesystemTrimResponse:
@ -515,7 +521,8 @@
# Since: 2.4
##
{ 'struct': 'GuestFilesystemTrimResponse',
'data': {'paths': ['GuestFilesystemTrimResult']} }
'data': {'paths': ['GuestFilesystemTrimResult']},
'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSTRIM'] } }
##
# @guest-fstrim:
@ -537,7 +544,8 @@
##
{ 'command': 'guest-fstrim',
'data': { '*minimum': 'int' },
'returns': 'GuestFilesystemTrimResponse' }
'returns': 'GuestFilesystemTrimResponse',
'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSTRIM'] } }
##
# @guest-suspend-disk:
@ -566,7 +574,8 @@
#
# Since: 1.1
##
{ 'command': 'guest-suspend-disk', 'success-response': false }
{ 'command': 'guest-suspend-disk', 'success-response': false,
'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-suspend-ram:
@ -602,7 +611,8 @@
#
# Since: 1.1
##
{ 'command': 'guest-suspend-ram', 'success-response': false }
{ 'command': 'guest-suspend-ram', 'success-response': false,
'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-suspend-hybrid:
@ -637,7 +647,8 @@
#
# Since: 1.1
##
{ 'command': 'guest-suspend-hybrid', 'success-response': false }
{ 'command': 'guest-suspend-hybrid', 'success-response': false,
'if': 'CONFIG_LINUX' }
##
# @GuestIpAddressType:
@ -651,7 +662,8 @@
# Since: 1.1
##
{ 'enum': 'GuestIpAddressType',
'data': [ 'ipv4', 'ipv6' ] }
'data': [ 'ipv4', 'ipv6' ],
'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestIpAddress:
@ -667,7 +679,8 @@
{ 'struct': 'GuestIpAddress',
'data': {'ip-address': 'str',
'ip-address-type': 'GuestIpAddressType',
'prefix': 'int'} }
'prefix': 'int'},
'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestNetworkInterfaceStat:
@ -699,7 +712,8 @@
'tx-packets': 'uint64',
'tx-errs': 'uint64',
'tx-dropped': 'uint64'
} }
},
'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestNetworkInterface:
@ -719,7 +733,8 @@
'data': {'name': 'str',
'*hardware-address': 'str',
'*ip-addresses': ['GuestIpAddress'],
'*statistics': 'GuestNetworkInterfaceStat' } }
'*statistics': 'GuestNetworkInterfaceStat' },
'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @guest-network-get-interfaces:
@ -731,7 +746,8 @@
# Since: 1.1
##
{ 'command': 'guest-network-get-interfaces',
'returns': ['GuestNetworkInterface'] }
'returns': ['GuestNetworkInterface'],
'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestLogicalProcessor:
@ -750,7 +766,8 @@
{ 'struct': 'GuestLogicalProcessor',
'data': {'logical-id': 'int',
'online': 'bool',
'*can-offline': 'bool'} }
'*can-offline': 'bool'},
'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-get-vcpus:
@ -765,7 +782,8 @@
# Since: 1.5
##
{ 'command': 'guest-get-vcpus',
'returns': ['GuestLogicalProcessor'] }
'returns': ['GuestLogicalProcessor'],
'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-set-vcpus:
@ -807,7 +825,8 @@
##
{ 'command': 'guest-set-vcpus',
'data': {'vcpus': ['GuestLogicalProcessor'] },
'returns': 'int' }
'returns': 'int',
'if': 'CONFIG_LINUX' }
##
# @GuestDiskBusType:
@ -859,7 +878,8 @@
{ 'enum': 'GuestDiskBusType',
'data': [ 'ide', 'fdc', 'scsi', 'virtio', 'xen', 'usb', 'uml', 'sata',
'sd', 'unknown', 'ieee1394', 'ssa', 'fibre', 'raid', 'iscsi',
'sas', 'mmc', 'virtual', 'file-backed-virtual', 'nvme' ] }
'sas', 'mmc', 'virtual', 'file-backed-virtual', 'nvme' ],
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
@ -877,7 +897,8 @@
##
{ 'struct': 'GuestPCIAddress',
'data': {'domain': 'int', 'bus': 'int',
'slot': 'int', 'function': 'int'} }
'slot': 'int', 'function': 'int'},
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestCCWAddress:
@ -896,7 +917,8 @@
'data': {'cssid': 'int',
'ssid': 'int',
'subchno': 'int',
'devno': 'int'} }
'devno': 'int'},
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestDiskAddress:
@ -925,7 +947,8 @@
'bus-type': 'GuestDiskBusType',
'bus': 'int', 'target': 'int', 'unit': 'int',
'*serial': 'str', '*dev': 'str',
'*ccw-address': 'GuestCCWAddress'} }
'*ccw-address': 'GuestCCWAddress'},
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestNVMeSmart:
@ -962,7 +985,8 @@
'media-errors-lo': 'uint64',
'media-errors-hi': 'uint64',
'number-of-error-log-entries-lo': 'uint64',
'number-of-error-log-entries-hi': 'uint64' } }
'number-of-error-log-entries-hi': 'uint64' },
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @GuestDiskSmart:
@ -976,7 +1000,8 @@
{ 'union': 'GuestDiskSmart',
'base': { 'type': 'GuestDiskBusType' },
'discriminator': 'type',
'data': { 'nvme': 'GuestNVMeSmart' } }
'data': { 'nvme': 'GuestNVMeSmart' },
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @GuestDiskInfo:
@ -1001,7 +1026,8 @@
{ 'struct': 'GuestDiskInfo',
'data': {'name': 'str', 'partition': 'bool', '*dependencies': ['str'],
'*address': 'GuestDiskAddress', '*alias': 'str',
'*smart': 'GuestDiskSmart'} }
'*smart': 'GuestDiskSmart'},
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @guest-get-disks:
@ -1014,7 +1040,8 @@
# Since: 5.2
##
{ 'command': 'guest-get-disks',
'returns': ['GuestDiskInfo'] }
'returns': ['GuestDiskInfo'],
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @GuestFilesystemInfo:
@ -1040,7 +1067,8 @@
{ 'struct': 'GuestFilesystemInfo',
'data': {'name': 'str', 'mountpoint': 'str', 'type': 'str',
'*used-bytes': 'uint64', '*total-bytes': 'uint64',
'*total-bytes-privileged': 'uint64', 'disk': ['GuestDiskAddress']} }
'*total-bytes-privileged': 'uint64', 'disk': ['GuestDiskAddress']},
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @guest-get-fsinfo:
@ -1053,7 +1081,8 @@
# Since: 2.2
##
{ 'command': 'guest-get-fsinfo',
'returns': ['GuestFilesystemInfo'] }
'returns': ['GuestFilesystemInfo'],
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @guest-set-user-password:
@ -1080,7 +1109,8 @@
# Since: 2.3
##
{ 'command': 'guest-set-user-password',
'data': { 'username': 'str', 'password': 'str', 'crypted': 'bool' } }
'data': { 'username': 'str', 'password': 'str', 'crypted': 'bool' },
'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX', 'CONFIG_FREEBSD'] } }
##
# @GuestMemoryBlock:
@ -1100,7 +1130,8 @@
{ 'struct': 'GuestMemoryBlock',
'data': {'phys-index': 'uint64',
'online': 'bool',
'*can-offline': 'bool'} }
'*can-offline': 'bool'},
'if': 'CONFIG_LINUX' }
##
# @guest-get-memory-blocks:
@ -1116,7 +1147,8 @@
# Since: 2.3
##
{ 'command': 'guest-get-memory-blocks',
'returns': ['GuestMemoryBlock'] }
'returns': ['GuestMemoryBlock'],
'if': 'CONFIG_LINUX' }
##
# @GuestMemoryBlockResponseType:
@ -1139,7 +1171,8 @@
##
{ 'enum': 'GuestMemoryBlockResponseType',
'data': ['success', 'not-found', 'operation-not-supported',
'operation-failed'] }
'operation-failed'],
'if': 'CONFIG_LINUX' }
##
# @GuestMemoryBlockResponse:
@ -1157,7 +1190,8 @@
{ 'struct': 'GuestMemoryBlockResponse',
'data': { 'phys-index': 'uint64',
'response': 'GuestMemoryBlockResponseType',
'*error-code': 'int' }}
'*error-code': 'int' },
'if': 'CONFIG_LINUX'}
##
# @guest-set-memory-blocks:
@ -1188,7 +1222,8 @@
##
{ 'command': 'guest-set-memory-blocks',
'data': {'mem-blks': ['GuestMemoryBlock'] },
'returns': ['GuestMemoryBlockResponse'] }
'returns': ['GuestMemoryBlockResponse'],
'if': 'CONFIG_LINUX' }
##
# @GuestMemoryBlockInfo:
@ -1200,7 +1235,8 @@
# Since: 2.3
##
{ 'struct': 'GuestMemoryBlockInfo',
'data': {'size': 'uint64'} }
'data': {'size': 'uint64'},
'if': 'CONFIG_LINUX' }
##
# @guest-get-memory-block-info:
@ -1212,7 +1248,8 @@
# Since: 2.3
##
{ 'command': 'guest-get-memory-block-info',
'returns': 'GuestMemoryBlockInfo' }
'returns': 'GuestMemoryBlockInfo',
'if': 'CONFIG_LINUX' }
##
# @GuestExecStatus:
@ -1378,7 +1415,8 @@
# Since: 2.10
##
{ 'struct': 'GuestUser',
'data': { 'user': 'str', 'login-time': 'number', '*domain': 'str' } }
'data': { 'user': 'str', 'login-time': 'number', '*domain': 'str' },
'if': { 'any': ['CONFIG_WIN32', 'HAVE_UTMPX' ] } }
##
# @guest-get-users:
@ -1390,7 +1428,8 @@
# Since: 2.10
##
{ 'command': 'guest-get-users',
'returns': ['GuestUser'] }
'returns': ['GuestUser'],
'if': { 'any': ['CONFIG_WIN32', 'HAVE_UTMPX' ] } }
##
# @GuestTimezone:
@ -1499,7 +1538,8 @@
# @pci: PCI device
##
{ 'enum': 'GuestDeviceType',
'data': [ 'pci' ] }
'data': [ 'pci' ],
'if': 'CONFIG_WIN32' }
##
# @GuestDeviceIdPCI:
@ -1511,7 +1551,8 @@
# Since: 5.2
##
{ 'struct': 'GuestDeviceIdPCI',
'data': { 'vendor-id': 'uint16', 'device-id': 'uint16' } }
'data': { 'vendor-id': 'uint16', 'device-id': 'uint16' },
'if': 'CONFIG_WIN32' }
##
# @GuestDeviceId:
@ -1525,7 +1566,8 @@
{ 'union': 'GuestDeviceId',
'base': { 'type': 'GuestDeviceType' },
'discriminator': 'type',
'data': { 'pci': 'GuestDeviceIdPCI' } }
'data': { 'pci': 'GuestDeviceIdPCI' },
'if': 'CONFIG_WIN32' }
##
# @GuestDeviceInfo:
@ -1546,7 +1588,8 @@
'*driver-date': 'int',
'*driver-version': 'str',
'*id': 'GuestDeviceId'
} }
},
'if': 'CONFIG_WIN32' }
##
# @guest-get-devices:
@ -1558,7 +1601,8 @@
# Since: 5.2
##
{ 'command': 'guest-get-devices',
'returns': ['GuestDeviceInfo'] }
'returns': ['GuestDeviceInfo'],
'if': 'CONFIG_WIN32' }
##
# @GuestAuthorizedKeys:
@ -1685,7 +1729,8 @@
'*ios-pgr': 'uint64',
'*total-ticks': 'uint64',
'*weight-ticks': 'uint64'
} }
},
'if': 'CONFIG_LINUX' }
##
# @GuestDiskStatsInfo:
@ -1702,7 +1747,8 @@
'data': {'name': 'str',
'major': 'uint64',
'minor': 'uint64',
'stats': 'GuestDiskStats' } }
'stats': 'GuestDiskStats' },
'if': 'CONFIG_LINUX' }
##
# @guest-get-diskstats:
@ -1714,7 +1760,8 @@
# Since: 7.1
##
{ 'command': 'guest-get-diskstats',
'returns': ['GuestDiskStatsInfo']
'returns': ['GuestDiskStatsInfo'],
'if': 'CONFIG_LINUX'
}
##
@ -1727,7 +1774,8 @@
# Since: 7.1
##
{ 'enum': 'GuestCpuStatsType',
'data': [ 'linux' ] }
'data': [ 'linux' ],
'if': 'CONFIG_LINUX' }
##
@ -1772,7 +1820,8 @@
'*steal': 'uint64',
'*guest': 'uint64',
'*guestnice': 'uint64'
} }
},
'if': 'CONFIG_LINUX' }
##
# @GuestCpuStats:
@ -1786,7 +1835,8 @@
{ 'union': 'GuestCpuStats',
'base': { 'type': 'GuestCpuStatsType' },
'discriminator': 'type',
'data': { 'linux': 'GuestLinuxCpuStats' } }
'data': { 'linux': 'GuestLinuxCpuStats' },
'if': 'CONFIG_LINUX' }
##
# @guest-get-cpustats:
@ -1798,5 +1848,79 @@
# Since: 7.1
##
{ 'command': 'guest-get-cpustats',
'returns': ['GuestCpuStats']
'returns': ['GuestCpuStats'],
'if': 'CONFIG_LINUX'
}
##
# @GuestNetworkRoute:
#
# Route information, currently, only linux supported.
#
# @iface: The destination network or host's egress network interface in the routing table
#
# @destination: The IP address of the target network or host, The final destination of the packet
#
# @metric: Route metric
#
# @gateway: The IP address of the next hop router
#
# @mask: Subnet Mask (IPv4 only)
#
# @irtt: Initial round-trip delay (not for windows, IPv4 only)
#
# @flags: Route flags (not for windows)
#
# @refcnt: The route's reference count (not for windows)
#
# @use: Route usage count (not for windows)
#
# @window: TCP window size, used for flow control (not for windows, IPv4 only)
#
# @mtu: Data link layer maximum packet size (not for windows)
#
# @desprefixlen: Destination prefix length (for IPv6)
#
# @source: Source IP address (for IPv6)
#
# @srcprefixlen: Source prefix length (for IPv6)
#
# @nexthop: Next hop IP address (for IPv6)
#
# @version: IP version (4 or 6)
#
# Since: 9.1
##
{ 'struct': 'GuestNetworkRoute',
'data': {'iface': 'str',
'destination': 'str',
'metric': 'int',
'*gateway': 'str',
'*mask': 'str',
'*irtt': 'int',
'*flags': 'uint64',
'*refcnt': 'int',
'*use': 'int',
'*window': 'int',
'*mtu': 'int',
'*desprefixlen': 'str',
'*source': 'str',
'*srcprefixlen': 'str',
'*nexthop': 'str',
'version': 'int'
},
'if': 'CONFIG_LINUX' }
##
# @guest-network-get-route:
#
# Retrieve information about route of network.
# Returns: List of route info of guest.
#
# Since: 9.1
##
{ 'command': 'guest-network-get-route',
'returns': ['GuestNetworkRoute'],
'if': 'CONFIG_LINUX'
}