1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Zbigniew Jędrzejewski-Szmek
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "conf-parser.h"
25 #include "sleep-config.h"
31 int parse_sleep_config(const char *verb, char ***modes, char ***states) {
32 _cleanup_strv_free_ char
33 **suspend_mode = NULL, **suspend_state = NULL,
34 **hibernate_mode = NULL, **hibernate_state = NULL,
35 **hybrid_mode = NULL, **hybrid_state = NULL;
37 const ConfigTableItem items[] = {
38 { "Sleep", "SuspendMode", config_parse_strv, 0, &suspend_mode },
39 { "Sleep", "SuspendState", config_parse_strv, 0, &suspend_state },
40 { "Sleep", "HibernateMode", config_parse_strv, 0, &hibernate_mode },
41 { "Sleep", "HibernateState", config_parse_strv, 0, &hibernate_state },
42 { "Sleep", "HybridSleepMode", config_parse_strv, 0, &hybrid_mode },
43 { "Sleep", "HybridSleepState", config_parse_strv, 0, &hybrid_state },
47 FILE _cleanup_fclose_ *f;
49 f = fopen(PKGSYSCONFDIR "/sleep.conf", "re");
54 log_warning("Failed to open configuration file " PKGSYSCONFDIR "/sleep.conf: %m");
58 r = config_parse(NULL, PKGSYSCONFDIR "/sleep.conf", f, "Sleep\0",
59 config_item_table_lookup, (void*) items, false, false, NULL);
61 log_warning("Failed to parse configuration file: %s", strerror(-r));
63 if (streq(verb, "suspend")) {
64 /* empty by default */
65 *modes = suspend_mode;
68 *states = suspend_state;
70 *states = strv_split_nulstr("mem\0standby\0freeze\0");
72 suspend_mode = suspend_state = NULL;
73 } else if (streq(verb, "hibernate")) {
75 *modes = hibernate_mode;
77 *modes = strv_split_nulstr("platform\0shutdown\0");
80 *states = hibernate_state;
82 *states = strv_split_nulstr("disk\0");
84 hibernate_mode = hibernate_state = NULL;
85 } else if (streq(verb, "hybrid-sleep")) {
89 *modes = strv_split_nulstr("suspend\0platform\0shutdown\0");
92 *states = hybrid_state;
94 *states = strv_split_nulstr("disk\0");
96 hybrid_mode = hybrid_state = NULL;
98 assert_not_reached("what verb");
100 if (!modes || !states) {
109 int can_sleep_state(char **types) {
110 char *w, *state, **type;
112 _cleanup_free_ char *p = NULL;
114 if (strv_isempty(types))
117 /* If /sys is read-only we cannot sleep */
118 if (access("/sys/power/state", W_OK) < 0)
121 r = read_one_line_file("/sys/power/state", &p);
125 STRV_FOREACH(type, types) {
129 FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state)
130 if (l == k && memcmp(w, *type, l) == 0)
137 int can_sleep_disk(char **types) {
138 char *w, *state, **type;
140 _cleanup_free_ char *p = NULL;
142 if (strv_isempty(types))
145 /* If /sys is read-only we cannot sleep */
146 if (access("/sys/power/disk", W_OK) < 0)
149 r = read_one_line_file("/sys/power/disk", &p);
153 STRV_FOREACH(type, types) {
157 FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
158 if (l == k && memcmp(w, *type, l) == 0)
161 if (l == k + 2 && w[0] == '[' && memcmp(w + 1, *type, l - 2) == 0 && w[l-1] == ']')
169 int can_sleep(const char *verb) {
170 _cleanup_strv_free_ char **modes = NULL, **states = NULL;
173 assert(streq(verb, "suspend") ||
174 streq(verb, "hibernate") ||
175 streq(verb, "hybrid-sleep"));
177 r = parse_sleep_config(verb, &modes, &states);
181 return can_sleep_state(states) && can_sleep_disk(modes);