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 <r@drigo.nl>
Reviewed-by: Kostiantyn Kostiuk <kkostiuk@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20250926214015.120338-1-r@drigo.nl
Signed-off-by: Kostiantyn Kostiuk <kkostiuk@redhat.com>
This commit is contained in:
parent
c741c087b8
commit
c5b4afd4d5
1 changed files with 29 additions and 0 deletions
|
|
@ -213,9 +213,20 @@ out:
|
||||||
return retcode;
|
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)
|
void qmp_guest_shutdown(const char *mode, Error **errp)
|
||||||
{
|
{
|
||||||
const char *shutdown_flag;
|
const char *shutdown_flag;
|
||||||
|
const char *shutdown_cmd = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
#ifdef CONFIG_SOLARIS
|
#ifdef CONFIG_SOLARIS
|
||||||
|
|
@ -234,10 +245,19 @@ void qmp_guest_shutdown(const char *mode, Error **errp)
|
||||||
|
|
||||||
slog("guest-shutdown called, mode: %s", mode);
|
slog("guest-shutdown called, mode: %s", mode);
|
||||||
if (!mode || strcmp(mode, "powerdown") == 0) {
|
if (!mode || strcmp(mode, "powerdown") == 0) {
|
||||||
|
if (file_exists(POWEROFF_CMD_PATH)) {
|
||||||
|
shutdown_cmd = POWEROFF_CMD_PATH;
|
||||||
|
}
|
||||||
shutdown_flag = powerdown_flag;
|
shutdown_flag = powerdown_flag;
|
||||||
} else if (strcmp(mode, "halt") == 0) {
|
} else if (strcmp(mode, "halt") == 0) {
|
||||||
|
if (file_exists(HALT_CMD_PATH)) {
|
||||||
|
shutdown_cmd = HALT_CMD_PATH;
|
||||||
|
}
|
||||||
shutdown_flag = halt_flag;
|
shutdown_flag = halt_flag;
|
||||||
} else if (strcmp(mode, "reboot") == 0) {
|
} else if (strcmp(mode, "reboot") == 0) {
|
||||||
|
if (file_exists(REBOOT_CMD_PATH)) {
|
||||||
|
shutdown_cmd = REBOOT_CMD_PATH;
|
||||||
|
}
|
||||||
shutdown_flag = reboot_flag;
|
shutdown_flag = reboot_flag;
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
|
|
@ -255,6 +275,15 @@ void qmp_guest_shutdown(const char *mode, Error **errp)
|
||||||
#endif
|
#endif
|
||||||
"hypervisor initiated shutdown", (char *) NULL};
|
"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);
|
ga_run_command(argv, NULL, "shutdown", &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue