summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/login/logind-action.c10
-rw-r--r--src/login/logind-dbus.c44
-rw-r--r--src/shared/sleep-config.c147
-rw-r--r--src/shared/sleep-config.h21
-rw-r--r--src/sleep/sleep.c79
-rw-r--r--src/test/test-sleep.c28
6 files changed, 150 insertions, 179 deletions
diff --git a/src/login/logind-action.c b/src/login/logind-action.c
index 1a017c8414..8ed066c25e 100644
--- a/src/login/logind-action.c
+++ b/src/login/logind-action.c
@@ -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));
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 61353c7f17..e48360100c 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -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);
}
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index a1ef64f6e9..7277a55635 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -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", "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", "HibernateDelaySec", config_parse_sec, 0, &sc->hibernate_delay_sec},
+ { "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->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 },
{}
};
@@ -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;
-
- assert(STR_IN_SET(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate"));
+static int can_sleep_internal(
+ const SleepConfig *sleep_config,
+ SleepOperation operation,
+ bool check_allowed) {
- r = sleep_settings(verb, sleep_config, &allow, &modes, &states);
- if (r < 0)
- return false;
+ assert(operation >= 0);
+ assert(operation < _SLEEP_OPERATION_MAX);
- 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);
}
diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h
index c17a5241ab..c049a55ad6 100644
--- a/src/shared/sleep-config.h
+++ b/src/shared/sleep-config.h
@@ -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);
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index 8aeaa1a543..86b155c9ea 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -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);
diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c
index d916254cc9..7b982c2df8 100644
--- a/src/test/test-sleep.c
+++ b/src/test/test-sleep.c
@@ -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));
}