1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-02-04 17:47:03 +03:00

sleep: use SleepOperation enum everywhere and drop sleep_settings()

Instead of comparing strings everywhere, let's use the new enum. This
allows us to drop sleep_settings(), since the operation enum can be
directly used as index into the config settings.

Some minor other refactoring is done, but mostly just shifting thing
around a bit, no actual change in behaviour.
This commit is contained in:
Lennart Poettering 2021-05-21 18:23:42 +02:00
parent be2a4b0d7e
commit c8cd8ca398
6 changed files with 148 additions and 177 deletions

View File

@ -102,20 +102,20 @@ int manager_handle_action(
}
if (handle == HANDLE_SUSPEND)
supported = can_sleep("suspend") > 0;
supported = can_sleep(SLEEP_SUSPEND) > 0;
else if (handle == HANDLE_HIBERNATE)
supported = can_sleep("hibernate") > 0;
supported = can_sleep(SLEEP_HIBERNATE) > 0;
else if (handle == HANDLE_HYBRID_SLEEP)
supported = can_sleep("hybrid-sleep") > 0;
supported = can_sleep(SLEEP_HYBRID_SLEEP) > 0;
else if (handle == HANDLE_SUSPEND_THEN_HIBERNATE)
supported = can_sleep("suspend-then-hibernate") > 0;
supported = can_sleep(SLEEP_SUSPEND_THEN_HIBERNATE) > 0;
else if (handle == HANDLE_KEXEC)
supported = access(KEXEC, X_OK) >= 0;
else
supported = true;
if (!supported && IN_SET(handle, HANDLE_HIBERNATE, HANDLE_HYBRID_SLEEP, HANDLE_SUSPEND_THEN_HIBERNATE)) {
supported = can_sleep("suspend") > 0;
supported = can_sleep(SLEEP_SUSPEND) > 0;
if (supported) {
log_notice("Requested %s operation is not supported, using regular suspend instead.",
handle_action_to_string(handle));

View File

@ -1851,7 +1851,7 @@ static int method_do_shutdown_or_sleep(
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
const char *sleep_verb,
SleepOperation sleep_operation,
bool with_flags,
sd_bus_error *error) {
@ -1894,14 +1894,14 @@ static int method_do_shutdown_or_sleep(
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
"There's already a shutdown or sleep operation in progress");
if (sleep_verb) {
r = can_sleep(sleep_verb);
if (sleep_operation >= 0) {
r = can_sleep(sleep_operation);
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);
"Sleep verb \"%s\" not supported", sleep_operation_to_string(sleep_operation));
if (r < 0)
return r;
}
@ -1928,7 +1928,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error
"org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-multiple-sessions",
"org.freedesktop.login1.power-off-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
sd_bus_message_is_method_call(message, NULL, "PowerOffWithFlags"),
error);
}
@ -1943,7 +1943,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
"org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-multiple-sessions",
"org.freedesktop.login1.reboot-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
sd_bus_message_is_method_call(message, NULL, "RebootWithFlags"),
error);
}
@ -1958,7 +1958,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er
"org.freedesktop.login1.halt",
"org.freedesktop.login1.halt-multiple-sessions",
"org.freedesktop.login1.halt-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
sd_bus_message_is_method_call(message, NULL, "HaltWithFlags"),
error);
}
@ -1973,7 +1973,7 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error
"org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
"suspend",
SLEEP_SUSPEND,
sd_bus_message_is_method_call(message, NULL, "SuspendWithFlags"),
error);
}
@ -1988,7 +1988,7 @@ static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_erro
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hibernate",
SLEEP_HIBERNATE,
sd_bus_message_is_method_call(message, NULL, "HibernateWithFlags"),
error);
}
@ -2003,7 +2003,7 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hybrid-sleep",
SLEEP_HYBRID_SLEEP,
sd_bus_message_is_method_call(message, NULL, "HybridSleepWithFlags"),
error);
}
@ -2018,7 +2018,7 @@ static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hybrid-sleep",
SLEEP_SUSPEND_THEN_HIBERNATE,
sd_bus_message_is_method_call(message, NULL, "SuspendThenHibernateWithFlags"),
error);
}
@ -2317,7 +2317,7 @@ static int method_can_shutdown_or_sleep(
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
const char *sleep_verb,
SleepOperation sleep_operation,
sd_bus_error *error) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
@ -2335,8 +2335,8 @@ static int method_can_shutdown_or_sleep(
assert(action_multiple_sessions);
assert(action_ignore_inhibit);
if (sleep_verb) {
r = can_sleep(sleep_verb);
if (sleep_operation >= 0) {
r = can_sleep(sleep_operation);
if (IN_SET(r, 0, -ENOSPC))
return sd_bus_reply_method_return(message, "s", "na");
if (r < 0)
@ -2358,7 +2358,7 @@ 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);
handle = handle_action_from_string(sleep_operation_to_string(sleep_operation));
if (handle >= 0) {
const char *target;
@ -2434,7 +2434,7 @@ static int method_can_poweroff(sd_bus_message *message, void *userdata, sd_bus_e
"org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-multiple-sessions",
"org.freedesktop.login1.power-off-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
error);
}
@ -2447,7 +2447,7 @@ static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_err
"org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-multiple-sessions",
"org.freedesktop.login1.reboot-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
error);
}
@ -2460,7 +2460,7 @@ static int method_can_halt(sd_bus_message *message, void *userdata, sd_bus_error
"org.freedesktop.login1.halt",
"org.freedesktop.login1.halt-multiple-sessions",
"org.freedesktop.login1.halt-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
error);
}
@ -2473,7 +2473,7 @@ static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_er
"org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
"suspend",
SLEEP_SUSPEND,
error);
}
@ -2486,7 +2486,7 @@ static int method_can_hibernate(sd_bus_message *message, void *userdata, sd_bus_
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hibernate",
SLEEP_HIBERNATE,
error);
}
@ -2499,7 +2499,7 @@ static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_b
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hybrid-sleep",
SLEEP_HYBRID_SLEEP,
error);
}
@ -2512,7 +2512,7 @@ static int method_can_suspend_then_hibernate(sd_bus_message *message, void *user
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"suspend-then-hibernate",
SLEEP_SUSPEND_THEN_HIBERNATE,
error);
}

View File

@ -44,19 +44,19 @@ int parse_sleep_config(SleepConfig **ret_sleep_config) {
return log_oom();
const ConfigTableItem items[] = {
{ "Sleep", "AllowSuspend", config_parse_tristate, 0, &allow_suspend },
{ "Sleep", "AllowHibernation", config_parse_tristate, 0, &allow_hibernate },
{ "Sleep", "AllowSuspendThenHibernate", config_parse_tristate, 0, &allow_s2h },
{ "Sleep", "AllowHybridSleep", config_parse_tristate, 0, &allow_hybrid_sleep },
{ "Sleep", "AllowSuspend", config_parse_tristate, 0, &allow_suspend },
{ "Sleep", "AllowHibernation", config_parse_tristate, 0, &allow_hibernate },
{ "Sleep", "AllowSuspendThenHibernate", config_parse_tristate, 0, &allow_s2h },
{ "Sleep", "AllowHybridSleep", config_parse_tristate, 0, &allow_hybrid_sleep },
{ "Sleep", "SuspendMode", config_parse_strv, 0, &sc->suspend_modes },
{ "Sleep", "SuspendState", config_parse_strv, 0, &sc->suspend_states },
{ "Sleep", "HibernateMode", config_parse_strv, 0, &sc->hibernate_modes },
{ "Sleep", "HibernateState", config_parse_strv, 0, &sc->hibernate_states },
{ "Sleep", "HybridSleepMode", config_parse_strv, 0, &sc->hybrid_modes },
{ "Sleep", "HybridSleepState", config_parse_strv, 0, &sc->hybrid_states },
{ "Sleep", "SuspendMode", config_parse_strv, 0, sc->modes + SLEEP_SUSPEND },
{ "Sleep", "SuspendState", config_parse_strv, 0, sc->states + SLEEP_SUSPEND },
{ "Sleep", "HibernateMode", config_parse_strv, 0, sc->modes + SLEEP_HIBERNATE },
{ "Sleep", "HibernateState", config_parse_strv, 0, sc->states + SLEEP_HIBERNATE },
{ "Sleep", "HybridSleepMode", config_parse_strv, 0, sc->modes + SLEEP_HYBRID_SLEEP },
{ "Sleep", "HybridSleepState", config_parse_strv, 0, sc->states + SLEEP_HYBRID_SLEEP },
{ "Sleep", "HibernateDelaySec", config_parse_sec, 0, &sc->hibernate_delay_sec},
{ "Sleep", "HibernateDelaySec", config_parse_sec, 0, &sc->hibernate_delay_sec },
{}
};
@ -70,29 +70,29 @@ int parse_sleep_config(SleepConfig **ret_sleep_config) {
NULL);
/* use default values unless set */
sc->allow_suspend = allow_suspend != 0;
sc->allow_hibernate = allow_hibernate != 0;
sc->allow_hybrid_sleep = allow_hybrid_sleep >= 0 ? allow_hybrid_sleep
sc->allow[SLEEP_SUSPEND] = allow_suspend != 0;
sc->allow[SLEEP_HIBERNATE] = allow_hibernate != 0;
sc->allow[SLEEP_HYBRID_SLEEP] = allow_hybrid_sleep >= 0 ? allow_hybrid_sleep
: (allow_suspend != 0 && allow_hibernate != 0);
sc->allow_s2h = allow_s2h >= 0 ? allow_s2h
sc->allow[SLEEP_SUSPEND_THEN_HIBERNATE] = allow_s2h >= 0 ? allow_s2h
: (allow_suspend != 0 && allow_hibernate != 0);
if (!sc->suspend_states)
sc->suspend_states = strv_new("mem", "standby", "freeze");
if (!sc->hibernate_modes)
sc->hibernate_modes = strv_new("platform", "shutdown");
if (!sc->hibernate_states)
sc->hibernate_states = strv_new("disk");
if (!sc->hybrid_modes)
sc->hybrid_modes = strv_new("suspend", "platform", "shutdown");
if (!sc->hybrid_states)
sc->hybrid_states = strv_new("disk");
if (!sc->states[SLEEP_SUSPEND])
sc->states[SLEEP_SUSPEND] = strv_new("mem", "standby", "freeze");
if (!sc->modes[SLEEP_HIBERNATE])
sc->modes[SLEEP_HIBERNATE] = strv_new("platform", "shutdown");
if (!sc->states[SLEEP_HIBERNATE])
sc->states[SLEEP_HIBERNATE] = strv_new("disk");
if (!sc->modes[SLEEP_HYBRID_SLEEP])
sc->modes[SLEEP_HYBRID_SLEEP] = strv_new("suspend", "platform", "shutdown");
if (!sc->states[SLEEP_HYBRID_SLEEP])
sc->states[SLEEP_HYBRID_SLEEP] = strv_new("disk");
if (sc->hibernate_delay_sec == 0)
sc->hibernate_delay_sec = 2 * USEC_PER_HOUR;
/* ensure values set for all required fields */
if (!sc->suspend_states || !sc->hibernate_modes
|| !sc->hibernate_states || !sc->hybrid_modes || !sc->hybrid_states)
if (!sc->states[SLEEP_SUSPEND] || !sc->modes[SLEEP_HIBERNATE]
|| !sc->states[SLEEP_HIBERNATE] || !sc->modes[SLEEP_HYBRID_SLEEP] || !sc->states[SLEEP_HYBRID_SLEEP])
return log_oom();
*ret_sleep_config = TAKE_PTR(sc);
@ -589,10 +589,15 @@ int read_fiemap(int fd, struct fiemap **ret) {
return 0;
}
static int can_sleep_internal(const char *verb, bool check_allowed, const SleepConfig *sleep_config);
static int can_sleep_internal(const SleepConfig *sleep_config, SleepOperation operation, bool check_allowed);
static bool can_s2h(const SleepConfig *sleep_config) {
const char *p;
static const SleepOperation operations[] = {
SLEEP_SUSPEND,
SLEEP_HIBERNATE,
};
int r;
if (!clock_supported(CLOCK_BOOTTIME_ALARM)) {
@ -600,42 +605,40 @@ static bool can_s2h(const SleepConfig *sleep_config) {
return false;
}
FOREACH_STRING(p, "suspend", "hibernate") {
r = can_sleep_internal(p, false, sleep_config);
for (size_t i = 0; i < ELEMENTSOF(operations); i++) {
r = can_sleep_internal(sleep_config, operations[i], false);
if (IN_SET(r, 0, -ENOSPC, -EADV)) {
log_debug("Unable to %s system.", p);
log_debug("Unable to %s system.", sleep_operation_to_string(operations[i]));
return false;
}
if (r < 0)
return log_debug_errno(r, "Failed to check if %s is possible: %m", p);
return log_debug_errno(r, "Failed to check if %s is possible: %m", sleep_operation_to_string(operations[i]));
}
return true;
}
static int can_sleep_internal(const char *verb, bool check_allowed, const SleepConfig *sleep_config) {
bool allow;
char **modes = NULL, **states = NULL;
int r;
static int can_sleep_internal(
const SleepConfig *sleep_config,
SleepOperation operation,
bool check_allowed) {
assert(STR_IN_SET(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate"));
assert(operation >= 0);
assert(operation < _SLEEP_OPERATION_MAX);
r = sleep_settings(verb, sleep_config, &allow, &modes, &states);
if (r < 0)
return false;
if (check_allowed && !allow) {
log_debug("Sleep mode \"%s\" is disabled by configuration.", verb);
if (check_allowed && !sleep_config->allow[operation]) {
log_debug("Sleep mode \"%s\" is disabled by configuration.", sleep_operation_to_string(operation));
return false;
}
if (streq(verb, "suspend-then-hibernate"))
if (operation == SLEEP_SUSPEND_THEN_HIBERNATE)
return can_s2h(sleep_config);
if (!can_sleep_state(states) || !can_sleep_disk(modes))
if (!can_sleep_state(sleep_config->states[operation]) ||
!can_sleep_disk(sleep_config->modes[operation]))
return false;
if (streq(verb, "suspend"))
if (operation == SLEEP_SUSPEND)
return true;
if (!enough_swap_for_hibernation())
@ -644,7 +647,7 @@ static int can_sleep_internal(const char *verb, bool check_allowed, const SleepC
return true;
}
int can_sleep(const char *verb) {
int can_sleep(SleepOperation operation) {
_cleanup_(free_sleep_configp) SleepConfig *sleep_config = NULL;
int r;
@ -652,51 +655,17 @@ int can_sleep(const char *verb) {
if (r < 0)
return r;
return can_sleep_internal(verb, true, sleep_config);
}
int sleep_settings(const char *verb, const SleepConfig *sleep_config, bool *ret_allow, char ***ret_modes, char ***ret_states) {
assert(verb);
assert(sleep_config);
assert(STR_IN_SET(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate"));
if (streq(verb, "suspend")) {
*ret_allow = sleep_config->allow_suspend;
*ret_modes = sleep_config->suspend_modes;
*ret_states = sleep_config->suspend_states;
} else if (streq(verb, "hibernate")) {
*ret_allow = sleep_config->allow_hibernate;
*ret_modes = sleep_config->hibernate_modes;
*ret_states = sleep_config->hibernate_states;
} else if (streq(verb, "hybrid-sleep")) {
*ret_allow = sleep_config->allow_hybrid_sleep;
*ret_modes = sleep_config->hybrid_modes;
*ret_states = sleep_config->hybrid_states;
} else if (streq(verb, "suspend-then-hibernate")) {
*ret_allow = sleep_config->allow_s2h;
*ret_modes = *ret_states = NULL;
}
/* suspend modes empty by default */
if ((!ret_modes && !streq(verb, "suspend")) || !ret_states)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No modes or states set for %s; Check sleep.conf", verb);
return 0;
return can_sleep_internal(sleep_config, operation, true);
}
SleepConfig* free_sleep_config(SleepConfig *sc) {
if (!sc)
return NULL;
strv_free(sc->suspend_modes);
strv_free(sc->suspend_states);
strv_free(sc->hibernate_modes);
strv_free(sc->hibernate_states);
strv_free(sc->hybrid_modes);
strv_free(sc->hybrid_states);
for (SleepOperation i = 0; i < _SLEEP_OPERATION_MAX; i++) {
strv_free(sc->modes[i]);
strv_free(sc->states[i]);
}
return mfree(sc);
}

View File

@ -14,19 +14,10 @@ typedef enum SleepOperation {
} SleepOperation;
typedef struct SleepConfig {
bool allow_suspend; /* AllowSuspend */
bool allow_hibernate; /* AllowHibernation */
bool allow_s2h; /* AllowSuspendThenHibernate */
bool allow_hybrid_sleep; /* AllowHybridSleep */
char **suspend_modes; /* SuspendMode */
char **suspend_states; /* SuspendState */
char **hibernate_modes; /* HibernateMode */
char **hibernate_states; /* HibernateState */
char **hybrid_modes; /* HybridSleepMode */
char **hybrid_states; /* HybridSleepState */
usec_t hibernate_delay_sec; /* HibernateDelaySec */
bool allow[_SLEEP_OPERATION_MAX];
char **modes[_SLEEP_OPERATION_MAX];
char **states[_SLEEP_OPERATION_MAX];
usec_t hibernate_delay_sec;
} SleepConfig;
SleepConfig* free_sleep_config(SleepConfig *sc);
@ -57,13 +48,11 @@ typedef struct HibernateLocation {
HibernateLocation* hibernate_location_free(HibernateLocation *hl);
DEFINE_TRIVIAL_CLEANUP_FUNC(HibernateLocation*, hibernate_location_free);
int sleep_settings(const char *verb, const SleepConfig *sleep_config, bool *ret_allow, char ***ret_modes, char ***ret_states);
int read_fiemap(int fd, struct fiemap **ret);
int parse_sleep_config(SleepConfig **sleep_config);
int find_hibernate_location(HibernateLocation **ret_hibernate_location);
int can_sleep(const char *verb);
int can_sleep(SleepOperation operation);
int can_sleep_disk(char **types);
int can_sleep_state(char **types);

View File

@ -35,9 +35,7 @@
#include "time-util.h"
#include "util.h"
static char* arg_verb = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_verb, freep);
static SleepOperation arg_operation = _SLEEP_OPERATION_INVALID;
static int write_hibernate_location_info(const HibernateLocation *hibernate_location) {
char offset_str[DECIMAL_STR_MAX(uint64_t)];
@ -169,11 +167,17 @@ static int lock_all_homes(void) {
return 0;
}
static int execute(char **modes, char **states, const char *action) {
static int execute(
const SleepConfig *sleep_config,
SleepOperation operation,
const char *action) {
char *arguments[] = {
NULL,
(char*) "pre",
arg_verb,
/* NB: we use 'arg_operation' instead of 'operation' here, as we want to communicate the overall
* operation here, not the specific one, in case of s2h. */
(char*) sleep_operation_to_string(arg_operation),
NULL
};
static const char* const dirs[] = {
@ -181,10 +185,24 @@ static int execute(char **modes, char **states, const char *action) {
NULL
};
_cleanup_fclose_ FILE *f = NULL;
_cleanup_(hibernate_location_freep) HibernateLocation *hibernate_location = NULL;
_cleanup_fclose_ FILE *f = NULL;
char **modes, **states;
int r;
assert(sleep_config);
assert(operation >= 0);
assert(operation < _SLEEP_OPERATION_MAX);
assert(operation != SLEEP_SUSPEND_THEN_HIBERNATE); /* Handled by execute_s2h() instead */
states = sleep_config->states[operation];
modes = sleep_config->modes[operation];
if (strv_isempty(states))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"No sleep states configured for sleep operation %s, can't sleep.",
sleep_operation_to_string(operation));
/* This file is opened first, so that if we hit an error,
* we can abort before modifying any state. */
f = fopen("/sys/power/state", "we");
@ -211,6 +229,11 @@ static int execute(char **modes, char **states, const char *action) {
return log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");;
}
/* Pass an action string to the call-outs. This is mostly our operation string, except if the
* hibernate step of s-t-h fails, in which case we communicate that with a separate action. */
if (!action)
action = sleep_operation_to_string(operation);
r = setenv("SYSTEMD_SLEEP_ACTION", action, 1);
if (r != 0)
log_warning_errno(errno, "Error setting SYSTEMD_SLEEP_ACTION=%s: %m", action);
@ -220,20 +243,20 @@ static int execute(char **modes, char **states, const char *action) {
log_struct(LOG_INFO,
"MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
LOG_MESSAGE("Suspending system..."),
"SLEEP=%s", arg_verb);
LOG_MESSAGE("Entering sleep state '%s'...", sleep_operation_to_string(operation)),
"SLEEP=%s", sleep_operation_to_string(arg_operation));
r = write_state(&f, states);
if (r < 0)
log_struct_errno(LOG_ERR, r,
"MESSAGE_ID=" SD_MESSAGE_SLEEP_STOP_STR,
LOG_MESSAGE("Failed to suspend system. System resumed again: %m"),
"SLEEP=%s", arg_verb);
LOG_MESSAGE("Failed to put system to sleep. System resumed again: %m"),
"SLEEP=%s", sleep_operation_to_string(arg_operation));
else
log_struct(LOG_INFO,
"MESSAGE_ID=" SD_MESSAGE_SLEEP_STOP_STR,
LOG_MESSAGE("System resumed."),
"SLEEP=%s", arg_verb);
LOG_MESSAGE("System returned from sleep state."),
"SLEEP=%s", sleep_operation_to_string(arg_operation));
arguments[1] = (char*) "post";
(void) execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
@ -262,7 +285,7 @@ static int execute_s2h(const SleepConfig *sleep_config) {
if (r < 0)
return log_error_errno(errno, "Error setting hibernate timer: %m");
r = execute(sleep_config->suspend_modes, sleep_config->suspend_states, "suspend");
r = execute(sleep_config, SLEEP_SUSPEND, NULL);
if (r < 0)
return r;
@ -278,11 +301,11 @@ static int execute_s2h(const SleepConfig *sleep_config) {
log_debug("Attempting to hibernate after waking from %s timer",
format_timespan(buf, sizeof(buf), sleep_config->hibernate_delay_sec, USEC_PER_SEC));
r = execute(sleep_config->hibernate_modes, sleep_config->hibernate_states, "hibernate");
r = execute(sleep_config, SLEEP_HIBERNATE, NULL);
if (r < 0) {
log_notice_errno(r, "Couldn't hibernate, will try to suspend again: %m");
r = execute(sleep_config->suspend_modes, sleep_config->suspend_states, "suspend-after-failed-hibernate");
r = execute(sleep_config, SLEEP_SUSPEND, "suspend-after-failed-hibernate");
if (r < 0)
return log_error_errno(r, "Could neither hibernate nor suspend, giving up: %m");
}
@ -351,20 +374,14 @@ static int parse_argv(int argc, char *argv[]) {
"Usage: %s COMMAND",
program_invocation_short_name);
arg_verb = strdup(argv[optind]);
if (!arg_verb)
return log_oom();
if (!STR_IN_SET(arg_verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unknown command '%s'.", arg_verb);
arg_operation = sleep_operation_from_string(argv[optind]);
if (arg_operation < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown command '%s'.", argv[optind]);
return 1 /* work to do */;
}
static int run(int argc, char *argv[]) {
bool allow;
char **modes = NULL, **states = NULL;
_cleanup_(free_sleep_configp) SleepConfig *sleep_config = NULL;
int r;
@ -378,19 +395,15 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return r;
r = sleep_settings(arg_verb, sleep_config, &allow, &modes, &states);
if (r < 0)
return r;
if (!allow)
if (!sleep_config->allow[arg_operation])
return log_error_errno(SYNTHETIC_ERRNO(EACCES),
"Sleep mode \"%s\" is disabled by configuration, refusing.",
arg_verb);
"Sleep operation \"%s\" is disabled by configuration, refusing.",
sleep_operation_to_string(arg_operation));
if (streq(arg_verb, "suspend-then-hibernate"))
if (arg_operation == SLEEP_SUSPEND_THEN_HIBERNATE)
return execute_s2h(sleep_config);
else
return execute(modes, states, arg_verb);
return execute(sleep_config, arg_operation, NULL);
}
DEFINE_MAIN_FUNCTION(run);

View File

@ -25,16 +25,16 @@ static void test_parse_sleep_config(void) {
_cleanup_free_ char *sum, *sus, *him, *his, *hym, *hys;
sum = strv_join(sleep_config->suspend_modes, ", ");
sus = strv_join(sleep_config->suspend_states, ", ");
him = strv_join(sleep_config->hibernate_modes, ", ");
his = strv_join(sleep_config->hibernate_states, ", ");
hym = strv_join(sleep_config->hybrid_modes, ", ");
hys = strv_join(sleep_config->hybrid_states, ", ");
log_debug(" allow_suspend: %u", sleep_config->allow_suspend);
log_debug(" allow_hibernate: %u", sleep_config->allow_hibernate);
log_debug(" allow_s2h: %u", sleep_config->allow_s2h);
log_debug(" allow_hybrid_sleep: %u", sleep_config->allow_hybrid_sleep);
sum = strv_join(sleep_config->modes[SLEEP_SUSPEND], ", ");
sus = strv_join(sleep_config->states[SLEEP_SUSPEND], ", ");
him = strv_join(sleep_config->modes[SLEEP_HIBERNATE], ", ");
his = strv_join(sleep_config->states[SLEEP_HIBERNATE], ", ");
hym = strv_join(sleep_config->modes[SLEEP_HYBRID_SLEEP], ", ");
hys = strv_join(sleep_config->states[SLEEP_HYBRID_SLEEP], ", ");
log_debug(" allow_suspend: %u", sleep_config->allow[SLEEP_SUSPEND]);
log_debug(" allow_hibernate: %u", sleep_config->allow[SLEEP_HIBERNATE]);
log_debug(" allow_s2h: %u", sleep_config->allow[SLEEP_SUSPEND_THEN_HIBERNATE]);
log_debug(" allow_hybrid_sleep: %u", sleep_config->allow[SLEEP_HYBRID_SLEEP]);
log_debug(" suspend modes: %s", sum);
log_debug(" states: %s", sus);
log_debug(" hibernate modes: %s", him);
@ -98,13 +98,13 @@ static void test_sleep(void) {
log_info("Freeze configured: %s", yes_no(can_sleep_state(freeze) > 0));
log_info("/= high-level sleep verbs =/");
r = can_sleep("suspend");
r = can_sleep(SLEEP_SUSPEND);
log_info("Suspend configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r));
r = can_sleep("hibernate");
r = can_sleep(SLEEP_HIBERNATE);
log_info("Hibernation configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r));
r = can_sleep("hybrid-sleep");
r = can_sleep(SLEEP_HYBRID_SLEEP);
log_info("Hybrid-sleep configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r));
r = can_sleep("suspend-then-hibernate");
r = can_sleep(SLEEP_SUSPEND_THEN_HIBERNATE);
log_info("Suspend-then-Hibernate configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r));
}