From c38e65a881e00f1f828920a96cba86bf72c1ccba Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 16 Sep 2025 14:19:49 +0200 Subject: [PATCH 1/3] scripts/qemu-guest-agent/fsfreeze-hook: improve script description With the current wording, users might think that the -F option is not required as long as the script is placed in the default path. Be clear that the option is always required. Also includes some minor language improvements in the rest of the comment. Signed-off-by: Fiona Ebner Reviewed-by: Kostiantyn Kostiuk Link: https://lore.kernel.org/qemu-devel/20250916122111.36019-1-f.ebner@proxmox.com Signed-off-by: Kostiantyn Kostiuk --- scripts/qemu-guest-agent/fsfreeze-hook | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/qemu-guest-agent/fsfreeze-hook b/scripts/qemu-guest-agent/fsfreeze-hook index c1feb6f5ce..5b915af017 100755 --- a/scripts/qemu-guest-agent/fsfreeze-hook +++ b/scripts/qemu-guest-agent/fsfreeze-hook @@ -1,11 +1,12 @@ #!/bin/sh -# This script is executed when a guest agent receives fsfreeze-freeze and -# fsfreeze-thaw command, if it is specified in --fsfreeze-hook (-F) -# option of qemu-ga or placed in default path (/etc/qemu/fsfreeze-hook). -# When the agent receives fsfreeze-freeze request, this script is issued with -# "freeze" argument before the filesystem is frozen. And for fsfreeze-thaw -# request, it is issued with "thaw" argument after filesystem is thawed. +# This script is executed when the guest agent receives fsfreeze-freeze and +# fsfreeze-thaw commands, provided that the --fsfreeze-hook (-F) option of +# qemu-ga is specified and the script is placed in /etc/qemu/fsfreeze-hook or in +# the path specified together with -F. When the agent receives fsfreeze-freeze +# requests, this script is called with "freeze" as its argument before the +# filesystem is frozen. And for fsfreeze-thaw requests, it is called with "thaw" +# as its argument after the filesystem is thawed. LOGFILE=/var/log/qga-fsfreeze-hook.log FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d From c741c087b8fb926f9e9e9150456784238c2e039b Mon Sep 17 00:00:00 2001 From: "minglei.liu" Date: Tue, 23 Sep 2025 19:32:43 +0800 Subject: [PATCH 2/3] qga: Improve Windows filesystem space info retrieval logic Previously, disk space reporting only worked for volumes with drive letters, skipping those without (e.g. System Reserved). This change always calls GetDiskFreeSpaceEx with fs->name, which is a volume GUID path. Windows APIs accept both drive letters (e.g. "C:\") and volume GUIDs (e.g. "\\?\Volume{GUID}\") as valid lpDirectoryName parameters, so space reporting is now consistent across all volumes. Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file Signed-off-by: minglei.liu Reviewed-by: Kostiantyn Kostiuk Link: https://lore.kernel.org/qemu-devel/20250923113243.78244-1-minglei.liu@smartx.com Signed-off-by: Kostiantyn Kostiuk --- qga/commands-win32.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 8227480810..acc2c11589 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -1164,15 +1164,15 @@ static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp) fs->mountpoint = g_strdup("System Reserved"); } else { fs->mountpoint = g_strndup(mnt_point, len); - if (GetDiskFreeSpaceEx(fs->mountpoint, - (PULARGE_INTEGER) & i64FreeBytesToCaller, - (PULARGE_INTEGER) & i64TotalBytes, - (PULARGE_INTEGER) & i64FreeBytes)) { - fs->used_bytes = i64TotalBytes - i64FreeBytes; - fs->total_bytes = i64TotalBytes; - fs->has_total_bytes = true; - fs->has_used_bytes = true; - } + } + if (GetDiskFreeSpaceEx(fs->name, + (PULARGE_INTEGER) & i64FreeBytesToCaller, + (PULARGE_INTEGER) & i64TotalBytes, + (PULARGE_INTEGER) & i64FreeBytes)) { + fs->used_bytes = i64TotalBytes - i64FreeBytes; + fs->total_bytes = i64TotalBytes; + fs->has_total_bytes = true; + fs->has_used_bytes = true; } wcstombs(fs_name, wfs_name, sizeof(wfs_name)); fs->type = g_strdup(fs_name); From c5b4afd4d56e9c2251e6674d8c9ae530a923ecb9 Mon Sep 17 00:00:00 2001 From: Rodrigo Dias Correa Date: Fri, 26 Sep 2025 23:40:11 +0200 Subject: [PATCH 3/3] qga: Support guest shutdown of BusyBox-based systems On POSIX systems, the QEMU Guest Agent uses /sbin/shutdown to implement the command guest-shutdown. Systems based on BusyBox, such as Alpine Linux, don't have /sbin/shutdown. They have instead three separate commands: poweroff, reboot, and halt. Change the QEMU Guest Agent to, depending on the mode argument, use /sbin/{poweroff,halt,reboot} when they exist, falling back to /sbin/shutdown when they don't. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2589 Signed-off-by: Rodrigo Dias Correa Reviewed-by: Kostiantyn Kostiuk Link: https://lore.kernel.org/qemu-devel/20250926214015.120338-1-r@drigo.nl Signed-off-by: Kostiantyn Kostiuk --- qga/commands-posix.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 5070f27d75..c7059857e4 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -213,9 +213,20 @@ out: return retcode; } +static bool file_exists(const char *path) +{ + struct stat st; + return stat(path, &st) == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)); +} + +#define POWEROFF_CMD_PATH "/sbin/poweroff" +#define HALT_CMD_PATH "/sbin/halt" +#define REBOOT_CMD_PATH "/sbin/reboot" + void qmp_guest_shutdown(const char *mode, Error **errp) { const char *shutdown_flag; + const char *shutdown_cmd = NULL; Error *local_err = NULL; #ifdef CONFIG_SOLARIS @@ -234,10 +245,19 @@ void qmp_guest_shutdown(const char *mode, Error **errp) slog("guest-shutdown called, mode: %s", mode); if (!mode || strcmp(mode, "powerdown") == 0) { + if (file_exists(POWEROFF_CMD_PATH)) { + shutdown_cmd = POWEROFF_CMD_PATH; + } shutdown_flag = powerdown_flag; } else if (strcmp(mode, "halt") == 0) { + if (file_exists(HALT_CMD_PATH)) { + shutdown_cmd = HALT_CMD_PATH; + } shutdown_flag = halt_flag; } else if (strcmp(mode, "reboot") == 0) { + if (file_exists(REBOOT_CMD_PATH)) { + shutdown_cmd = REBOOT_CMD_PATH; + } shutdown_flag = reboot_flag; } else { error_setg(errp, @@ -255,6 +275,15 @@ void qmp_guest_shutdown(const char *mode, Error **errp) #endif "hypervisor initiated shutdown", (char *) NULL}; + /* + * If the specific command exists (poweroff, halt or reboot), use it instead + * of /sbin/shutdown. + */ + if (shutdown_cmd != NULL) { + argv[0] = shutdown_cmd; + argv[1] = NULL; + } + ga_run_command(argv, NULL, "shutdown", &local_err); if (local_err) { error_propagate(errp, local_err);