chiark / gitweb /
treewide: more log_*_errno() conversions, multiline calls
[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 "sd-id128.h"
29 #include "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 #include "def.h"
37
38 static char* arg_verb = NULL;
39
40 static int write_mode(char **modes) {
41         int r = 0;
42         char **mode;
43
44         STRV_FOREACH(mode, modes) {
45                 int k;
46
47                 k = write_string_file("/sys/power/disk", *mode);
48                 if (k == 0)
49                         return 0;
50
51                 log_debug_errno(k, "Failed to write '%s' to /sys/power/disk: %m",
52                                 *mode);
53                 if (r == 0)
54                         r = k;
55         }
56
57         if (r < 0)
58                 log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");
59
60         return r;
61 }
62
63 static int write_state(FILE **f, char **states) {
64         char **state;
65         int r = 0;
66
67         STRV_FOREACH(state, states) {
68                 int k;
69
70                 k = write_string_stream(*f, *state);
71                 if (k == 0)
72                         return 0;
73                 log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
74                                 *state);
75                 if (r == 0)
76                         r = k;
77
78                 fclose(*f);
79                 *f = fopen("/sys/power/state", "we");
80                 if (!*f) {
81                         log_error("Failed to open /sys/power/state: %m");
82                         return -errno;
83                 }
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
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                 log_error("Failed to open /sys/power/state: %m");
106                 return -errno;
107         }
108
109         /* Configure the hibernation mode */
110         r = write_mode(modes);
111         if (r < 0)
112                 return r;
113
114         execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
115
116         log_struct(LOG_INFO,
117                    LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
118                    LOG_MESSAGE("Suspending system..."),
119                    "SLEEP=%s", arg_verb,
120                    NULL);
121
122         r = write_state(&f, states);
123         if (r < 0)
124                 return r;
125
126         log_struct(LOG_INFO,
127                    LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
128                    LOG_MESSAGE("MESSAGE=System resumed."),
129                    "SLEEP=%s", arg_verb,
130                    NULL);
131
132         arguments[1] = (char*) "post";
133         execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
134
135         return r;
136 }
137
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                         puts(PACKAGE_STRING);
174                         puts(SYSTEMD_FEATURES);
175                         return 0 /* done */;
176
177                 case '?':
178                         return -EINVAL;
179
180                 default:
181                         assert_not_reached("Unhandled option");
182                 }
183
184         if (argc - optind != 1) {
185                 log_error("Usage: %s COMMAND",
186                           program_invocation_short_name);
187                 return -EINVAL;
188         }
189
190         arg_verb = argv[optind];
191
192         if (!streq(arg_verb, "suspend") &&
193             !streq(arg_verb, "hibernate") &&
194             !streq(arg_verb, "hybrid-sleep")) {
195                 log_error("Unknown command '%s'.", arg_verb);
196                 return -EINVAL;
197         }
198
199         return 1 /* work to do */;
200 }
201
202 int main(int argc, char *argv[]) {
203         _cleanup_strv_free_ char **modes = NULL, **states = NULL;
204         int r;
205
206         log_set_target(LOG_TARGET_AUTO);
207         log_parse_environment();
208         log_open();
209
210         r = parse_argv(argc, argv);
211         if (r <= 0)
212                 goto finish;
213
214         r = parse_sleep_config(arg_verb, &modes, &states);
215         if (r < 0)
216                 goto finish;
217
218         r = execute(modes, states);
219
220 finish:
221         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
222 }