chiark / gitweb /
Prep v236 : Add missing SPDX-License-Identifier (7/9) src/systemd
[elogind.git] / src / sleep / sleep.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2012 Lennart Poettering
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 <errno.h>
23 //#include <getopt.h>
24 //#include <stdio.h>
25
26 #include "sd-messages.h"
27
28 #include "def.h"
29 #include "exec-util.h"
30 #include "fd-util.h"
31 #include "fileio.h"
32 //#include "log.h"
33 //#include "sleep-config.h"
34 //#include "string-util.h"
35 #include "strv.h"
36 //#include "util.h"
37
38 /// Additional includes needed by elogind
39 #include "sleep.h"
40
41 static char* arg_verb = NULL;
42
43 static int write_mode(char **modes) {
44         int r = 0;
45         char **mode;
46
47         STRV_FOREACH(mode, modes) {
48                 int k;
49
50                 k = write_string_file("/sys/power/disk", *mode, 0);
51                 if (k == 0)
52                         return 0;
53
54                 log_debug_errno(k, "Failed to write '%s' to /sys/power/disk: %m",
55                                 *mode);
56                 if (r == 0)
57                         r = k;
58         }
59
60         if (r < 0)
61                 log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");
62
63         return r;
64 }
65
66 static int write_state(FILE **f, char **states) {
67         char **state;
68         int r = 0;
69
70         STRV_FOREACH(state, states) {
71                 int k;
72
73                 k = write_string_stream(*f, *state, 0);
74                 if (k == 0)
75                         return 0;
76                 log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
77                                 *state);
78                 if (r == 0)
79                         r = k;
80
81                 fclose(*f);
82                 *f = fopen("/sys/power/state", "we");
83                 if (!*f)
84                         return log_error_errno(errno, "Failed to open /sys/power/state: %m");
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         static const char* const dirs[] = {
99                 SYSTEM_SLEEP_PATH,
100                 NULL
101         };
102
103         int r;
104         _cleanup_fclose_ FILE *f = NULL;
105
106         /* This file is opened first, so that if we hit an error,
107          * we can abort before modifying any state. */
108         f = fopen("/sys/power/state", "we");
109         if (!f)
110                 return log_error_errno(errno, "Failed to open /sys/power/state: %m");
111
112         /* Configure the hibernation mode */
113         r = write_mode(modes);
114         if (r < 0)
115                 return r;
116
117         execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
118
119         log_struct(LOG_INFO,
120                    "MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
121                    LOG_MESSAGE("Suspending system..."),
122                    "SLEEP=%s", arg_verb,
123                    NULL);
124
125         r = write_state(&f, states);
126         if (r < 0)
127                 return r;
128
129         log_struct(LOG_INFO,
130                    "MESSAGE_ID=" SD_MESSAGE_SLEEP_STOP_STR,
131                    LOG_MESSAGE("System resumed."),
132                    "SLEEP=%s", arg_verb,
133                    NULL);
134
135         arguments[1] = (char*) "post";
136         execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
137
138         return r;
139 }
140
141 #if 0 /// elogind calls execute() by itself and does not need another binary
142 static void help(void) {
143         printf("%s COMMAND\n\n"
144                "Suspend the system, hibernate the system, or both.\n\n"
145                "Commands:\n"
146                "  -h --help            Show this help and exit\n"
147                "  --version            Print version string and exit\n"
148                "  suspend              Suspend the system\n"
149                "  hibernate            Hibernate the system\n"
150                "  hybrid-sleep         Both hibernate and suspend the system\n"
151                , program_invocation_short_name);
152 }
153
154 static int parse_argv(int argc, char *argv[]) {
155         enum {
156                 ARG_VERSION = 0x100,
157         };
158
159         static const struct option options[] = {
160                 { "help",         no_argument,       NULL, 'h'           },
161                 { "version",      no_argument,       NULL, ARG_VERSION   },
162                 {}
163         };
164
165         int c;
166
167         assert(argc >= 0);
168         assert(argv);
169
170         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
171                 switch(c) {
172                 case 'h':
173                         help();
174                         return 0; /* done */
175
176                 case ARG_VERSION:
177                         return version();
178
179                 case '?':
180                         return -EINVAL;
181
182                 default:
183                         assert_not_reached("Unhandled option");
184                 }
185
186         if (argc - optind != 1) {
187                 log_error("Usage: %s COMMAND",
188                           program_invocation_short_name);
189                 return -EINVAL;
190         }
191
192         arg_verb = argv[optind];
193
194         if (!streq(arg_verb, "suspend") &&
195             !streq(arg_verb, "hibernate") &&
196             !streq(arg_verb, "hybrid-sleep")) {
197                 log_error("Unknown command '%s'.", arg_verb);
198                 return -EINVAL;
199         }
200
201         return 1 /* work to do */;
202 }
203
204 int main(int argc, char *argv[]) {
205         _cleanup_strv_free_ char **modes = NULL, **states = NULL;
206         int r;
207
208         log_set_target(LOG_TARGET_AUTO);
209         log_parse_environment();
210         log_open();
211
212         r = parse_argv(argc, argv);
213         if (r <= 0)
214                 goto finish;
215
216         r = parse_sleep_config(arg_verb, &modes, &states);
217         if (r < 0)
218                 goto finish;
219
220         r = execute(modes, states);
221
222 finish:
223         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
224 }
225 #else
226 int do_sleep(const char *verb, char **modes, char **states) {
227         assert(verb);
228         arg_verb = (char*)verb;
229         return execute(modes, states);
230 }
231 #endif // 0