chiark / gitweb /
log: fix order of log_unit_struct() to match other logging 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("Failed to write '%s' to /sys/power/disk: %s",
52                           *mode, strerror(-k));
53                 if (r == 0)
54                         r = k;
55         }
56
57         if (r < 0)
58                 log_error("Failed to write mode to /sys/power/disk: %s",
59                           strerror(-r));
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);
72                 if (k == 0)
73                         return 0;
74                 log_debug("Failed to write '%s' to /sys/power/state: %s",
75                           *state, strerror(-k));
76                 if (r == 0)
77                         r = k;
78
79                 fclose(*f);
80                 *f = fopen("/sys/power/state", "we");
81                 if (!*f) {
82                         log_error("Failed to open /sys/power/state: %m");
83                         return -errno;
84                 }
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
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                 log_error("Failed to open /sys/power/state: %m");
107                 return -errno;
108         }
109
110         /* Configure the hibernation mode */
111         r = write_mode(modes);
112         if (r < 0)
113                 return r;
114
115         execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
116
117         log_struct(LOG_INFO,
118                    LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
119                    LOG_MESSAGE("Suspending system..."),
120                    "SLEEP=%s", arg_verb,
121                    NULL);
122
123         r = write_state(&f, states);
124         if (r < 0)
125                 return r;
126
127         log_struct(LOG_INFO,
128                    LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
129                    LOG_MESSAGE("MESSAGE=System resumed."),
130                    "SLEEP=%s", arg_verb,
131                    NULL);
132
133         arguments[1] = (char*) "post";
134         execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
135
136         return r;
137 }
138
139 static void help(void) {
140         printf("%s COMMAND\n\n"
141                "Suspend the system, hibernate the system, or both.\n\n"
142                "Commands:\n"
143                "  -h --help            Show this help and exit\n"
144                "  --version            Print version string and exit\n"
145                "  suspend              Suspend the system\n"
146                "  hibernate            Hibernate the system\n"
147                "  hybrid-sleep         Both hibernate and suspend the system\n"
148                , program_invocation_short_name);
149 }
150
151 static int parse_argv(int argc, char *argv[]) {
152         enum {
153                 ARG_VERSION = 0x100,
154         };
155
156         static const struct option options[] = {
157                 { "help",         no_argument,       NULL, 'h'           },
158                 { "version",      no_argument,       NULL, ARG_VERSION   },
159                 {}
160         };
161
162         int c;
163
164         assert(argc >= 0);
165         assert(argv);
166
167         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
168                 switch(c) {
169                 case 'h':
170                         help();
171                         return 0; /* done */
172
173                 case ARG_VERSION:
174                         puts(PACKAGE_STRING);
175                         puts(SYSTEMD_FEATURES);
176                         return 0 /* done */;
177
178                 case '?':
179                         return -EINVAL;
180
181                 default:
182                         assert_not_reached("Unhandled option");
183                 }
184
185         if (argc - optind != 1) {
186                 log_error("Usage: %s COMMAND",
187                           program_invocation_short_name);
188                 return -EINVAL;
189         }
190
191         arg_verb = argv[optind];
192
193         if (!streq(arg_verb, "suspend") &&
194             !streq(arg_verb, "hibernate") &&
195             !streq(arg_verb, "hybrid-sleep")) {
196                 log_error("Unknown command '%s'.", arg_verb);
197                 return -EINVAL;
198         }
199
200         return 1 /* work to do */;
201 }
202
203 int main(int argc, char *argv[]) {
204         _cleanup_strv_free_ char **modes = NULL, **states = NULL;
205         int r;
206
207         log_set_target(LOG_TARGET_AUTO);
208         log_parse_environment();
209         log_open();
210
211         r = parse_argv(argc, argv);
212         if (r <= 0)
213                 goto finish;
214
215         r = parse_sleep_config(arg_verb, &modes, &states);
216         if (r < 0)
217                 goto finish;
218
219         r = execute(modes, states);
220
221 finish:
222         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
223 }