chiark / gitweb /
cf03c34b30e327accaa9fa7e78db1653f5b60efe
[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 "fd-util.h"
29 #include "fileio.h"
30 //#include "log.h"
31 //#include "sleep-config.h"
32 //#include "string-util.h"
33 #include "strv.h"
34 //#include "util.h"
35
36 /// Additional includes needed by elogind
37 #include "sleep.h"
38
39 static char* arg_verb = NULL;
40
41 static int write_mode(char **modes) {
42         int r = 0;
43         char **mode;
44
45         STRV_FOREACH(mode, modes) {
46                 int k;
47
48                 k = write_string_file("/sys/power/disk", *mode, 0);
49                 if (k == 0)
50                         return 0;
51
52                 log_debug_errno(k, "Failed to write '%s' to /sys/power/disk: %m",
53                                 *mode);
54                 if (r == 0)
55                         r = k;
56         }
57
58         if (r < 0)
59                 log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");
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, true);
72                 if (k == 0)
73                         return 0;
74                 log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
75                                 *state);
76                 if (r == 0)
77                         r = k;
78
79                 fclose(*f);
80                 *f = fopen("/sys/power/state", "we");
81                 if (!*f)
82                         return log_error_errno(errno, "Failed to open /sys/power/state: %m");
83         }
84
85         return r;
86 }
87
88 static int execute(char **modes, char **states) {
89
90         char *arguments[] = {
91                 NULL,
92                 (char*) "pre",
93                 arg_verb,
94                 NULL
95         };
96         static const char* const dirs[] = {SYSTEM_SLEEP_PATH, NULL};
97
98         int r;
99         _cleanup_fclose_ FILE *f = NULL;
100
101         /* This file is opened first, so that if we hit an error,
102          * we can abort before modifying any state. */
103         f = fopen("/sys/power/state", "we");
104         if (!f)
105                 return log_error_errno(errno, "Failed to open /sys/power/state: %m");
106
107         /* Configure the hibernation mode */
108         r = write_mode(modes);
109         if (r < 0)
110                 return r;
111
112         execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
113
114         log_struct(LOG_INFO,
115                    LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
116                    LOG_MESSAGE("Suspending system..."),
117                    "SLEEP=%s", arg_verb,
118                    NULL);
119
120         r = write_state(&f, states);
121         if (r < 0)
122                 return r;
123
124         log_struct(LOG_INFO,
125                    LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
126                    LOG_MESSAGE("System resumed."),
127                    "SLEEP=%s", arg_verb,
128                    NULL);
129
130         arguments[1] = (char*) "post";
131         execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
132
133         return r;
134 }
135
136 #if 0 /// elogind calls execute() by itself and does not need another binary
137 static void help(void) {
138         printf("%s COMMAND\n\n"
139                "Suspend the system, hibernate the system, or both.\n\n"
140                "Commands:\n"
141                "  -h --help            Show this help and exit\n"
142                "  --version            Print version string and exit\n"
143                "  suspend              Suspend the system\n"
144                "  hibernate            Hibernate the system\n"
145                "  hybrid-sleep         Both hibernate and suspend the system\n"
146                , program_invocation_short_name);
147 }
148
149 static 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                 {}
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                         return version();
173
174                 case '?':
175                         return -EINVAL;
176
177                 default:
178                         assert_not_reached("Unhandled option");
179                 }
180
181         if (argc - optind != 1) {
182                 log_error("Usage: %s COMMAND",
183                           program_invocation_short_name);
184                 return -EINVAL;
185         }
186
187         arg_verb = argv[optind];
188
189         if (!streq(arg_verb, "suspend") &&
190             !streq(arg_verb, "hibernate") &&
191             !streq(arg_verb, "hybrid-sleep")) {
192                 log_error("Unknown command '%s'.", arg_verb);
193                 return -EINVAL;
194         }
195
196         return 1 /* work to do */;
197 }
198
199 int main(int argc, char *argv[]) {
200         _cleanup_strv_free_ char **modes = NULL, **states = NULL;
201         int r;
202
203         log_set_target(LOG_TARGET_AUTO);
204         log_parse_environment();
205         log_open();
206
207         r = parse_argv(argc, argv);
208         if (r <= 0)
209                 goto finish;
210
211         r = parse_sleep_config(arg_verb, &modes, &states);
212         if (r < 0)
213                 goto finish;
214
215         r = execute(modes, states);
216
217 finish:
218         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
219 }
220 #else
221 int do_sleep(const char *verb, char **modes, char **states) {
222         assert(verb);
223         arg_verb = (char*)verb;
224         return execute(modes, states);
225 }
226 #endif // 0