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