]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/sleep/sleep.c
hostnamectl: Exit with zero on success
[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
aa62a893
LP
28#include "sd-id128.h"
29#include "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"
aa62a893 36#include "def.h"
19adb8a3
ZJS
37
38static char* arg_verb = NULL;
39
40static int write_mode(char **modes) {
41 int r = 0;
42 char **mode;
43
44 STRV_FOREACH(mode, modes) {
aa62a893
LP
45 int k;
46
47 k = write_string_file("/sys/power/disk", *mode);
19adb8a3
ZJS
48 if (k == 0)
49 return 0;
aa62a893 50
19adb8a3
ZJS
51 log_debug("Failed to write '%s' to /sys/power/disk: %s",
52 *mode, strerror(-k));
53 if (r == 0)
54 r = k;
55 }
6edd7d0a 56
19adb8a3
ZJS
57 if (r < 0)
58 log_error("Failed to write mode to /sys/power/disk: %s",
59 strerror(-r));
6edd7d0a 60
19adb8a3
ZJS
61 return r;
62}
6edd7d0a 63
2fd069b1 64static int write_state(FILE **f, char **states) {
19adb8a3
ZJS
65 char **state;
66 int r = 0;
67
68 STRV_FOREACH(state, states) {
69 int k;
70
717603e3 71 k = write_string_stream(*f, *state);
19adb8a3
ZJS
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
2fd069b1
ZJS
79 fclose(*f);
80 *f = fopen("/sys/power/state", "we");
81 if (!*f) {
19adb8a3
ZJS
82 log_error("Failed to open /sys/power/state: %m");
83 return -errno;
84 }
6edd7d0a
LP
85 }
86
19adb8a3
ZJS
87 return r;
88}
6edd7d0a 89
19adb8a3 90static int execute(char **modes, char **states) {
e2cc6eca
LP
91
92 char *arguments[] = {
93 NULL,
94 (char*) "pre",
95 arg_verb,
96 NULL
97 };
98
19adb8a3 99 int r;
2fd069b1 100 _cleanup_fclose_ FILE *f = NULL;
6524990f 101
19adb8a3 102 /* This file is opened first, so that if we hit an error,
09692409 103 * we can abort before modifying any state. */
6edd7d0a
LP
104 f = fopen("/sys/power/state", "we");
105 if (!f) {
106 log_error("Failed to open /sys/power/state: %m");
19adb8a3 107 return -errno;
6edd7d0a
LP
108 }
109
19adb8a3
ZJS
110 /* Configure the hibernation mode */
111 r = write_mode(modes);
112 if (r < 0)
113 return r;
114
e2680723 115 execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
6edd7d0a 116
19adb8a3 117 log_struct(LOG_INFO,
e2cc6eca
LP
118 LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
119 LOG_MESSAGE("Suspending system..."),
120 "SLEEP=%s", arg_verb,
19adb8a3
ZJS
121 NULL);
122
2fd069b1 123 r = write_state(&f, states);
19adb8a3
ZJS
124 if (r < 0)
125 return r;
126
127 log_struct(LOG_INFO,
e2cc6eca
LP
128 LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
129 LOG_MESSAGE("MESSAGE=System resumed."),
130 "SLEEP=%s", arg_verb,
19adb8a3 131 NULL);
eb267289 132
6edd7d0a 133 arguments[1] = (char*) "post";
e2680723 134 execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
6edd7d0a 135
19adb8a3
ZJS
136 return r;
137}
6edd7d0a 138
601185b4 139static void help(void) {
19adb8a3
ZJS
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"
601185b4 148 , program_invocation_short_name);
19adb8a3 149}
6edd7d0a 150
19adb8a3
ZJS
151static 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 },
eb9da376 159 {}
19adb8a3
ZJS
160 };
161
162 int c;
163
164 assert(argc >= 0);
165 assert(argv);
166
601185b4 167 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
19adb8a3
ZJS
168 switch(c) {
169 case 'h':
601185b4
ZJS
170 help();
171 return 0; /* done */
19adb8a3
ZJS
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:
eb9da376 182 assert_not_reached("Unhandled option");
19adb8a3
ZJS
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];
6edd7d0a 192
19adb8a3
ZJS
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
203int 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
221finish:
222 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6edd7d0a 223}