~yuningdodo/systemd/systemd.trusty-proposed.lp1313522

« back to all changes in this revision

Viewing changes to .pc/Advertise-hibernation-only-if-there-s-enough-free-sw.patch/src/shared/sleep-config.c

  • Committer: Yu Ning
  • Date: 2014-05-07 11:42:33 UTC
  • Revision ID: ning.yu@canonical.com-20140507114233-prrbrjvrcrtyrk82
[Martin Pitt]
  * Advertise hibernation only if there's enough free swap. Patches backported
    from current upstream. (LP: #1313522)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 
2
 
 
3
/***
 
4
  This file is part of systemd.
 
5
 
 
6
  Copyright 2013 Zbigniew Jędrzejewski-Szmek
 
7
 
 
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.
 
12
 
 
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.
 
17
 
 
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/>.
 
20
***/
 
21
 
 
22
#include <stdio.h>
 
23
 
 
24
#include "conf-parser.h"
 
25
#include "sleep-config.h"
 
26
#include "fileio.h"
 
27
#include "log.h"
 
28
#include "strv.h"
 
29
#include "util.h"
 
30
 
 
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;
 
36
 
 
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 },
 
44
                {}};
 
45
 
 
46
        int r;
 
47
        FILE _cleanup_fclose_ *f;
 
48
 
 
49
        f = fopen(PKGSYSCONFDIR "/sleep.conf", "re");
 
50
        if (!f)
 
51
                log_full(errno == ENOENT ? LOG_DEBUG: LOG_WARNING,
 
52
                         "Failed to open configuration file " PKGSYSCONFDIR "/sleep.conf: %m");
 
53
        else {
 
54
                r = config_parse(NULL, PKGSYSCONFDIR "/sleep.conf", f, "Sleep\0",
 
55
                                 config_item_table_lookup, (void*) items, false, false, NULL);
 
56
                if (r < 0)
 
57
                        log_warning("Failed to parse configuration file: %s", strerror(-r));
 
58
        }
 
59
 
 
60
        if (streq(verb, "suspend")) {
 
61
                /* empty by default */
 
62
                *modes = suspend_mode;
 
63
 
 
64
                if (suspend_state)
 
65
                        *states = suspend_state;
 
66
                else
 
67
                        *states = strv_split_nulstr("mem\0standby\0freeze\0");
 
68
 
 
69
                suspend_mode = suspend_state = NULL;
 
70
        } else if (streq(verb, "hibernate")) {
 
71
                if (hibernate_mode)
 
72
                        *modes = hibernate_mode;
 
73
                else
 
74
                        *modes = strv_split_nulstr("platform\0shutdown\0");
 
75
 
 
76
                if (hibernate_state)
 
77
                        *states = hibernate_state;
 
78
                else
 
79
                        *states = strv_split_nulstr("disk\0");
 
80
 
 
81
                hibernate_mode = hibernate_state = NULL;
 
82
        } else if (streq(verb, "hybrid-sleep")) {
 
83
                if (hybrid_mode)
 
84
                        *modes = hybrid_mode;
 
85
                else
 
86
                        *modes = strv_split_nulstr("suspend\0platform\0shutdown\0");
 
87
 
 
88
                if (hybrid_state)
 
89
                        *states = hybrid_state;
 
90
                else
 
91
                        *states = strv_split_nulstr("disk\0");
 
92
 
 
93
                hybrid_mode = hybrid_state = NULL;
 
94
        } else
 
95
                assert_not_reached("what verb");
 
96
 
 
97
        if (!modes || !states) {
 
98
                strv_free(*modes);
 
99
                strv_free(*states);
 
100
                return log_oom();
 
101
        }
 
102
 
 
103
        return 0;
 
104
}
 
105
 
 
106
int can_sleep_state(char **types) {
 
107
        char *w, *state, **type;
 
108
        int r;
 
109
        _cleanup_free_ char *p = NULL;
 
110
 
 
111
        if (strv_isempty(types))
 
112
                return true;
 
113
 
 
114
        /* If /sys is read-only we cannot sleep */
 
115
        if (access("/sys/power/state", W_OK) < 0)
 
116
                return false;
 
117
 
 
118
        r = read_one_line_file("/sys/power/state", &p);
 
119
        if (r < 0)
 
120
                return false;
 
121
 
 
122
        STRV_FOREACH(type, types) {
 
123
                size_t l, k;
 
124
 
 
125
                k = strlen(*type);
 
126
                FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state)
 
127
                        if (l == k && memcmp(w, *type, l) == 0)
 
128
                                return true;
 
129
        }
 
130
 
 
131
        return false;
 
132
}
 
133
 
 
134
int can_sleep_disk(char **types) {
 
135
        char *w, *state, **type;
 
136
        int r;
 
137
        _cleanup_free_ char *p = NULL;
 
138
 
 
139
        if (strv_isempty(types))
 
140
                return true;
 
141
 
 
142
        /* If /sys is read-only we cannot sleep */
 
143
        if (access("/sys/power/disk", W_OK) < 0)
 
144
                return false;
 
145
 
 
146
        r = read_one_line_file("/sys/power/disk", &p);
 
147
        if (r < 0)
 
148
                return false;
 
149
 
 
150
        STRV_FOREACH(type, types) {
 
151
                size_t l, k;
 
152
 
 
153
                k = strlen(*type);
 
154
                FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
 
155
                        if (l == k && memcmp(w, *type, l) == 0)
 
156
                                return true;
 
157
 
 
158
                        if (l == k + 2 && w[0] == '[' && memcmp(w + 1, *type, l - 2) == 0 && w[l-1] == ']')
 
159
                                return true;
 
160
                }
 
161
        }
 
162
 
 
163
        return false;
 
164
}
 
165
 
 
166
int can_sleep(const char *verb) {
 
167
        _cleanup_strv_free_ char **modes = NULL, **states = NULL;
 
168
        int r;
 
169
 
 
170
        assert(streq(verb, "suspend") ||
 
171
               streq(verb, "hibernate") ||
 
172
               streq(verb, "hybrid-sleep"));
 
173
 
 
174
        r = parse_sleep_config(verb, &modes, &states);
 
175
        if (r < 0)
 
176
                return false;
 
177
 
 
178
        return can_sleep_state(states) && can_sleep_disk(modes);
 
179
}