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