]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/login/logind-dbus.c
Merge pull request #8700 from keszybz/hibernation
[thirdparty/systemd.git] / src / login / logind-dbus.c
index 27e6b9ddf94c260e063977b0390d50aa40f0b012..563c7fef9f9dbfd50c9cad466f42a44f018a57f0 100644 (file)
@@ -16,6 +16,7 @@
 #include "audit-util.h"
 #include "bus-common-errors.h"
 #include "bus-error.h"
+#include "bus-unit-util.h"
 #include "bus-util.h"
 #include "dirent-util.h"
 #include "efivars.h"
@@ -1692,6 +1693,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(
                 InhibitWhat w,
                 sd_bus_error *error) {
 
+        _cleanup_free_ char *load_state = NULL;
         bool delayed;
         int r;
 
@@ -1701,6 +1703,15 @@ int bus_manager_shutdown_or_sleep_now_or_later(
         assert(w <= _INHIBIT_WHAT_MAX);
         assert(!m->action_job);
 
+        r = unit_load_state(m->bus, unit_name, &load_state);
+        if (r < 0)
+                return r;
+
+        if (!streq(load_state, "loaded")) {
+                log_notice("Unit %s is %s, refusing operation.", unit_name, load_state);
+                return -EACCES;
+        }
+
         /* Tell everybody to prepare for shutdown/sleep */
         (void) send_prepare_for(m, w, true);
 
@@ -1811,11 +1822,14 @@ static int method_do_shutdown_or_sleep(
 
         if (sleep_verb) {
                 r = can_sleep(sleep_verb);
+                if (r == -ENOSPC)
+                        return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+                                                "Not enough swap space for hibernation");
+                if (r == 0)
+                        return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+                                                 "Sleep verb \"%s\" not supported", sleep_verb);
                 if (r < 0)
                         return r;
-
-                if (r == 0)
-                        return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
         }
 
         r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions,
@@ -2222,6 +2236,7 @@ static int method_can_shutdown_or_sleep(
                 sd_bus_error *error) {
 
         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+        HandleAction handle;
         bool multiple_sessions, challenge, blocked;
         const char *result = NULL;
         uid_t uid;
@@ -2237,10 +2252,10 @@ static int method_can_shutdown_or_sleep(
 
         if (sleep_verb) {
                 r = can_sleep(sleep_verb);
+                if (IN_SET(r,  0, -ENOSPC))
+                        return sd_bus_reply_method_return(message, "s", "na");
                 if (r < 0)
                         return r;
-                if (r == 0)
-                        return sd_bus_reply_method_return(message, "s", "na");
         }
 
         r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
@@ -2258,6 +2273,25 @@ static int method_can_shutdown_or_sleep(
         multiple_sessions = r > 0;
         blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
 
+        handle = handle_action_from_string(sleep_verb);
+        if (handle >= 0) {
+                const char *target;
+
+                target = manager_target_for_action(handle);
+                if (target) {
+                        _cleanup_free_ char *load_state = NULL;
+
+                        r = unit_load_state(m->bus, target, &load_state);
+                        if (r < 0)
+                                return r;
+
+                        if (!streq(load_state, "loaded")) {
+                                result = "no";
+                                goto finish;
+                        }
+                }
+        }
+
         if (multiple_sessions) {
                 r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, UID_INVALID, &challenge, error);
                 if (r < 0)
@@ -2300,6 +2334,7 @@ static int method_can_shutdown_or_sleep(
                         result = "no";
         }
 
+ finish:
         return sd_bus_reply_method_return(message, "s", result);
 }