Permalink
Browse files

shared/sleep-config: forbid hibernation if resume= is not configured

(cherry picked from commit 5fdf2d5)
  • Loading branch information...
keszybz committed Sep 26, 2018
1 parent 304dd73 commit 6789dca0a26df0c44ff8020f0a4206bf21e52a7a
Showing with 96 additions and 6 deletions.
  1. +4 −3 src/login/logind-dbus.c
  2. +92 −3 src/shared/sleep-config.c
@@ -1770,8 +1770,9 @@ static int method_do_shutdown_or_sleep(
if (sleep_verb) {
r = can_sleep(sleep_verb);
if (r == -ENOSPC)
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
"Not enough swap space for hibernation");
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Not enough swap space for hibernation");
if (r == -EADV)
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Resume not configured, can't hibernate");
if (r == 0)
return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
"Sleep verb \"%s\" not supported", sleep_verb);
@@ -2199,7 +2200,7 @@ static int method_can_shutdown_or_sleep(

if (sleep_verb) {
r = can_sleep(sleep_verb);
if (IN_SET(r, 0, -ENOSPC))
if (IN_SET(r, 0, -ENOSPC, -EADV))
return sd_bus_reply_method_return(message, "s", "na");
if (r < 0)
return r;
@@ -13,6 +13,7 @@
#include <unistd.h>

#include "alloc-util.h"
#include "bootspec.h"
#include "conf-parser.h"
#include "def.h"
#include "env-util.h"
@@ -22,6 +23,7 @@
#include "macro.h"
#include "parse-util.h"
#include "path-util.h"
#include "proc-cmdline.h"
#include "sleep-config.h"
#include "string-util.h"
#include "strv.h"
@@ -260,12 +262,94 @@ static bool enough_swap_for_hibernation(void) {
}

r = act <= (size - used) * HIBERNATION_SWAP_THRESHOLD;
log_debug("Hibernation is %spossible, Active(anon)=%llu kB, size=%zu kB, used=%zu kB, threshold=%.2g%%",
r ? "" : "im", act, size, used, 100*HIBERNATION_SWAP_THRESHOLD);
log_debug("%s swap for hibernation, Active(anon)=%llu kB, size=%zu kB, used=%zu kB, threshold=%.2g%%",
r ? "Enough" : "Not enough", act, size, used, 100*HIBERNATION_SWAP_THRESHOLD);

return r;
}

static int check_resume_keys(const char *key, const char *value, void *data) {
assert_se(key);
assert_se(data);

int *resume = data;

if (*resume == 0)
/* Exit if we already know we can't resume. */
return 0;

if (streq(key, "noresume")) {
log_debug("Found \"noresume\" on the kernel command line, hibernation is disabled.");
*resume = 0;

} else if (streq(key, "resume")) {
log_debug("Found resume= option on the kernel command line, hibernation is possible.");
*resume = 1;
}

return 0;
}

static int resume_configured_in_options(const char *options) {
int resume = -1, r;

/* We don't use PROC_CMDLINE_STRIP_RD_PREFIX here, so rd.resume is *not* supported. */
r = proc_cmdline_parse_given(options, check_resume_keys, &resume, 0);
if (r < 0)
return r;

if (resume < 0)
log_debug("Couldn't find resume= option, hibernation is disabled.");
return resume > 0;
}

static int resume_configured(void) {
_cleanup_(boot_config_free) BootConfig config = {};
const BootEntry *e;
int r;

/* Check whether a valid resume= option is present. If possible, we query the boot options
* for the default kernel. If the system is not using sd-boot, fall back to checking the
* current kernel command line. This is not perfect, but should suffice for most cases. */

r = find_default_boot_entry(NULL, NULL, &config, &e);
if (r == -ENOKEY)
log_debug_errno(r, "Cannot find the ESP partition mount point, falling back to other checks.");
else if (r < 0)
return log_debug_errno(r, "Cannot read boot configuration from ESP, assuming hibernation is not possible.");
else {
_cleanup_free_ char *options = NULL;

options = strv_join(e->options, " ");
if (!options)
return log_oom();

r = resume_configured_in_options(options);
if (r < 0)
return log_error_errno(r, "Failed to parse kernel options in \"%s\": %m",
strnull(e->path));
return r;
}

/* If we can't figure out the default boot entry, let's fall back to current kernel cmdline */
_cleanup_free_ char *line = NULL;
r = proc_cmdline(&line);
if (IN_SET(r, -EPERM, -EACCES, -ENOENT))
log_debug_errno(r, "Cannot access /proc/cmdline: %m");
else if (r < 0)
return log_error_errno(r, "Failed to query /proc/cmdline: %m");
else {
r = resume_configured_in_options(line);
if (r < 0)
return log_error_errno(r, "Failed to parse kernel proc cmdline: %m");

return r;
}

log_debug("Couldn't detect any resume mechanism, hibernation is disabled.");
return false;
}

int read_fiemap(int fd, struct fiemap **ret) {
_cleanup_free_ struct fiemap *fiemap = NULL, *result_fiemap = NULL;
struct stat statinfo;
@@ -363,7 +447,7 @@ static bool can_s2h(void) {

FOREACH_STRING(p, "suspend", "hibernate") {
r = can_sleep(p);
if (IN_SET(r, 0, -ENOSPC)) {
if (IN_SET(r, 0, -ENOSPC, -EADV)) {
log_debug("Unable to %s system.", p);
return false;
}
@@ -396,5 +480,10 @@ int can_sleep(const char *verb) {
if (!enough_swap_for_hibernation())
return -ENOSPC;

r = resume_configured();
if (r <= 0)
/* We squash all errors (e.g. EPERM) into a single value for reporting. */
return -EADV;

return true;
}

0 comments on commit 6789dca

Please sign in to comment.