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:
parent
be2a4b0d7e
commit
c8cd8ca398
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user