mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
sleep-config: introduce sleep_supported_full that returns a reason
Preparation for later commits. Also some other cleanups: * Add assertions * Use FOREACH_ARRAY
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user