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");
51
log_full(errno == ENOENT ? LOG_DEBUG: LOG_WARNING,
52
"Failed to open configuration file " PKGSYSCONFDIR "/sleep.conf: %m");
54
r = config_parse(NULL, PKGSYSCONFDIR "/sleep.conf", f, "Sleep\0",
55
config_item_table_lookup, (void*) items, false, false, NULL);
57
log_warning("Failed to parse configuration file: %s", strerror(-r));
60
if (streq(verb, "suspend")) {
61
/* empty by default */
62
*modes = suspend_mode;
65
*states = suspend_state;
67
*states = strv_split_nulstr("mem\0standby\0freeze\0");
69
suspend_mode = suspend_state = NULL;
70
} else if (streq(verb, "hibernate")) {
72
*modes = hibernate_mode;
74
*modes = strv_split_nulstr("platform\0shutdown\0");
77
*states = hibernate_state;
79
*states = strv_split_nulstr("disk\0");
81
hibernate_mode = hibernate_state = NULL;
82
} else if (streq(verb, "hybrid-sleep")) {
86
*modes = strv_split_nulstr("suspend\0platform\0shutdown\0");
89
*states = hybrid_state;
91
*states = strv_split_nulstr("disk\0");
93
hybrid_mode = hybrid_state = NULL;
95
assert_not_reached("what verb");
97
if (!modes || !states) {
106
int can_sleep_state(char **types) {
107
char *w, *state, **type;
109
_cleanup_free_ char *p = NULL;
111
if (strv_isempty(types))
114
/* If /sys is read-only we cannot sleep */
115
if (access("/sys/power/state", W_OK) < 0)
118
r = read_one_line_file("/sys/power/state", &p);
122
STRV_FOREACH(type, types) {
126
FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state)
127
if (l == k && memcmp(w, *type, l) == 0)
134
int can_sleep_disk(char **types) {
135
char *w, *state, **type;
137
_cleanup_free_ char *p = NULL;
139
if (strv_isempty(types))
142
/* If /sys is read-only we cannot sleep */
143
if (access("/sys/power/disk", W_OK) < 0)
146
r = read_one_line_file("/sys/power/disk", &p);
150
STRV_FOREACH(type, types) {
154
FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
155
if (l == k && memcmp(w, *type, l) == 0)
158
if (l == k + 2 && w[0] == '[' && memcmp(w + 1, *type, l - 2) == 0 && w[l-1] == ']')
166
int can_sleep(const char *verb) {
167
_cleanup_strv_free_ char **modes = NULL, **states = NULL;
170
assert(streq(verb, "suspend") ||
171
streq(verb, "hibernate") ||
172
streq(verb, "hybrid-sleep"));
174
r = parse_sleep_config(verb, &modes, &states);
178
return can_sleep_state(states) && can_sleep_disk(modes);