chiark / gitweb /
sleep.c: fix typo
[elogind.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 "systemd/sd-id128.h"
29 #include "systemd/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
37 static char* arg_verb = NULL;
38
39 static int write_mode(char **modes) {
40         int r = 0;
41         char **mode;
42
43         STRV_FOREACH(mode, modes) {
44                 int k = write_string_file("/sys/power/disk", *mode);
45                 if (k == 0)
46                         return 0;
47                 log_debug("Failed to write '%s' to /sys/power/disk: %s",
48                           *mode, strerror(-k));
49                 if (r == 0)
50                         r = k;
51         }
52
53         if (r < 0)
54                 log_error("Failed to write mode to /sys/power/disk: %s",
55                           strerror(-r));
56
57         return r;
58 }
59
60 static int write_state(FILE **f, char **states) {
61         char **state;
62         int r = 0;
63
64         STRV_FOREACH(state, states) {
65                 int k;
66
67                 k = write_string_to_file(*f, *state);
68                 if (k == 0)
69                         return 0;
70                 log_debug("Failed to write '%s' to /sys/power/state: %s",
71                           *state, strerror(-k));
72                 if (r == 0)
73                         r = k;
74
75                 fclose(*f);
76                 *f = fopen("/sys/power/state", "we");
77                 if (!*f) {
78                         log_error("Failed to open /sys/power/state: %m");
79                         return -errno;
80                 }
81         }
82
83         return r;
84 }
85
86 static int execute(char **modes, char **states) {
87         char* arguments[4];
88         int r;
89         _cleanup_fclose_ FILE *f = NULL;
90         const char* note = strappenda("SLEEP=", arg_verb);
91
92         /* This file is opened first, so that if we hit an error,
93          * we can abort before modifying any state. */
94         f = fopen("/sys/power/state", "we");
95         if (!f) {
96                 log_error("Failed to open /sys/power/state: %m");
97                 return -errno;
98         }
99
100         /* Configure the hibernation mode */
101         r = write_mode(modes);
102         if (r < 0)
103                 return r;
104
105         arguments[0] = NULL;
106         arguments[1] = (char*) "pre";
107         arguments[2] = arg_verb;
108         arguments[3] = NULL;
109         execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments);
110
111         log_struct(LOG_INFO,
112                    MESSAGE_ID(SD_MESSAGE_SLEEP_START),
113                    "MESSAGE=Suspending system...",
114                    note,
115                    NULL);
116
117         r = write_state(&f, states);
118         if (r < 0)
119                 return r;
120
121         log_struct(LOG_INFO,
122                    MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
123                    "MESSAGE=System resumed.",
124                    note,
125                    NULL);
126
127         arguments[1] = (char*) "post";
128         execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments);
129
130         return r;
131 }
132
133 static int help(void) {
134         printf("%s COMMAND\n\n"
135                "Suspend the system, hibernate the system, or both.\n\n"
136                "Commands:\n"
137                "  -h --help            Show this help and exit\n"
138                "  --version            Print version string and exit\n"
139                "  suspend              Suspend the system\n"
140                "  hibernate            Hibernate the system\n"
141                "  hybrid-sleep         Both hibernate and suspend the system\n"
142                , program_invocation_short_name
143                );
144
145         return 0;
146 }
147
148 static int parse_argv(int argc, char *argv[]) {
149         enum {
150                 ARG_VERSION = 0x100,
151         };
152
153         static const struct option options[] = {
154                 { "help",         no_argument,       NULL, 'h'           },
155                 { "version",      no_argument,       NULL, ARG_VERSION   },
156                 {}
157         };
158
159         int c;
160
161         assert(argc >= 0);
162         assert(argv);
163
164         while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
165                 switch(c) {
166                 case 'h':
167                         return help();
168
169                 case ARG_VERSION:
170                         puts(PACKAGE_STRING);
171                         puts(SYSTEMD_FEATURES);
172                         return 0 /* done */;
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 }