From 313f86d98c7232354d1d877f94f263dfcbcb7dd4 Mon Sep 17 00:00:00 2001 From: James Hogarth Date: Tue, 17 May 2016 11:33:33 +0100 Subject: [PATCH] check for valid resume= in order to allow a hibernate --- src/shared/sleep-config.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index a0aef66bc8..c516a6dc8a 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -36,6 +36,10 @@ #include "sleep-config.h" #include "string-util.h" #include "strv.h" +#include "proc-cmdline.h" +#include "fstab-util.h" + +static char *arg_resume_dev = NULL; #define USE(x, y) do{ (x) = (y); (y) = NULL; } while(0) @@ -255,6 +259,51 @@ static bool enough_memory_for_hibernation(void) { return r; } +static int parse_proc_cmdline_item(const char *key, const char *value) { + + assert(key); + + if (streq(key, "resume") && value) { + free(arg_resume_dev); + arg_resume_dev = fstab_node_to_udev_node(value); + if (!arg_resume_dev) + return log_oom(); + } + + return 0; + +} + +static bool resume_passed_to_kernel(void) { + int r = 0; + struct stat rd; + + r = parse_proc_cmdline(parse_proc_cmdline_item); + if (r < 0) { + log_warning("Failed to parse kernel command line, disabling hibernation."); + return false; + } + + if (arg_resume_dev == NULL) { + log_warning("No resume= argument specified in the kernel command line, disabling hibernation."); + return false; + } + + if (stat(arg_resume_dev, &rd) < 0) { + log_warning("Could not stat device %s specified in resume=, disabling hibernation.", + arg_resume_dev); + return false; + } + + if (!S_ISBLK(rd.st_mode)) { + log_warning("Device %s specified in resume= is not a block device, disabling hibernation.", + arg_resume_dev); + return false; + } + + return true; +} + int can_sleep(const char *verb) { _cleanup_strv_free_ char **modes = NULL, **states = NULL; int r; @@ -270,5 +319,8 @@ int can_sleep(const char *verb) { if (!can_sleep_state(states) || !can_sleep_disk(modes)) return false; - return streq(verb, "suspend") || enough_memory_for_hibernation(); + if (streq(verb, "suspend")) + return true; + + return enough_memory_for_hibernation() && resume_passed_to_kernel(); }