summaryrefslogtreecommitdiffstats
path: root/src/shared/sleep-config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/sleep-config.c')
-rw-r--r--src/shared/sleep-config.c78
1 files changed, 55 insertions, 23 deletions
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 7282111..3d4d331 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -54,6 +54,8 @@ SleepConfig* sleep_config_free(SleepConfig *sc) {
strv_free(sc->modes[i]);
}
+ strv_free(sc->mem_modes);
+
return mfree(sc);
}
@@ -69,8 +71,8 @@ static int config_parse_sleep_mode(
void *data,
void *userdata) {
- _cleanup_strv_free_ char **modes = NULL;
char ***sv = ASSERT_PTR(data);
+ _cleanup_strv_free_ char **modes = NULL;
int r;
assert(filename);
@@ -87,7 +89,7 @@ static int config_parse_sleep_mode(
return log_oom();
}
- return free_and_replace(*sv, modes);
+ return strv_free_and_replace(*sv, modes);
}
static void sleep_config_validate_state_and_mode(SleepConfig *sc) {
@@ -140,14 +142,19 @@ int parse_sleep_config(SleepConfig **ret) {
{ "Sleep", "HybridSleepState", config_parse_warn_compat, DISABLED_LEGACY, NULL },
{ "Sleep", "HybridSleepMode", config_parse_warn_compat, DISABLED_LEGACY, NULL },
+ { "Sleep", "MemorySleepMode", config_parse_sleep_mode, 0, &sc->mem_modes },
+
{ "Sleep", "HibernateDelaySec", config_parse_sec, 0, &sc->hibernate_delay_usec },
{ "Sleep", "SuspendEstimationSec", config_parse_sec, 0, &sc->suspend_estimation_usec },
{}
};
- (void) config_parse_config_file("sleep.conf", "Sleep\0",
- config_item_table_lookup, items,
- CONFIG_PARSE_WARN, NULL);
+ (void) config_parse_standard_file_with_dropins(
+ "systemd/sleep.conf",
+ "Sleep\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN,
+ /* userdata= */ NULL);
/* use default values unless set */
sc->allow[SLEEP_SUSPEND] = allow_suspend != 0;
@@ -180,7 +187,7 @@ int parse_sleep_config(SleepConfig **ret) {
return 0;
}
-int sleep_state_supported(char **states) {
+int sleep_state_supported(char * const *states) {
_cleanup_free_ char *supported_sysfs = NULL;
const char *found;
int r;
@@ -210,22 +217,24 @@ int sleep_state_supported(char **states) {
return false;
}
-int sleep_mode_supported(char **modes) {
+int sleep_mode_supported(const char *path, char * const *modes) {
_cleanup_free_ char *supported_sysfs = NULL;
int r;
+ assert(path);
+
/* Unlike state, kernel has its own default choice if not configured */
if (strv_isempty(modes)) {
- log_debug("No sleep mode configured, using kernel default.");
+ log_debug("No sleep mode configured, using kernel default for %s.", path);
return true;
}
- if (access("/sys/power/disk", W_OK) < 0)
- return log_debug_errno(errno, "/sys/power/disk is not writable: %m");
+ if (access(path, W_OK) < 0)
+ return log_debug_errno(errno, "%s is not writable: %m", path);
- r = read_one_line_file("/sys/power/disk", &supported_sysfs);
+ r = read_one_line_file(path, &supported_sysfs);
if (r < 0)
- return log_debug_errno(r, "Failed to read /sys/power/disk: %m");
+ return log_debug_errno(r, "Failed to read %s: %m", path);
for (const char *p = supported_sysfs;;) {
_cleanup_free_ char *word = NULL;
@@ -234,7 +243,7 @@ int sleep_mode_supported(char **modes) {
r = extract_first_word(&p, &word, NULL, 0);
if (r < 0)
- return log_debug_errno(r, "Failed to parse /sys/power/disk: %m");
+ return log_debug_errno(r, "Failed to parse %s: %m", path);
if (r == 0)
break;
@@ -247,14 +256,15 @@ int sleep_mode_supported(char **modes) {
}
if (strv_contains(modes, mode)) {
- log_debug("Disk sleep mode '%s' is supported by kernel.", mode);
+ log_debug("Sleep mode '%s' is supported by kernel (%s).", mode, path);
return true;
}
}
if (DEBUG_LOGGING) {
_cleanup_free_ char *joined = strv_join(modes, " ");
- log_debug("None of the configured hibernation power modes are supported by kernel: %s", strnull(joined));
+ log_debug("None of the configured modes are supported by kernel (%s): %s",
+ path, strnull(joined));
}
return false;
}
@@ -284,7 +294,7 @@ static int s2h_supported(const SleepConfig *sleep_config, SleepSupport *ret_supp
return false;
}
- FOREACH_ARRAY(i, operations, ELEMENTSOF(operations)) {
+ FOREACH_ELEMENT(i, operations) {
r = sleep_supported_internal(sleep_config, *i, /* check_allowed = */ false, &support);
if (r < 0)
return r;
@@ -338,8 +348,18 @@ static int sleep_supported_internal(
return false;
}
- if (sleep_operation_is_hibernation(operation)) {
- r = sleep_mode_supported(sleep_config->modes[operation]);
+ if (SLEEP_NEEDS_MEM_SLEEP(sleep_config, operation)) {
+ r = sleep_mode_supported("/sys/power/mem_sleep", sleep_config->mem_modes);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ *ret_support = SLEEP_STATE_OR_MODE_NOT_SUPPORTED;
+ return false;
+ }
+ }
+
+ if (SLEEP_OPERATION_IS_HIBERNATION(operation)) {
+ r = sleep_mode_supported("/sys/power/disk", sleep_config->modes[operation]);
if (r < 0)
return r;
if (r == 0) {
@@ -348,16 +368,28 @@ static int sleep_supported_internal(
}
r = hibernation_is_safe();
- if (r == -ENOTRECOVERABLE) {
+ switch (r) {
+
+ case -ENOTRECOVERABLE:
*ret_support = SLEEP_RESUME_NOT_SUPPORTED;
return false;
- }
- if (r == -ENOSPC) {
+
+ case -ESTALE:
+ *ret_support = SLEEP_RESUME_DEVICE_MISSING;
+ return false;
+
+ case -ENOMEDIUM:
+ *ret_support = SLEEP_RESUME_MISCONFIGURED;
+ return false;
+
+ case -ENOSPC:
*ret_support = SLEEP_NOT_ENOUGH_SWAP_SPACE;
return false;
+
+ default:
+ if (r < 0)
+ return r;
}
- if (r < 0)
- return r;
} else
assert(!sleep_config->modes[operation]);