]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/sleep/sleep.c
Merge pull request #1372 from jemk/prefsrc
[thirdparty/systemd.git] / src / sleep / sleep.c
CommitLineData
6edd7d0a
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
19adb8a3 7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
6edd7d0a
LP
8
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21***/
22
6edd7d0a 23#include <errno.h>
19adb8a3 24#include <getopt.h>
3f6fd1ba 25#include <stdio.h>
6edd7d0a 26
aa62a893 27#include "sd-messages.h"
3f6fd1ba
LP
28
29#include "def.h"
a5c32cff 30#include "fileio.h"
3f6fd1ba 31#include "log.h"
19adb8a3 32#include "sleep-config.h"
3f6fd1ba
LP
33#include "strv.h"
34#include "util.h"
19adb8a3
ZJS
35
36static char* arg_verb = NULL;
37
38static int write_mode(char **modes) {
39 int r = 0;
40 char **mode;
41
42 STRV_FOREACH(mode, modes) {
aa62a893
LP
43 int k;
44
4c1fc3e4 45 k = write_string_file("/sys/power/disk", *mode, 0);
19adb8a3
ZJS
46 if (k == 0)
47 return 0;
aa62a893 48
c33b3297
MS
49 log_debug_errno(k, "Failed to write '%s' to /sys/power/disk: %m",
50 *mode);
19adb8a3
ZJS
51 if (r == 0)
52 r = k;
53 }
6edd7d0a 54
19adb8a3 55 if (r < 0)
c33b3297 56 log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");
6edd7d0a 57
19adb8a3
ZJS
58 return r;
59}
6edd7d0a 60
2fd069b1 61static int write_state(FILE **f, char **states) {
19adb8a3
ZJS
62 char **state;
63 int r = 0;
64
65 STRV_FOREACH(state, states) {
66 int k;
67
40beecdb 68 k = write_string_stream(*f, *state, true);
19adb8a3
ZJS
69 if (k == 0)
70 return 0;
c33b3297
MS
71 log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
72 *state);
19adb8a3
ZJS
73 if (r == 0)
74 r = k;
75
2fd069b1
ZJS
76 fclose(*f);
77 *f = fopen("/sys/power/state", "we");
4a62c710
MS
78 if (!*f)
79 return log_error_errno(errno, "Failed to open /sys/power/state: %m");
6edd7d0a
LP
80 }
81
19adb8a3
ZJS
82 return r;
83}
6edd7d0a 84
19adb8a3 85static int execute(char **modes, char **states) {
e2cc6eca
LP
86
87 char *arguments[] = {
88 NULL,
89 (char*) "pre",
90 arg_verb,
91 NULL
92 };
e801700e 93 static const char* const dirs[] = {SYSTEM_SLEEP_PATH, NULL};
e2cc6eca 94
19adb8a3 95 int r;
2fd069b1 96 _cleanup_fclose_ FILE *f = NULL;
6524990f 97
19adb8a3 98 /* This file is opened first, so that if we hit an error,
09692409 99 * we can abort before modifying any state. */
6edd7d0a 100 f = fopen("/sys/power/state", "we");
4a62c710
MS
101 if (!f)
102 return log_error_errno(errno, "Failed to open /sys/power/state: %m");
6edd7d0a 103
19adb8a3
ZJS
104 /* Configure the hibernation mode */
105 r = write_mode(modes);
106 if (r < 0)
107 return r;
108
e801700e 109 execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments);
6edd7d0a 110
19adb8a3 111 log_struct(LOG_INFO,
e2cc6eca
LP
112 LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
113 LOG_MESSAGE("Suspending system..."),
114 "SLEEP=%s", arg_verb,
19adb8a3
ZJS
115 NULL);
116
2fd069b1 117 r = write_state(&f, states);
19adb8a3
ZJS
118 if (r < 0)
119 return r;
120
121 log_struct(LOG_INFO,
e2cc6eca 122 LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
a5ccdb98 123 LOG_MESSAGE("System resumed."),
e2cc6eca 124 "SLEEP=%s", arg_verb,
19adb8a3 125 NULL);
eb267289 126
6edd7d0a 127 arguments[1] = (char*) "post";
e801700e 128 execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments);
6edd7d0a 129
19adb8a3
ZJS
130 return r;
131}
6edd7d0a 132
601185b4 133static void help(void) {
19adb8a3
ZJS
134 printf("%s COMMAND\n\n"
135 "Suspend the system, hibernate the system, or both.\n\n"
136 "Commands:\n"
137 " -h --help Show this help and exit\n"
138 " --version Print version string and exit\n"
139 " suspend Suspend the system\n"
140 " hibernate Hibernate the system\n"
141 " hybrid-sleep Both hibernate and suspend the system\n"
601185b4 142 , program_invocation_short_name);
19adb8a3 143}
6edd7d0a 144
19adb8a3
ZJS
145static int parse_argv(int argc, char *argv[]) {
146 enum {
147 ARG_VERSION = 0x100,
148 };
149
150 static const struct option options[] = {
151 { "help", no_argument, NULL, 'h' },
152 { "version", no_argument, NULL, ARG_VERSION },
eb9da376 153 {}
19adb8a3
ZJS
154 };
155
156 int c;
157
158 assert(argc >= 0);
159 assert(argv);
160
601185b4 161 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
19adb8a3
ZJS
162 switch(c) {
163 case 'h':
601185b4
ZJS
164 help();
165 return 0; /* done */
19adb8a3
ZJS
166
167 case ARG_VERSION:
3f6fd1ba 168 return version();
19adb8a3
ZJS
169
170 case '?':
171 return -EINVAL;
172
173 default:
eb9da376 174 assert_not_reached("Unhandled option");
19adb8a3
ZJS
175 }
176
177 if (argc - optind != 1) {
178 log_error("Usage: %s COMMAND",
179 program_invocation_short_name);
180 return -EINVAL;
181 }
182
183 arg_verb = argv[optind];
6edd7d0a 184
19adb8a3
ZJS
185 if (!streq(arg_verb, "suspend") &&
186 !streq(arg_verb, "hibernate") &&
187 !streq(arg_verb, "hybrid-sleep")) {
188 log_error("Unknown command '%s'.", arg_verb);
189 return -EINVAL;
190 }
191
192 return 1 /* work to do */;
193}
194
195int main(int argc, char *argv[]) {
196 _cleanup_strv_free_ char **modes = NULL, **states = NULL;
197 int r;
198
199 log_set_target(LOG_TARGET_AUTO);
200 log_parse_environment();
201 log_open();
202
203 r = parse_argv(argc, argv);
204 if (r <= 0)
205 goto finish;
206
207 r = parse_sleep_config(arg_verb, &modes, &states);
208 if (r < 0)
209 goto finish;
210
211 r = execute(modes, states);
212
213finish:
214 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6edd7d0a 215}