]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/sleep/sleep.c
path-util: paths_check_timestamp() opimizations
[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
23#include <stdio.h>
24#include <errno.h>
25#include <string.h>
19adb8a3 26#include <getopt.h>
6edd7d0a 27
877d54e9
LP
28#include "systemd/sd-id128.h"
29#include "systemd/sd-messages.h"
19adb8a3
ZJS
30#include "log.h"
31#include "util.h"
32#include "strv.h"
a5c32cff 33#include "fileio.h"
19adb8a3
ZJS
34#include "build.h"
35#include "sleep-config.h"
36
37static char* arg_verb = NULL;
38
39static int write_mode(char **modes) {
40 int r = 0;
41 char **mode;
42
43 STRV_FOREACH(mode, modes) {
44 int k = write_string_file("/sys/power/disk", *mode);
45 if (k == 0)
46 return 0;
47 log_debug("Failed to write '%s' to /sys/power/disk: %s",
48 *mode, strerror(-k));
49 if (r == 0)
50 r = k;
51 }
6edd7d0a 52
19adb8a3
ZJS
53 if (r < 0)
54 log_error("Failed to write mode to /sys/power/disk: %s",
55 strerror(-r));
6edd7d0a 56
19adb8a3
ZJS
57 return r;
58}
6edd7d0a 59
19adb8a3
ZJS
60static int write_state(FILE *f0, char **states) {
61 FILE _cleanup_fclose_ *f = f0;
62 char **state;
63 int r = 0;
64
65 STRV_FOREACH(state, states) {
66 int k;
67
68 k = write_string_to_file(f, *state);
69 if (k == 0)
70 return 0;
71 log_debug("Failed to write '%s' to /sys/power/state: %s",
72 *state, strerror(-k));
73 if (r == 0)
74 r = k;
75
76 fclose(f);
77 f = fopen("/sys/power/state", "we");
78 if (!f) {
79 log_error("Failed to open /sys/power/state: %m");
80 return -errno;
81 }
6edd7d0a
LP
82 }
83
19adb8a3
ZJS
84 return r;
85}
6edd7d0a 86
19adb8a3
ZJS
87static int execute(char **modes, char **states) {
88 char* arguments[4];
89 int r;
90 FILE *f;
91 const char* note = strappenda("SLEEP=", arg_verb);
6524990f 92
19adb8a3
ZJS
93 /* This file is opened first, so that if we hit an error,
94 * we can abort before modyfing any state. */
6edd7d0a
LP
95 f = fopen("/sys/power/state", "we");
96 if (!f) {
97 log_error("Failed to open /sys/power/state: %m");
19adb8a3 98 return -errno;
6edd7d0a
LP
99 }
100
19adb8a3
ZJS
101 /* Configure the hibernation mode */
102 r = write_mode(modes);
103 if (r < 0)
104 return r;
105
6edd7d0a
LP
106 arguments[0] = NULL;
107 arguments[1] = (char*) "pre";
19adb8a3 108 arguments[2] = arg_verb;
6edd7d0a 109 arguments[3] = NULL;
ddcbc873 110 execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments);
6edd7d0a 111
19adb8a3
ZJS
112 log_struct(LOG_INFO,
113 MESSAGE_ID(SD_MESSAGE_SLEEP_START),
114 "MESSAGE=Suspending system...",
115 note,
116 NULL);
117
118 r = write_state(f, states);
119 if (r < 0)
120 return r;
121
122 log_struct(LOG_INFO,
123 MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
124 "MESSAGE=System resumed.",
125 note,
126 NULL);
eb267289 127
6edd7d0a 128 arguments[1] = (char*) "post";
ddcbc873 129 execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments);
6edd7d0a 130
19adb8a3
ZJS
131 return r;
132}
6edd7d0a 133
19adb8a3
ZJS
134static int help(void) {
135 printf("%s COMMAND\n\n"
136 "Suspend the system, hibernate the system, or both.\n\n"
137 "Commands:\n"
138 " -h --help Show this help and exit\n"
139 " --version Print version string and exit\n"
140 " suspend Suspend the system\n"
141 " hibernate Hibernate the system\n"
142 " hybrid-sleep Both hibernate and suspend the system\n"
143 , program_invocation_short_name
144 );
145
146 return 0;
147}
6edd7d0a 148
19adb8a3
ZJS
149static int parse_argv(int argc, char *argv[]) {
150 enum {
151 ARG_VERSION = 0x100,
152 };
153
154 static const struct option options[] = {
155 { "help", no_argument, NULL, 'h' },
156 { "version", no_argument, NULL, ARG_VERSION },
157 { NULL, 0, NULL, 0 }
158 };
159
160 int c;
161
162 assert(argc >= 0);
163 assert(argv);
164
165 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
166 switch(c) {
167 case 'h':
168 help();
169 return 0 /* done */;
170
171 case ARG_VERSION:
172 puts(PACKAGE_STRING);
173 puts(SYSTEMD_FEATURES);
174 return 0 /* done */;
175
176 case '?':
177 return -EINVAL;
178
179 default:
180 log_error("Unknown option code %c", c);
181 return -EINVAL;
182 }
183
184 if (argc - optind != 1) {
185 log_error("Usage: %s COMMAND",
186 program_invocation_short_name);
187 return -EINVAL;
188 }
189
190 arg_verb = argv[optind];
6edd7d0a 191
19adb8a3
ZJS
192 if (!streq(arg_verb, "suspend") &&
193 !streq(arg_verb, "hibernate") &&
194 !streq(arg_verb, "hybrid-sleep")) {
195 log_error("Unknown command '%s'.", arg_verb);
196 return -EINVAL;
197 }
198
199 return 1 /* work to do */;
200}
201
202int main(int argc, char *argv[]) {
203 _cleanup_strv_free_ char **modes = NULL, **states = NULL;
204 int r;
205
206 log_set_target(LOG_TARGET_AUTO);
207 log_parse_environment();
208 log_open();
209
210 r = parse_argv(argc, argv);
211 if (r <= 0)
212 goto finish;
213
214 r = parse_sleep_config(arg_verb, &modes, &states);
215 if (r < 0)
216 goto finish;
217
218 r = execute(modes, states);
219
220finish:
221 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6edd7d0a 222}