]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared/sleep-config: add switches to kill specific sleep modes
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 26 Sep 2018 09:17:36 +0000 (11:17 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 8 Oct 2018 16:21:00 +0000 (18:21 +0200)
/etc/systemd/sleep.conf gains four new switches:
AllowSuspend=, AllowHibernation=, AllowSuspendThenHibernate=, AllowHybridSleep=.

Disabling specific modes was already possible by masking suspend.target,
hibernate.target, suspend-then-hibernate.target, or hybrid-sleep.target.
But this is not convenient for distributions, which want to set some defaults
based on what they want to support. Having those available as configuration
makes it easy to put a config file in /usr/lib/systemd/sleep.conf.d/ that
overrides the defaults and gives instructions how to undo that override.

TODO
man/systemd-sleep.conf.xml
src/shared/sleep-config.c
src/shared/sleep-config.h
src/sleep/sleep.c
src/test/test-sleep.c

diff --git a/TODO b/TODO
index 59ea95746c3bf67c9495f94afbb7fedaa162c55b..e1f3dfb7cc968817681e72d3cee7662fd7b038da 100644 (file)
--- a/TODO
+++ b/TODO
@@ -87,9 +87,8 @@ Features:
   1. add resume_offset support to the resume code (i.e. support swap files
      properly)
   2. check if swap is on weird storage and refuse if so
-  3. add env-var based option to disable hibernation
-  4. figure out what to do with swap-on-luks
-  5. add autodetection of hibernation images
+  3. figure out what to do with swap-on-luks
+  4. add autodetection of hibernation images
 
 * portables: introduce a new unit file directory /etc/systemd/system.attached/
   or so, where we attach portable services to
index 10bbc8c76a0d43a36540ded1c255b57a83820d14..96e6d5e452369e95edc3190a5ac790a34e651928 100644 (file)
     <filename>sleep.conf.d</filename> file:</para>
 
     <variablelist class='systemd-directives'>
+      <varlistentry>
+        <term><varname>AllowSuspend=</varname></term>
+        <term><varname>AllowHibernation=</varname></term>
+        <term><varname>AllowSuspendThenHibernate=</varname></term>
+        <term><varname>AllowHybridSleep=</varname></term>
+
+        <listitem><para>By default any power-saving mode is advertised if possible (i.e.
+        the kernel supports that mode, the necessary resources are available). Those
+        switches can be used to disable specific modes.</para>
+
+        <para>If <varname>AllowHibernation=no</varname> or <varname>AllowSuspend=no</varname> is
+        used, this implies <varname>AllowSuspendThenHibernate=no</varname> and
+        <varname>AllowHybridSleep=no</varname>, since those methods use both suspend and hibernation
+        internally. <varname>AllowSuspendThenHibernate=yes</varname> and
+        <varname>AllowHybridSleep=yes</varname> can be used to override and enable those specific
+        modes.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>SuspendMode=</varname></term>
         <term><varname>HibernateMode=</varname></term>
index fba6851d28d96cc7bc6aa73b0dcefa1f237bd328..67783991887de1eab32e36f50728cd4bcdbaeb24 100644 (file)
 #include "string-util.h"
 #include "strv.h"
 
-int parse_sleep_config(const char *verb, char ***_modes, char ***_states, usec_t *_delay) {
-
+int parse_sleep_config(const char *verb, bool *ret_allow, char ***ret_modes, char ***ret_states, usec_t *ret_delay) {
+        int allow_suspend = -1, allow_hibernate = -1,
+            allow_s2h = -1, allow_hybrid_sleep = -1;
+        bool allow;
         _cleanup_strv_free_ char
                 **suspend_mode = NULL, **suspend_state = NULL,
                 **hibernate_mode = NULL, **hibernate_state = NULL,
@@ -41,13 +43,19 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states, usec_t
         usec_t delay = 180 * USEC_PER_MINUTE;
 
         const ConfigTableItem items[] = {
-                { "Sleep",   "SuspendMode",      config_parse_strv,  0, &suspend_mode  },
-                { "Sleep",   "SuspendState",     config_parse_strv,  0, &suspend_state },
-                { "Sleep",   "HibernateMode",    config_parse_strv,  0, &hibernate_mode  },
-                { "Sleep",   "HibernateState",   config_parse_strv,  0, &hibernate_state },
-                { "Sleep",   "HybridSleepMode",  config_parse_strv,  0, &hybrid_mode  },
-                { "Sleep",   "HybridSleepState", config_parse_strv,  0, &hybrid_state },
-                { "Sleep",   "HibernateDelaySec", config_parse_sec,  0, &delay},
+                { "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, &suspend_mode  },
+                { "Sleep", "SuspendState",              config_parse_strv, 0, &suspend_state },
+                { "Sleep", "HibernateMode",             config_parse_strv, 0, &hibernate_mode  },
+                { "Sleep", "HibernateState",            config_parse_strv, 0, &hibernate_state },
+                { "Sleep", "HybridSleepMode",           config_parse_strv, 0, &hybrid_mode  },
+                { "Sleep", "HybridSleepState",          config_parse_strv, 0, &hybrid_state },
+
+                { "Sleep", "HibernateDelaySec",         config_parse_sec,  0, &delay},
                 {}
         };
 
@@ -57,6 +65,8 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states, usec_t
                                         CONFIG_PARSE_WARN, NULL);
 
         if (streq(verb, "suspend")) {
+                allow = allow_suspend != 0;
+
                 /* empty by default */
                 modes = TAKE_PTR(suspend_mode);
 
@@ -66,6 +76,8 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states, usec_t
                         states = strv_new("mem", "standby", "freeze", NULL);
 
         } else if (streq(verb, "hibernate")) {
+                allow = allow_hibernate != 0;
+
                 if (hibernate_mode)
                         modes = TAKE_PTR(hibernate_mode);
                 else
@@ -77,6 +89,9 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states, usec_t
                         states = strv_new("disk", NULL);
 
         } else if (streq(verb, "hybrid-sleep")) {
+                allow = allow_hybrid_sleep > 0 ||
+                        (allow_suspend != 0 && allow_hibernate != 0);
+
                 if (hybrid_mode)
                         modes = TAKE_PTR(hybrid_mode);
                 else
@@ -87,21 +102,26 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states, usec_t
                 else
                         states = strv_new("disk", NULL);
 
-        } else if (streq(verb, "suspend-then-hibernate"))
+        } else if (streq(verb, "suspend-then-hibernate")) {
+                allow = allow_s2h > 0 ||
+                        (allow_suspend != 0 && allow_hibernate != 0);
+
                 modes = states = NULL;
-        else
+        else
                 assert_not_reached("what verb");
 
         if ((!modes && STR_IN_SET(verb, "hibernate", "hybrid-sleep")) ||
             (!states && !streq(verb, "suspend-then-hibernate")))
                 return log_oom();
 
-        if (_modes)
-                *_modes = TAKE_PTR(modes);
-        if (_states)
-                *_states = TAKE_PTR(states);
-        if (_delay)
-                *_delay = delay;
+        if (ret_allow)
+                *ret_allow = allow;
+        if (ret_modes)
+                *ret_modes = TAKE_PTR(modes);
+        if (ret_states)
+                *ret_states = TAKE_PTR(states);
+        if (ret_delay)
+                *ret_delay = delay;
 
         return 0;
 }
@@ -506,6 +526,8 @@ int read_fiemap(int fd, struct fiemap **ret) {
         return 0;
 }
 
+static int can_sleep_internal(const char *verb, bool check_allowed);
+
 static bool can_s2h(void) {
         const char *p;
         int r;
@@ -518,7 +540,7 @@ static bool can_s2h(void) {
         }
 
         FOREACH_STRING(p, "suspend", "hibernate") {
-                r = can_sleep(p);
+                r = can_sleep_internal(p, false);
                 if (IN_SET(r, 0, -ENOSPC, -ENOMEDIUM, -EADV)) {
                         log_debug("Unable to %s system.", p);
                         return false;
@@ -530,19 +552,25 @@ static bool can_s2h(void) {
         return true;
 }
 
-int can_sleep(const char *verb) {
+static int can_sleep_internal(const char *verb, bool check_allowed) {
+        bool allow;
         _cleanup_strv_free_ char **modes = NULL, **states = NULL;
         int r;
 
         assert(STR_IN_SET(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate"));
 
-        if (streq(verb, "suspend-then-hibernate"))
-                return can_s2h();
-
-        r = parse_sleep_config(verb, &modes, &states, NULL);
+        r = parse_sleep_config(verb, &allow, &modes, &states, NULL);
         if (r < 0)
                 return false;
 
+        if (check_allowed && !allow) {
+                log_debug("Sleep mode \"%s\" is disabled by configuration.", verb);
+                return false;
+        }
+
+        if (streq(verb, "suspend-then-hibernate"))
+                return can_s2h();
+
         if (!can_sleep_state(states) || !can_sleep_disk(modes))
                 return false;
 
@@ -564,3 +592,7 @@ int can_sleep(const char *verb) {
 
         return true;
 }
+
+int can_sleep(const char *verb) {
+        return can_sleep_internal(verb, true);
+}
index 6bf035969a6c578cea6c41d039c2eeb15701d1c7..c584f44d39dbc57d23e548d995c1f31ae276e5ae 100644 (file)
@@ -5,7 +5,7 @@
 #include "time-util.h"
 
 int read_fiemap(int fd, struct fiemap **ret);
-int parse_sleep_config(const char *verb, char ***modes, char ***states, usec_t *delay);
+int parse_sleep_config(const char *verb, bool *ret_allow, char ***ret_modes, char ***ret_states, usec_t *ret_delay);
 int find_hibernate_location(char **device, char **type, size_t *size, size_t *used);
 
 int can_sleep(const char *verb);
index 042a44656fe1ff2462c177a73057ae7ab36638c2..0085cb0196fe8698bbd52c68f0b3868cb6cb933e 100644 (file)
@@ -136,7 +136,6 @@ static int write_state(FILE **f, char **states) {
 }
 
 static int execute(char **modes, char **states) {
-
         char *arguments[] = {
                 NULL,
                 (char*) "pre",
@@ -221,13 +220,11 @@ static int execute_s2h(usec_t hibernate_delay_sec) {
         char time_str[DECIMAL_STR_MAX(uint64_t)];
         int r;
 
-        r = parse_sleep_config("suspend", &suspend_modes, &suspend_states,
-                               NULL);
+        r = parse_sleep_config("suspend", NULL, &suspend_modes, &suspend_states, NULL);
         if (r < 0)
                 return r;
 
-        r = parse_sleep_config("hibernate", &hibernate_modes,
-                               &hibernate_states, NULL);
+        r = parse_sleep_config("hibernate", NULL, &hibernate_modes, &hibernate_states, NULL);
         if (r < 0)
                 return r;
 
@@ -340,6 +337,7 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 int main(int argc, char *argv[]) {
+        bool allow;
         _cleanup_strv_free_ char **modes = NULL, **states = NULL;
         usec_t delay = 0;
         int r;
@@ -352,10 +350,15 @@ int main(int argc, char *argv[]) {
         if (r <= 0)
                 goto finish;
 
-        r = parse_sleep_config(arg_verb, &modes, &states, &delay);
+        r = parse_sleep_config(arg_verb, &allow, &modes, &states, &delay);
         if (r < 0)
                 goto finish;
 
+        if (!allow) {
+                log_error("Sleep mode \"%s\" is disabled by configuration, refusing.", arg_verb);
+                return EXIT_FAILURE;
+        }
+
         if (streq(arg_verb, "suspend-then-hibernate"))
                 r = execute_s2h(delay);
         else
index 2d614a913c1df689ee21a3d1defeec1e5fa26860..442541a298d1639869de4b627b5e2a048f200a44 100644 (file)
@@ -17,7 +17,7 @@ static void test_parse_sleep_config(void) {
         log_info("/* %s */", __func__);
 
         FOREACH_STRING(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate")
-                assert_se(parse_sleep_config(verb, NULL, NULL, NULL) == 0);
+                assert_se(parse_sleep_config(verb, NULL, NULL, NULL, NULL) == 0);
 }
 
 static int test_fiemap(const char *path) {