]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sleep-config: introduce sleep_supported_full that returns a reason
authorMike Yuan <me@yhndnzj.com>
Mon, 16 Oct 2023 12:34:29 +0000 (20:34 +0800)
committerMike Yuan <me@yhndnzj.com>
Fri, 20 Oct 2023 15:22:28 +0000 (23:22 +0800)
Preparation for later commits.

Also some other cleanups:
* Add assertions
* Use FOREACH_ARRAY

src/login/logind-action.c
src/login/logind-dbus.c
src/shared/sleep-config.c
src/shared/sleep-config.h
src/test/test-sleep-config.c

index a2b211933a2459f44a322d8f9e2bbd2bb41e2669..d4d53bddd704d678b89a2913052bcc9874171be8 100644 (file)
@@ -201,20 +201,20 @@ int manager_handle_action(
         }
 
         if (handle == HANDLE_SUSPEND)
-                supported = can_sleep(SLEEP_SUSPEND) > 0;
+                supported = sleep_supported(SLEEP_SUSPEND) > 0;
         else if (handle == HANDLE_HIBERNATE)
-                supported = can_sleep(SLEEP_HIBERNATE) > 0;
+                supported = sleep_supported(SLEEP_HIBERNATE) > 0;
         else if (handle == HANDLE_HYBRID_SLEEP)
-                supported = can_sleep(SLEEP_HYBRID_SLEEP) > 0;
+                supported = sleep_supported(SLEEP_HYBRID_SLEEP) > 0;
         else if (handle == HANDLE_SUSPEND_THEN_HIBERNATE)
-                supported = can_sleep(SLEEP_SUSPEND_THEN_HIBERNATE) > 0;
+                supported = sleep_supported(SLEEP_SUSPEND_THEN_HIBERNATE) > 0;
         else if (handle == HANDLE_KEXEC)
                 supported = access(KEXEC, X_OK) >= 0;
         else
                 supported = true;
 
         if (!supported && HANDLE_ACTION_IS_SLEEP(handle) && handle != HANDLE_SUSPEND) {
-                supported = can_sleep(SLEEP_SUSPEND) > 0;
+                supported = sleep_supported(SLEEP_SUSPEND) > 0;
                 if (supported) {
                         log_notice("Requested %s operation is not supported, using regular suspend instead.",
                                    handle_action_to_string(handle));
index d631a3071668bc5297d4a967b9f671d34e9d1153..e17d48bf262529d944fccf42a38300417786a9e2 100644 (file)
@@ -1924,16 +1924,34 @@ static int method_do_shutdown_or_sleep(
                                          "There's already a shutdown or sleep operation in progress");
 
         if (a->sleep_operation >= 0) {
-                r = can_sleep(a->sleep_operation);
-                if (r == -ENOSPC)
-                        return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
-                                                "Not enough suitable swap space for hibernation available on compatible block devices and file systems");
-                if (r == 0)
-                        return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
-                                                 "Sleep verb \"%s\" not supported",
-                                                 sleep_operation_to_string(a->sleep_operation));
+                SleepSupport support;
+
+                r = sleep_supported_full(a->sleep_operation, &support);
                 if (r < 0)
                         return r;
+                if (r == 0)
+                        switch (support) {
+
+                        case SLEEP_DISABLED:
+                                return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+                                                         "Sleep verb '%s' is disabled by config",
+                                                         sleep_operation_to_string(a->sleep_operation));
+
+                        case SLEEP_NOT_CONFIGURED:
+                        case SLEEP_STATE_OR_MODE_NOT_SUPPORTED:
+                        case SLEEP_ALARM_NOT_SUPPORTED:
+                                return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+                                                         "Sleep verb '%s' is not configured or configuration is not supported by kernel",
+                                                         sleep_operation_to_string(a->sleep_operation));
+
+                        case SLEEP_NOT_ENOUGH_SWAP_SPACE:
+                                return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+                                                        "Not enough suitable swap space for hibernation available on compatible block devices and file systems");
+
+                        default:
+                                assert_not_reached();
+
+                        }
         }
 
         r = verify_shutdown_creds(m, message, a, flags, error);
@@ -2395,11 +2413,11 @@ static int method_can_shutdown_or_sleep(
         assert(a);
 
         if (a->sleep_operation >= 0) {
-                r = can_sleep(a->sleep_operation);
-                if (IN_SET(r,  0, -ENOSPC))
-                        return sd_bus_reply_method_return(message, "s", "na");
+                r = sleep_supported(a->sleep_operation);
                 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);
index 736e38381fb020a2f7cf5e8c1ae1318b225a21bd..e5e96041ed05dd90549ed4284c3256402afccc70 100644 (file)
@@ -191,71 +191,122 @@ int sleep_mode_supported(char **modes) {
         return false;
 }
 
-static int can_sleep_internal(const SleepConfig *sleep_config, SleepOperation operation, bool check_allowed);
+static int sleep_supported_internal(
+                const SleepConfig *sleep_config,
+                SleepOperation operation,
+                bool check_allowed,
+                SleepSupport *ret_support);
 
-static bool can_s2h(const SleepConfig *sleep_config) {
+static int s2h_supported(const SleepConfig *sleep_config, SleepSupport *ret_support) {
 
         static const SleepOperation operations[] = {
                 SLEEP_SUSPEND,
                 SLEEP_HIBERNATE,
         };
 
+        SleepSupport support;
         int r;
 
+        assert(sleep_config);
+        assert(ret_support);
+
         if (!clock_supported(CLOCK_BOOTTIME_ALARM)) {
-                log_debug("CLOCK_BOOTTIME_ALARM is not supported.");
+                log_debug("CLOCK_BOOTTIME_ALARM is not supported, can't perform %s.", sleep_operation_to_string(SLEEP_SUSPEND_THEN_HIBERNATE));
+                *ret_support = SLEEP_ALARM_NOT_SUPPORTED;
                 return false;
         }
 
-        for (size_t i = 0; i < ELEMENTSOF(operations); i++) {
-                r = can_sleep_internal(sleep_config, operations[i], false);
-                if (IN_SET(r, 0, -ENOSPC)) {
-                        log_debug("Unable to %s system.", sleep_operation_to_string(operations[i]));
+        FOREACH_ARRAY(i, operations, ELEMENTSOF(operations)) {
+                r = sleep_supported_internal(sleep_config, *i, /* check_allowed = */ false, &support);
+                if (r < 0)
+                        return r;
+                if (r == 0) {
+                        log_debug("Sleep operation %s is not supported, can't perform %s.",
+                                  sleep_operation_to_string(*i), sleep_operation_to_string(SLEEP_SUSPEND_THEN_HIBERNATE));
+                        *ret_support = support;
                         return false;
                 }
-                if (r < 0)
-                        return log_debug_errno(r, "Failed to check if %s is possible: %m", sleep_operation_to_string(operations[i]));
         }
 
+        assert(support == SLEEP_SUPPORTED);
+        *ret_support = support;
+
         return true;
 }
 
-static int can_sleep_internal(
+static int sleep_supported_internal(
                 const SleepConfig *sleep_config,
                 SleepOperation operation,
-                bool check_allowed) {
+                bool check_allowed,
+                SleepSupport *ret_support) {
+
+        int r;
 
+        assert(sleep_config);
         assert(operation >= 0);
         assert(operation < _SLEEP_OPERATION_MAX);
+        assert(ret_support);
 
         if (check_allowed && !sleep_config->allow[operation]) {
-                log_debug("Sleep mode \"%s\" is disabled by configuration.", sleep_operation_to_string(operation));
+                log_debug("Sleep operation %s is disabled by configuration.", sleep_operation_to_string(operation));
+                *ret_support = SLEEP_DISABLED;
                 return false;
         }
 
         if (operation == SLEEP_SUSPEND_THEN_HIBERNATE)
-                return can_s2h(sleep_config);
+                return s2h_supported(sleep_config, ret_support);
 
-        if (sleep_state_supported(sleep_config->states[operation]) <= 0 ||
-            sleep_mode_supported(sleep_config->modes[operation]) <= 0)
+        assert(operation < _SLEEP_OPERATION_CONFIG_MAX);
+
+        r = sleep_state_supported(sleep_config->states[operation]);
+        if (r == -ENOMSG) {
+                *ret_support = SLEEP_NOT_CONFIGURED;
                 return false;
+        }
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                *ret_support = SLEEP_STATE_OR_MODE_NOT_SUPPORTED;
+                return false;
+        }
 
-        if (operation == SLEEP_SUSPEND)
-                return true;
+        r = sleep_mode_supported(sleep_config->modes[operation]);
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                *ret_support = SLEEP_STATE_OR_MODE_NOT_SUPPORTED;
+                return false;
+        }
 
-        if (!enough_swap_for_hibernation())
-                return -ENOSPC;
+        if (IN_SET(operation, SLEEP_HIBERNATE, SLEEP_HYBRID_SLEEP) && !enough_swap_for_hibernation()) {
+                *ret_support = SLEEP_NOT_ENOUGH_SWAP_SPACE;
+                return false;
+        }
 
+        *ret_support = SLEEP_SUPPORTED;
         return true;
 }
 
-int can_sleep(SleepOperation operation) {
+int sleep_supported_full(SleepOperation operation, SleepSupport *ret_support) {
         _cleanup_(sleep_config_freep) SleepConfig *sleep_config = NULL;
+        SleepSupport support;
         int r;
 
+        assert(operation >= 0);
+        assert(operation < _SLEEP_OPERATION_MAX);
+
         r = parse_sleep_config(&sleep_config);
         if (r < 0)
                 return r;
 
-        return can_sleep_internal(sleep_config, operation, true);
+        r = sleep_supported_internal(sleep_config, operation, /* check_allowed = */ true, &support);
+        if (r < 0)
+                return r;
+
+        assert((r > 0) == (support == SLEEP_SUPPORTED));
+
+        if (ret_support)
+                *ret_support = support;
+
+        return r;
 }
index fc737bf94100158176aef57be00f8326ff0c2bc1..756b0e13ae2b89332ea9d40c1f5f612531257b8f 100644 (file)
@@ -35,7 +35,19 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(SleepConfig*, sleep_config_free);
 
 int parse_sleep_config(SleepConfig **sleep_config);
 
-int can_sleep(SleepOperation operation);
+typedef enum SleepSupport {
+        SLEEP_SUPPORTED,
+        SLEEP_DISABLED,                    /* Disabled in SleepConfig.allow */
+        SLEEP_NOT_CONFIGURED,              /* SleepConfig.states is not configured */
+        SLEEP_STATE_OR_MODE_NOT_SUPPORTED, /* SleepConfig.states/modes are not supported by kernel */
+        SLEEP_NOT_ENOUGH_SWAP_SPACE,
+        SLEEP_ALARM_NOT_SUPPORTED,         /* CLOCK_BOOTTIME_ALARM is unsupported by kernel (only used by s2h) */
+} SleepSupport;
+
+int sleep_supported_full(SleepOperation operation, SleepSupport *ret_support);
+static inline int sleep_supported(SleepOperation operation) {
+        return sleep_supported_full(operation, NULL);
+}
 
 /* Only for test-sleep-config */
 int sleep_state_supported(char **states);
index c7aa0619b429c2522b0a6ff54d8408a1685fee56..112fec63461e457fca25df33479f26dacb4d4640 100644 (file)
@@ -59,13 +59,13 @@ TEST(sleep_supported) {
         log_info("Freeze configured: %s", yes_no(sleep_state_supported(freeze) > 0));
 
         log_info("/= high-level sleep verbs =/");
-        r = can_sleep(SLEEP_SUSPEND);
+        r = sleep_supported(SLEEP_SUSPEND);
         log_info("Suspend configured and possible: %s", r >= 0 ? yes_no(r) : STRERROR(r));
-        r = can_sleep(SLEEP_HIBERNATE);
+        r = sleep_supported(SLEEP_HIBERNATE);
         log_info("Hibernation configured and possible: %s", r >= 0 ? yes_no(r) : STRERROR(r));
-        r = can_sleep(SLEEP_HYBRID_SLEEP);
+        r = sleep_supported(SLEEP_HYBRID_SLEEP);
         log_info("Hybrid-sleep configured and possible: %s", r >= 0 ? yes_no(r) : STRERROR(r));
-        r = can_sleep(SLEEP_SUSPEND_THEN_HIBERNATE);
+        r = sleep_supported(SLEEP_SUSPEND_THEN_HIBERNATE);
         log_info("Suspend-then-Hibernate configured and possible: %s", r >= 0 ? yes_no(r) : STRERROR(r));
 }