chiark / gitweb /
Prep v231: Move can_sleep() back to src/shared/sleep-config.c
authorSven Eden <yamakuzure@gmx.net>
Wed, 14 Jun 2017 15:37:58 +0000 (17:37 +0200)
committerSven Eden <yamakuzure@gmx.net>
Fri, 16 Jun 2017 08:13:01 +0000 (10:13 +0200)
src/login/logind-dbus.c
src/shared/sleep-config.c [new file with mode: 0644]
src/shared/sleep-config.h [new file with mode: 0644]

index 3ad24b1fee20a31c0f8e44a62da9cda53eae991a..c2628ad7cb69f88c250de3a5a4a5d71454c0bdca 100644 (file)
@@ -41,7 +41,7 @@
 #include "path-util.h"
 #include "process-util.h"
 #include "selinux-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "selinux-util.h"
-//#include "sleep-config.h"
+#include "sleep-config.h"
 //#include "special.h"
 #include "strv.h"
 #include "terminal-util.h"
 //#include "special.h"
 #include "strv.h"
 #include "terminal-util.h"
@@ -50,7 +50,7 @@
 #include "user-util.h"
 #include "utmp-wtmp.h"
 
 #include "user-util.h"
 #include "utmp-wtmp.h"
 
-/// Includes needed by elogind:
+/// Additional includes needed by elogind
 #include "update-utmp.h"
 
 int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
 #include "update-utmp.h"
 
 int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
@@ -918,7 +918,9 @@ static int method_release_session(sd_bus_message *message, void *userdata, sd_bu
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
+#if 1 /// elogind must queue this session
         session_add_to_gc_queue(session);
         session_add_to_gc_queue(session);
+#endif // 1
 
         return sd_bus_reply_method_return(message, NULL);
 }
 
         return sd_bus_reply_method_return(message, NULL);
 }
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
new file mode 100644 (file)
index 0000000..7d47e79
--- /dev/null
@@ -0,0 +1,315 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Zbigniew JÄ™drzejewski-Szmek
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+//#include <errno.h>
+//#include <stdbool.h>
+//#include <stddef.h>
+//#include <stdio.h>
+//#include <string.h>
+//#include <syslog.h>
+//#include <unistd.h>
+
+#include "alloc-util.h"
+//#include "conf-parser.h"
+//#include "def.h"
+//#include "env-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+//#include "log.h"
+//#include "macro.h"
+#include "parse-util.h"
+#include "sleep-config.h"
+#include "string-util.h"
+#include "strv.h"
+
+#if 0 /// UNNEEDED by elogind
+#define USE(x, y) do { (x) = (y); (y) = NULL; } while (0)
+
+int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
+
+        _cleanup_strv_free_ char
+                **suspend_mode = NULL, **suspend_state = NULL,
+                **hibernate_mode = NULL, **hibernate_state = NULL,
+                **hybrid_mode = NULL, **hybrid_state = NULL;
+        char **modes, **states;
+
+        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 },
+                {}
+        };
+
+        config_parse_many(PKGSYSCONFDIR "/sleep.conf",
+                          CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
+                          "Sleep\0", config_item_table_lookup, items,
+                          false, NULL);
+
+        if (streq(verb, "suspend")) {
+                /* empty by default */
+                USE(modes, suspend_mode);
+
+                if (suspend_state)
+                        USE(states, suspend_state);
+                else
+                        states = strv_new("mem", "standby", "freeze", NULL);
+
+        } else if (streq(verb, "hibernate")) {
+                if (hibernate_mode)
+                        USE(modes, hibernate_mode);
+                else
+                        modes = strv_new("platform", "shutdown", NULL);
+
+                if (hibernate_state)
+                        USE(states, hibernate_state);
+                else
+                        states = strv_new("disk", NULL);
+
+        } else if (streq(verb, "hybrid-sleep")) {
+                if (hybrid_mode)
+                        USE(modes, hybrid_mode);
+                else
+                        modes = strv_new("suspend", "platform", "shutdown", NULL);
+
+                if (hybrid_state)
+                        USE(states, hybrid_state);
+                else
+                        states = strv_new("disk", NULL);
+
+        } else
+                assert_not_reached("what verb");
+
+        if ((!modes && !streq(verb, "suspend")) || !states) {
+                strv_free(modes);
+                strv_free(states);
+                return log_oom();
+        }
+
+        *_modes = modes;
+        *_states = states;
+        return 0;
+}
+#endif // 0
+
+#if 1 /// Only available in this file for elogind
+static
+#endif // 0
+int can_sleep_state(char **types) {
+        char **type;
+        int r;
+        _cleanup_free_ char *p = NULL;
+
+        if (strv_isempty(types))
+                return true;
+
+        /* If /sys is read-only we cannot sleep */
+        if (access("/sys/power/state", W_OK) < 0)
+                return false;
+
+        r = read_one_line_file("/sys/power/state", &p);
+        if (r < 0)
+                return false;
+
+        STRV_FOREACH(type, types) {
+                const char *word, *state;
+                size_t l, k;
+
+                k = strlen(*type);
+                FOREACH_WORD_SEPARATOR(word, l, p, WHITESPACE, state)
+                        if (l == k && memcmp(word, *type, l) == 0)
+                                return true;
+        }
+
+        return false;
+}
+
+#if 1 /// Only available in this file for elogind
+static
+#endif // 0
+int can_sleep_disk(char **types) {
+        char **type;
+        int r;
+        _cleanup_free_ char *p = NULL;
+
+        if (strv_isempty(types))
+                return true;
+
+        /* If /sys is read-only we cannot sleep */
+        if (access("/sys/power/disk", W_OK) < 0)
+                return false;
+
+        r = read_one_line_file("/sys/power/disk", &p);
+        if (r < 0)
+                return false;
+
+        STRV_FOREACH(type, types) {
+                const char *word, *state;
+                size_t l, k;
+
+                k = strlen(*type);
+                FOREACH_WORD_SEPARATOR(word, l, p, WHITESPACE, state) {
+                        if (l == k && memcmp(word, *type, l) == 0)
+                                return true;
+
+                        if (l == k + 2 &&
+                            word[0] == '[' &&
+                            memcmp(word + 1, *type, l - 2) == 0 &&
+                            word[l-1] == ']')
+                                return true;
+                }
+        }
+
+        return false;
+}
+
+#define HIBERNATION_SWAP_THRESHOLD 0.98
+
+static int hibernation_partition_size(size_t *size, size_t *used) {
+        _cleanup_fclose_ FILE *f;
+        unsigned i;
+
+        assert(size);
+        assert(used);
+
+        f = fopen("/proc/swaps", "re");
+        if (!f) {
+                log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
+                         "Failed to retrieve open /proc/swaps: %m");
+                assert(errno > 0);
+                return -errno;
+        }
+
+        (void) fscanf(f, "%*s %*s %*s %*s %*s\n");
+
+        for (i = 1;; i++) {
+                _cleanup_free_ char *dev = NULL, *type = NULL;
+                size_t size_field, used_field;
+                int k;
+
+                k = fscanf(f,
+                           "%ms "   /* device/file */
+                           "%ms "   /* type of swap */
+                           "%zu "   /* swap size */
+                           "%zu "   /* used */
+                           "%*i\n", /* priority */
+                           &dev, &type, &size_field, &used_field);
+                if (k != 4) {
+                        if (k == EOF)
+                                break;
+
+                        log_warning("Failed to parse /proc/swaps:%u", i);
+                        continue;
+                }
+
+                if (streq(type, "partition") && endswith(dev, "\\040(deleted)")) {
+                        log_warning("Ignoring deleted swapfile '%s'.", dev);
+                        continue;
+                }
+
+                *size = size_field;
+                *used = used_field;
+                return 0;
+        }
+
+        log_debug("No swap partitions were found.");
+        return -ENOSYS;
+}
+
+static bool enough_memory_for_hibernation(void) {
+        _cleanup_free_ char *active = NULL;
+        unsigned long long act = 0;
+        size_t size = 0, used = 0;
+        int r;
+
+#if 0 /// elogind does not allow any bypass, we are never init!
+        if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0)
+                return true;
+#endif // 0
+
+        r = hibernation_partition_size(&size, &used);
+        if (r < 0)
+                return false;
+
+        r = get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE, &active);
+        if (r < 0) {
+                log_error_errno(r, "Failed to retrieve Active(anon) from /proc/meminfo: %m");
+                return false;
+        }
+
+        r = safe_atollu(active, &act);
+        if (r < 0) {
+                log_error_errno(r, "Failed to parse Active(anon) from /proc/meminfo: %s: %m",
+                                active);
+                return false;
+        }
+
+        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);
+
+        return r;
+}
+
+#if 0 /// elogind has to do, or better, *can* do it differently
+int can_sleep(const char *verb) {
+        _cleanup_strv_free_ char **modes = NULL, **states = NULL;
+        int r;
+
+        assert(streq(verb, "suspend") ||
+               streq(verb, "hibernate") ||
+               streq(verb, "hybrid-sleep"));
+
+        r = parse_sleep_config(verb, &modes, &states);
+        if (r < 0)
+                return false;
+
+        if (!can_sleep_state(states) || !can_sleep_disk(modes))
+                return false;
+
+        return streq(verb, "suspend") || enough_memory_for_hibernation();
+}
+#else
+int can_sleep(Manager *m, const char *verb) {
+
+        assert(streq(verb, "suspend") ||
+               streq(verb, "hibernate") ||
+               streq(verb, "hybrid-sleep"));
+
+        if ( streq(verb, "suspend")
+          && ( !can_sleep_state(m->suspend_state)
+            || !can_sleep_disk(m->suspend_mode) ) )
+                return false;
+
+        if ( streq(verb, "hibernate")
+          && ( !can_sleep_state(m->hibernate_state)
+            || !can_sleep_disk(m->hibernate_mode) ) )
+                return false;
+
+        if ( streq(verb, "hybrid-sleep")
+          && ( !can_sleep_state(m->hybrid_sleep_state)
+            || !can_sleep_disk(m->hybrid_sleep_mode) ) )
+                return false;
+
+
+        return streq(verb, "suspend") || enough_memory_for_hibernation();
+}
+#endif // 0
diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h
new file mode 100644 (file)
index 0000000..238775d
--- /dev/null
@@ -0,0 +1,31 @@
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Zbigniew JÄ™drzejewski-Szmek
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#if 0 /// UNNEEDED by elogind
+int parse_sleep_config(const char *verb, char ***modes, char ***states);
+
+int can_sleep(const char *verb);
+int can_sleep_disk(char **types);
+int can_sleep_state(char **types);
+#else
+#include <logind.h>
+int can_sleep(Manager* m, const char *verb);
+#endif // 0