aboutsummaryrefslogtreecommitdiff
path: root/qga/commands-posix.c
diff options
context:
space:
mode:
authorDaniel Henrique Barboza <danielhb413@gmail.com>2018-06-21 07:21:52 -0300
committerMichael Roth <mdroth@linux.vnet.ibm.com>2018-07-03 15:20:51 -0500
commit067927d62e097a8a3624a926e792756ce7a353ed (patch)
treebff66bf64b5116b77fa43f7cf319dd53dcdc1a7d /qga/commands-posix.c
parent8b020b5eb708091e723518907184e609350f6d41 (diff)
downloadqemu-067927d62e097a8a3624a926e792756ce7a353ed.zip
qemu-067927d62e097a8a3624a926e792756ce7a353ed.tar.gz
qemu-067927d62e097a8a3624a926e792756ce7a353ed.tar.bz2
qga: systemd hibernate/suspend/hybrid-sleep support
pmutils isn't being supported by newer OSes like Fedora 27 or Mint. This means that the only suspend option QGA offers for these guests are writing directly into the Linux sys state file. This also means that QGA also loses the ability to do hybrid suspend in those guests - this suspend mode is only available when using pmutils. Newer guests can use systemd facilities to do all the suspend types QGA supports. The mapping in comparison with pmutils is: - pm-hibernate -> systemctl hibernate - pm-suspend -> systemctl suspend - pm-suspend-hybrid -> systemctl hybrid-sleep To discover whether systemd supports these functions, we inspect the status of the services that implements them. With this patch, we can offer hybrid suspend again for newer guests that do not have pmutils support anymore. Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Diffstat (limited to 'qga/commands-posix.c')
-rw-r--r--qga/commands-posix.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 1559753..cdb8259 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1517,6 +1517,63 @@ static int run_process_child(const char *command[], Error **errp)
return -1;
}
+static bool systemd_supports_mode(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ 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, &local_err);
+
+ /*
+ * 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;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ }
+
+ 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;
@@ -1660,6 +1717,14 @@ static void bios_supports_mode(SuspendMode mode, Error **errp)
Error *local_err = NULL;
bool ret;
+ ret = systemd_supports_mode(mode, &local_err);
+ if (ret) {
+ return;
+ }
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
ret = pmutils_supports_mode(mode, &local_err);
if (ret) {
return;
@@ -1689,6 +1754,13 @@ static void guest_suspend(SuspendMode mode, Error **errp)
return;
}
+ systemd_suspend(mode, &local_err);
+ if (!local_err) {
+ return;
+ }
+
+ error_free(local_err);
+
pmutils_suspend(mode, &local_err);
if (!local_err) {
return;