The qmp_guest_suspend_{disk,ram,hybrid} command impls in
commands-posix.c are surrounded by '#ifdef __linux__' so should
instead live in commands-linux.c
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
qga/commands-linux.c | 265 +++++++++++++++++++++++++++++++++++++++++++
qga/commands-posix.c | 265 -------------------------------------------
2 files changed, 265 insertions(+), 265 deletions(-)
diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index 78580ac39d..3fabf54882 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -286,6 +286,271 @@ int qmp_guest_fsfreeze_do_thaw(Error **errp)
}
#endif /* CONFIG_FSFREEZE */
+
+#define LINUX_SYS_STATE_FILE "/sys/power/state"
+#define SUSPEND_SUPPORTED 0
+#define SUSPEND_NOT_SUPPORTED 1
+
+typedef enum {
+ SUSPEND_MODE_DISK = 0,
+ SUSPEND_MODE_RAM = 1,
+ SUSPEND_MODE_HYBRID = 2,
+} SuspendMode;
+
+/*
+ * Executes a command in a child process using g_spawn_sync,
+ * returning an int >= 0 representing the exit status of the
+ * process.
+ *
+ * If the program wasn't found in path, returns -1.
+ *
+ * If a problem happened when creating the child process,
+ * returns -1 and errp is set.
+ */
+static int run_process_child(const char *command[], Error **errp)
+{
+ int exit_status, spawn_flag;
+ GError *g_err = NULL;
+ bool success;
+
+ spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL |
+ G_SPAWN_STDERR_TO_DEV_NULL;
+
+ success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag,
+ NULL, NULL, NULL, NULL,
+ &exit_status, &g_err);
+
+ if (success) {
+ return WEXITSTATUS(exit_status);
+ }
+
+ if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) {
+ error_setg(errp, "failed to create child process, error '%s'",
+ g_err->message);
+ }
+
+ g_error_free(g_err);
+ return -1;
+}
+
+static bool systemd_supports_mode(SuspendMode mode, Error **errp)
+{
+ const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend",
+ "systemd-hybrid-sleep"};
+ const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, errp);
+
+ /*
+ * systemctl status uses LSB return codes so we can expect
+ * status > 0 and be ok. To assert if the guest has support
+ * for the selected suspend mode, status should be < 4. 4 is
+ * the code for unknown service status, the return value when
+ * the service does not exist. A common value is status = 3
+ * (program is not running).
+ */
+ if (status > 0 && status < 4) {
+ return true;
+ }
+
+ return false;
+}
+
+static void systemd_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"};
+ const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == 0) {
+ return;
+ }
+
+ if ((status == -1) && !local_err) {
+ error_setg(errp, "the helper program 'systemctl %s' was not found",
+ systemctl_args[mode]);
+ return;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
+ error_setg(errp, "the helper program 'systemctl %s' returned an "
+ "unexpected exit status code (%d)",
+ systemctl_args[mode], status);
+ }
+}
+
+static bool pmutils_supports_mode(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *pmutils_args[3] = {"--hibernate", "--suspend",
+ "--suspend-hybrid"};
+ const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == SUSPEND_SUPPORTED) {
+ return true;
+ }
+
+ if ((status == -1) && !local_err) {
+ return false;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
+ error_setg(errp,
+ "the helper program '%s' returned an unexpected exit"
+ " status code (%d)", "pm-is-supported", status);
+ }
+
+ return false;
+}
+
+static void pmutils_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend",
+ "pm-suspend-hybrid"};
+ const char *cmd[2] = {pmutils_binaries[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == 0) {
+ return;
+ }
+
+ if ((status == -1) && !local_err) {
+ error_setg(errp, "the helper program '%s' was not found",
+ pmutils_binaries[mode]);
+ return;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
+ error_setg(errp,
+ "the helper program '%s' returned an unexpected exit"
+ " status code (%d)", pmutils_binaries[mode], status);
+ }
+}
+
+static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp)
+{
+ const char *sysfile_strs[3] = {"disk", "mem", NULL};
+ const char *sysfile_str = sysfile_strs[mode];
+ char buf[32]; /* hopefully big enough */
+ int fd;
+ ssize_t ret;
+
+ if (!sysfile_str) {
+ error_setg(errp, "unknown guest suspend mode");
+ return false;
+ }
+
+ fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
+ if (fd < 0) {
+ return false;
+ }
+
+ ret = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (ret <= 0) {
+ return false;
+ }
+ buf[ret] = '\0';
+
+ if (strstr(buf, sysfile_str)) {
+ return true;
+ }
+ return false;
+}
+
+static void linux_sys_state_suspend(SuspendMode mode, Error **errp)
+{
+ g_autoptr(GError) local_gerr = NULL;
+ const char *sysfile_strs[3] = {"disk", "mem", NULL};
+ const char *sysfile_str = sysfile_strs[mode];
+
+ if (!sysfile_str) {
+ error_setg(errp, "unknown guest suspend mode");
+ return;
+ }
+
+ if (!g_file_set_contents(LINUX_SYS_STATE_FILE, sysfile_str,
+ -1, &local_gerr)) {
+ error_setg(errp, "suspend: cannot write to '%s': %s",
+ LINUX_SYS_STATE_FILE, local_gerr->message);
+ return;
+ }
+}
+
+static void guest_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ bool mode_supported = false;
+
+ if (systemd_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ systemd_suspend(mode, &local_err);
+
+ if (!local_err) {
+ return;
+ }
+ }
+
+ error_free(local_err);
+ local_err = NULL;
+
+ if (pmutils_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ pmutils_suspend(mode, &local_err);
+
+ if (!local_err) {
+ return;
+ }
+ }
+
+ error_free(local_err);
+ local_err = NULL;
+
+ if (linux_sys_state_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ linux_sys_state_suspend(mode, &local_err);
+ }
+
+ if (!mode_supported) {
+ error_free(local_err);
+ error_setg(errp,
+ "the requested suspend mode is not supported by the guest");
+ } else {
+ error_propagate(errp, local_err);
+ }
+}
+
+void qmp_guest_suspend_disk(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_DISK, errp);
+}
+
+void qmp_guest_suspend_ram(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_RAM, errp);
+}
+
+void qmp_guest_suspend_hybrid(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_HYBRID, errp);
+}
+
/* Transfer online/offline status between @vcpu and the guest system.
*
* On input either @errp or *@errp must be NULL.
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index a8ef41f175..ef21da63be 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1738,271 +1738,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
}
#endif /* CONFIG_FSTRIM */
-
-#define LINUX_SYS_STATE_FILE "/sys/power/state"
-#define SUSPEND_SUPPORTED 0
-#define SUSPEND_NOT_SUPPORTED 1
-
-typedef enum {
- SUSPEND_MODE_DISK = 0,
- SUSPEND_MODE_RAM = 1,
- SUSPEND_MODE_HYBRID = 2,
-} SuspendMode;
-
-/*
- * Executes a command in a child process using g_spawn_sync,
- * returning an int >= 0 representing the exit status of the
- * process.
- *
- * If the program wasn't found in path, returns -1.
- *
- * If a problem happened when creating the child process,
- * returns -1 and errp is set.
- */
-static int run_process_child(const char *command[], Error **errp)
-{
- int exit_status, spawn_flag;
- GError *g_err = NULL;
- bool success;
-
- spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL |
- G_SPAWN_STDERR_TO_DEV_NULL;
-
- success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag,
- NULL, NULL, NULL, NULL,
- &exit_status, &g_err);
-
- if (success) {
- return WEXITSTATUS(exit_status);
- }
-
- if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) {
- error_setg(errp, "failed to create child process, error '%s'",
- g_err->message);
- }
-
- g_error_free(g_err);
- return -1;
-}
-
-static bool systemd_supports_mode(SuspendMode mode, Error **errp)
-{
- const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend",
- "systemd-hybrid-sleep"};
- const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL};
- int status;
-
- status = run_process_child(cmd, errp);
-
- /*
- * systemctl status uses LSB return codes so we can expect
- * status > 0 and be ok. To assert if the guest has support
- * for the selected suspend mode, status should be < 4. 4 is
- * the code for unknown service status, the return value when
- * the service does not exist. A common value is status = 3
- * (program is not running).
- */
- if (status > 0 && status < 4) {
- return true;
- }
-
- return false;
-}
-
-static void systemd_suspend(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"};
- const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL};
- int status;
-
- status = run_process_child(cmd, &local_err);
-
- if (status == 0) {
- return;
- }
-
- if ((status == -1) && !local_err) {
- error_setg(errp, "the helper program 'systemctl %s' was not found",
- systemctl_args[mode]);
- return;
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- } else {
- error_setg(errp, "the helper program 'systemctl %s' returned an "
- "unexpected exit status code (%d)",
- systemctl_args[mode], status);
- }
-}
-
-static bool pmutils_supports_mode(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- const char *pmutils_args[3] = {"--hibernate", "--suspend",
- "--suspend-hybrid"};
- const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL};
- int status;
-
- status = run_process_child(cmd, &local_err);
-
- if (status == SUSPEND_SUPPORTED) {
- return true;
- }
-
- if ((status == -1) && !local_err) {
- return false;
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- } else {
- error_setg(errp,
- "the helper program '%s' returned an unexpected exit"
- " status code (%d)", "pm-is-supported", status);
- }
-
- return false;
-}
-
-static void pmutils_suspend(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend",
- "pm-suspend-hybrid"};
- const char *cmd[2] = {pmutils_binaries[mode], NULL};
- int status;
-
- status = run_process_child(cmd, &local_err);
-
- if (status == 0) {
- return;
- }
-
- if ((status == -1) && !local_err) {
- error_setg(errp, "the helper program '%s' was not found",
- pmutils_binaries[mode]);
- return;
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- } else {
- error_setg(errp,
- "the helper program '%s' returned an unexpected exit"
- " status code (%d)", pmutils_binaries[mode], status);
- }
-}
-
-static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp)
-{
- const char *sysfile_strs[3] = {"disk", "mem", NULL};
- const char *sysfile_str = sysfile_strs[mode];
- char buf[32]; /* hopefully big enough */
- int fd;
- ssize_t ret;
-
- if (!sysfile_str) {
- error_setg(errp, "unknown guest suspend mode");
- return false;
- }
-
- fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
- if (fd < 0) {
- return false;
- }
-
- ret = read(fd, buf, sizeof(buf) - 1);
- close(fd);
- if (ret <= 0) {
- return false;
- }
- buf[ret] = '\0';
-
- if (strstr(buf, sysfile_str)) {
- return true;
- }
- return false;
-}
-
-static void linux_sys_state_suspend(SuspendMode mode, Error **errp)
-{
- g_autoptr(GError) local_gerr = NULL;
- const char *sysfile_strs[3] = {"disk", "mem", NULL};
- const char *sysfile_str = sysfile_strs[mode];
-
- if (!sysfile_str) {
- error_setg(errp, "unknown guest suspend mode");
- return;
- }
-
- if (!g_file_set_contents(LINUX_SYS_STATE_FILE, sysfile_str,
- -1, &local_gerr)) {
- error_setg(errp, "suspend: cannot write to '%s': %s",
- LINUX_SYS_STATE_FILE, local_gerr->message);
- return;
- }
-}
-
-static void guest_suspend(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- bool mode_supported = false;
-
- if (systemd_supports_mode(mode, &local_err)) {
- mode_supported = true;
- systemd_suspend(mode, &local_err);
-
- if (!local_err) {
- return;
- }
- }
-
- error_free(local_err);
- local_err = NULL;
-
- if (pmutils_supports_mode(mode, &local_err)) {
- mode_supported = true;
- pmutils_suspend(mode, &local_err);
-
- if (!local_err) {
- return;
- }
- }
-
- error_free(local_err);
- local_err = NULL;
-
- if (linux_sys_state_supports_mode(mode, &local_err)) {
- mode_supported = true;
- linux_sys_state_suspend(mode, &local_err);
- }
-
- if (!mode_supported) {
- error_free(local_err);
- error_setg(errp,
- "the requested suspend mode is not supported by the guest");
- } else {
- error_propagate(errp, local_err);
- }
-}
-
-void qmp_guest_suspend_disk(Error **errp)
-{
- guest_suspend(SUSPEND_MODE_DISK, errp);
-}
-
-void qmp_guest_suspend_ram(Error **errp)
-{
- guest_suspend(SUSPEND_MODE_RAM, errp);
-}
-
-void qmp_guest_suspend_hybrid(Error **errp)
-{
- guest_suspend(SUSPEND_MODE_HYBRID, errp);
-}
-
#endif /* __linux__ */
#if defined(__linux__) || defined(__FreeBSD__)
--
2.45.1
On Tue, 04 Jun 2024 16:49, "Daniel P. Berrangé" <berrange@redhat.com> wrote: >The qmp_guest_suspend_{disk,ram,hybrid} command impls in >commands-posix.c are surrounded by '#ifdef __linux__' so should >instead live in commands-linux.c > >Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> >--- Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> > qga/commands-linux.c | 265 +++++++++++++++++++++++++++++++++++++++++++ > qga/commands-posix.c | 265 ------------------------------------------- > 2 files changed, 265 insertions(+), 265 deletions(-) > >diff --git a/qga/commands-linux.c b/qga/commands-linux.c >index 78580ac39d..3fabf54882 100644 >--- a/qga/commands-linux.c >+++ b/qga/commands-linux.c >@@ -286,6 +286,271 @@ int qmp_guest_fsfreeze_do_thaw(Error **errp) > } > #endif /* CONFIG_FSFREEZE */ > >+ >+#define LINUX_SYS_STATE_FILE "/sys/power/state" >+#define SUSPEND_SUPPORTED 0 >+#define SUSPEND_NOT_SUPPORTED 1 >+ >+typedef enum { >+ SUSPEND_MODE_DISK = 0, >+ SUSPEND_MODE_RAM = 1, >+ SUSPEND_MODE_HYBRID = 2, >+} SuspendMode; >+ >+/* >+ * Executes a command in a child process using g_spawn_sync, >+ * returning an int >= 0 representing the exit status of the >+ * process. >+ * >+ * If the program wasn't found in path, returns -1. >+ * >+ * If a problem happened when creating the child process, >+ * returns -1 and errp is set. >+ */ >+static int run_process_child(const char *command[], Error **errp) >+{ >+ int exit_status, spawn_flag; >+ GError *g_err = NULL; >+ bool success; >+ >+ spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | >+ G_SPAWN_STDERR_TO_DEV_NULL; >+ >+ success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag, >+ NULL, NULL, NULL, NULL, >+ &exit_status, &g_err); >+ >+ if (success) { >+ return WEXITSTATUS(exit_status); >+ } >+ >+ if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) { >+ error_setg(errp, "failed to create child process, error '%s'", >+ g_err->message); >+ } >+ >+ g_error_free(g_err); >+ return -1; >+} >+ >+static bool systemd_supports_mode(SuspendMode mode, Error **errp) >+{ >+ const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend", >+ "systemd-hybrid-sleep"}; >+ const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL}; >+ int status; >+ >+ status = run_process_child(cmd, errp); >+ >+ /* >+ * systemctl status uses LSB return codes so we can expect >+ * status > 0 and be ok. To assert if the guest has support >+ * for the selected suspend mode, status should be < 4. 4 is >+ * the code for unknown service status, the return value when >+ * the service does not exist. A common value is status = 3 >+ * (program is not running). >+ */ >+ if (status > 0 && status < 4) { >+ return true; >+ } >+ >+ return false; >+} >+ >+static void systemd_suspend(SuspendMode mode, Error **errp) >+{ >+ Error *local_err = NULL; >+ const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"}; >+ const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL}; >+ int status; >+ >+ status = run_process_child(cmd, &local_err); >+ >+ if (status == 0) { >+ return; >+ } >+ >+ if ((status == -1) && !local_err) { >+ error_setg(errp, "the helper program 'systemctl %s' was not found", >+ systemctl_args[mode]); >+ return; >+ } >+ >+ if (local_err) { >+ error_propagate(errp, local_err); >+ } else { >+ error_setg(errp, "the helper program 'systemctl %s' returned an " >+ "unexpected exit status code (%d)", >+ systemctl_args[mode], status); >+ } >+} >+ >+static bool pmutils_supports_mode(SuspendMode mode, Error **errp) >+{ >+ Error *local_err = NULL; >+ const char *pmutils_args[3] = {"--hibernate", "--suspend", >+ "--suspend-hybrid"}; >+ const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL}; >+ int status; >+ >+ status = run_process_child(cmd, &local_err); >+ >+ if (status == SUSPEND_SUPPORTED) { >+ return true; >+ } >+ >+ if ((status == -1) && !local_err) { >+ return false; >+ } >+ >+ if (local_err) { >+ error_propagate(errp, local_err); >+ } else { >+ error_setg(errp, >+ "the helper program '%s' returned an unexpected exit" >+ " status code (%d)", "pm-is-supported", status); >+ } >+ >+ return false; >+} >+ >+static void pmutils_suspend(SuspendMode mode, Error **errp) >+{ >+ Error *local_err = NULL; >+ const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend", >+ "pm-suspend-hybrid"}; >+ const char *cmd[2] = {pmutils_binaries[mode], NULL}; >+ int status; >+ >+ status = run_process_child(cmd, &local_err); >+ >+ if (status == 0) { >+ return; >+ } >+ >+ if ((status == -1) && !local_err) { >+ error_setg(errp, "the helper program '%s' was not found", >+ pmutils_binaries[mode]); >+ return; >+ } >+ >+ if (local_err) { >+ error_propagate(errp, local_err); >+ } else { >+ error_setg(errp, >+ "the helper program '%s' returned an unexpected exit" >+ " status code (%d)", pmutils_binaries[mode], status); >+ } >+} >+ >+static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp) >+{ >+ const char *sysfile_strs[3] = {"disk", "mem", NULL}; >+ const char *sysfile_str = sysfile_strs[mode]; >+ char buf[32]; /* hopefully big enough */ >+ int fd; >+ ssize_t ret; >+ >+ if (!sysfile_str) { >+ error_setg(errp, "unknown guest suspend mode"); >+ return false; >+ } >+ >+ fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); >+ if (fd < 0) { >+ return false; >+ } >+ >+ ret = read(fd, buf, sizeof(buf) - 1); >+ close(fd); >+ if (ret <= 0) { >+ return false; >+ } >+ buf[ret] = '\0'; >+ >+ if (strstr(buf, sysfile_str)) { >+ return true; >+ } >+ return false; >+} >+ >+static void linux_sys_state_suspend(SuspendMode mode, Error **errp) >+{ >+ g_autoptr(GError) local_gerr = NULL; >+ const char *sysfile_strs[3] = {"disk", "mem", NULL}; >+ const char *sysfile_str = sysfile_strs[mode]; >+ >+ if (!sysfile_str) { >+ error_setg(errp, "unknown guest suspend mode"); >+ return; >+ } >+ >+ if (!g_file_set_contents(LINUX_SYS_STATE_FILE, sysfile_str, >+ -1, &local_gerr)) { >+ error_setg(errp, "suspend: cannot write to '%s': %s", >+ LINUX_SYS_STATE_FILE, local_gerr->message); >+ return; >+ } >+} >+ >+static void guest_suspend(SuspendMode mode, Error **errp) >+{ >+ Error *local_err = NULL; >+ bool mode_supported = false; >+ >+ if (systemd_supports_mode(mode, &local_err)) { >+ mode_supported = true; >+ systemd_suspend(mode, &local_err); >+ >+ if (!local_err) { >+ return; >+ } >+ } >+ >+ error_free(local_err); >+ local_err = NULL; >+ >+ if (pmutils_supports_mode(mode, &local_err)) { >+ mode_supported = true; >+ pmutils_suspend(mode, &local_err); >+ >+ if (!local_err) { >+ return; >+ } >+ } >+ >+ error_free(local_err); >+ local_err = NULL; >+ >+ if (linux_sys_state_supports_mode(mode, &local_err)) { >+ mode_supported = true; >+ linux_sys_state_suspend(mode, &local_err); >+ } >+ >+ if (!mode_supported) { >+ error_free(local_err); >+ error_setg(errp, >+ "the requested suspend mode is not supported by the guest"); >+ } else { >+ error_propagate(errp, local_err); >+ } >+} >+ >+void qmp_guest_suspend_disk(Error **errp) >+{ >+ guest_suspend(SUSPEND_MODE_DISK, errp); >+} >+ >+void qmp_guest_suspend_ram(Error **errp) +{ >+ guest_suspend(SUSPEND_MODE_RAM, errp); >+} >+ >+void qmp_guest_suspend_hybrid(Error **errp) >+{ >+ guest_suspend(SUSPEND_MODE_HYBRID, errp); >+} >+ > /* Transfer online/offline status between @vcpu and the guest system. > * > * On input either @errp or *@errp must be NULL. >diff --git a/qga/commands-posix.c b/qga/commands-posix.c >index a8ef41f175..ef21da63be 100644 >--- a/qga/commands-posix.c >+++ b/qga/commands-posix.c >@@ -1738,271 +1738,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) > } > #endif /* CONFIG_FSTRIM */ > >- >-#define LINUX_SYS_STATE_FILE "/sys/power/state" >-#define SUSPEND_SUPPORTED 0 >-#define SUSPEND_NOT_SUPPORTED 1 >- >-typedef enum { >- SUSPEND_MODE_DISK = 0, >- SUSPEND_MODE_RAM = 1, >- SUSPEND_MODE_HYBRID = 2, >-} SuspendMode; >- >-/* >- * Executes a command in a child process using g_spawn_sync, >- * returning an int >= 0 representing the exit status of the >- * process. >- * >- * If the program wasn't found in path, returns -1. >- * >- * If a problem happened when creating the child process, >- * returns -1 and errp is set. >- */ >-static int run_process_child(const char *command[], Error **errp) >-{ >- int exit_status, spawn_flag; >- GError *g_err = NULL; >- bool success; >- >- spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | >- G_SPAWN_STDERR_TO_DEV_NULL; >- >- success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag, >- NULL, NULL, NULL, NULL, >- &exit_status, &g_err); >- >- if (success) { >- return WEXITSTATUS(exit_status); >- } >- >- if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) { >- error_setg(errp, "failed to create child process, error '%s'", >- g_err->message); >- } >- >- g_error_free(g_err); >- return -1; >-} >- >-static bool systemd_supports_mode(SuspendMode mode, Error **errp) >-{ >- const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend", >- "systemd-hybrid-sleep"}; >- const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL}; >- int status; >- >- status = run_process_child(cmd, errp); >- >- /* >- * systemctl status uses LSB return codes so we can expect >- * status > 0 and be ok. To assert if the guest has support >- * for the selected suspend mode, status should be < 4. 4 is >- * the code for unknown service status, the return value when >- * the service does not exist. A common value is status = 3 >- * (program is not running). >- */ >- if (status > 0 && status < 4) { >- return true; >- } >- >- return false; >-} >- >-static void systemd_suspend(SuspendMode mode, Error **errp) >-{ >- Error *local_err = NULL; >- const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"}; >- const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL}; >- int status; >- >- status = run_process_child(cmd, &local_err); >- >- if (status == 0) { >- return; >- } >- >- if ((status == -1) && !local_err) { >- error_setg(errp, "the helper program 'systemctl %s' was not found", >- systemctl_args[mode]); >- return; >- } >- >- if (local_err) { >- error_propagate(errp, local_err); >- } else { >- error_setg(errp, "the helper program 'systemctl %s' returned an " >- "unexpected exit status code (%d)", >- systemctl_args[mode], status); >- } >-} >- >-static bool pmutils_supports_mode(SuspendMode mode, Error **errp) >-{ >- Error *local_err = NULL; >- const char *pmutils_args[3] = {"--hibernate", "--suspend", >- "--suspend-hybrid"}; >- const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL}; >- int status; >- >- status = run_process_child(cmd, &local_err); >- >- if (status == SUSPEND_SUPPORTED) { >- return true; >- } >- >- if ((status == -1) && !local_err) { >- return false; >- } >- >- if (local_err) { >- error_propagate(errp, local_err); >- } else { >- error_setg(errp, >- "the helper program '%s' returned an unexpected exit" >- " status code (%d)", "pm-is-supported", status); >- } >- >- return false; >-} >- >-static void pmutils_suspend(SuspendMode mode, Error **errp) >-{ >- Error *local_err = NULL; >- const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend", >- "pm-suspend-hybrid"}; >- const char *cmd[2] = {pmutils_binaries[mode], NULL}; >- int status; >- >- status = run_process_child(cmd, &local_err); >- >- if (status == 0) { >- return; >- } >- >- if ((status == -1) && !local_err) { >- error_setg(errp, "the helper program '%s' was not found", >- pmutils_binaries[mode]); >- return; >- } >- >- if (local_err) { >- error_propagate(errp, local_err); >- } else { >- error_setg(errp, >- "the helper program '%s' returned an unexpected exit" >- " status code (%d)", pmutils_binaries[mode], status); >- } >-} >- >-static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp) >-{ >- const char *sysfile_strs[3] = {"disk", "mem", NULL}; >- const char *sysfile_str = sysfile_strs[mode]; >- char buf[32]; /* hopefully big enough */ >- int fd; >- ssize_t ret; >- >- if (!sysfile_str) { >- error_setg(errp, "unknown guest suspend mode"); >- return false; >- } >- >- fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); >- if (fd < 0) { >- return false; >- } >- >- ret = read(fd, buf, sizeof(buf) - 1); >- close(fd); >- if (ret <= 0) { >- return false; >- } >- buf[ret] = '\0'; >- >- if (strstr(buf, sysfile_str)) { >- return true; >- } >- return false; >-} >- >-static void linux_sys_state_suspend(SuspendMode mode, Error **errp) >-{ >- g_autoptr(GError) local_gerr = NULL; >- const char *sysfile_strs[3] = {"disk", "mem", NULL}; >- const char *sysfile_str = sysfile_strs[mode]; >- >- if (!sysfile_str) { >- error_setg(errp, "unknown guest suspend mode"); >- return; >- } >- >- if (!g_file_set_contents(LINUX_SYS_STATE_FILE, sysfile_str, >- -1, &local_gerr)) { >- error_setg(errp, "suspend: cannot write to '%s': %s", >- LINUX_SYS_STATE_FILE, local_gerr->message); >- return; >- } >-} >- >-static void guest_suspend(SuspendMode mode, Error **errp) >-{ >- Error *local_err = NULL; >- bool mode_supported = false; >- >- if (systemd_supports_mode(mode, &local_err)) { >- mode_supported = true; >- systemd_suspend(mode, &local_err); >- >- if (!local_err) { >- return; >- } >- } >- >- error_free(local_err); >- local_err = NULL; >- >- if (pmutils_supports_mode(mode, &local_err)) { >- mode_supported = true; >- pmutils_suspend(mode, &local_err); >- >- if (!local_err) { >- return; >- } >- } >- >- error_free(local_err); >- local_err = NULL; >- >- if (linux_sys_state_supports_mode(mode, &local_err)) { >- mode_supported = true; >- linux_sys_state_suspend(mode, &local_err); >- } >- >- if (!mode_supported) { >- error_free(local_err); >- error_setg(errp, >- "the requested suspend mode is not supported by the guest"); >- } else { >- error_propagate(errp, local_err); >- } >-} >- >-void qmp_guest_suspend_disk(Error **errp) >-{ >- guest_suspend(SUSPEND_MODE_DISK, errp); >-} >- >-void qmp_guest_suspend_ram(Error **errp) >-{ >- guest_suspend(SUSPEND_MODE_RAM, errp); >-} >- >-void qmp_guest_suspend_hybrid(Error **errp) >-{ >- guest_suspend(SUSPEND_MODE_HYBRID, errp); >-} >- > #endif /* __linux__ */ > > #if defined(__linux__) || defined(__FreeBSD__) >-- >2.45.1 > >
© 2016 - 2024 Red Hat, Inc.