chiark / gitweb /
exec-util,conf-files: skip non-executable files in execute_directories()
[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[] = {
98                 SYSTEM_SLEEP_PATH,
99                 NULL
100         };
101
102         int r;
103         _cleanup_fclose_ FILE *f = NULL;
104
105         /* This file is opened first, so that if we hit an error,
106          * we can abort before modifying any state. */
107         f = fopen("/sys/power/state", "we");
108         if (!f)
109                 return log_error_errno(errno, "Failed to open /sys/power/state: %m");
110
111         /* Configure the hibernation mode */
112         r = write_mode(modes);
113         if (r < 0)
114                 return r;
115
116         execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
117
118         log_struct(LOG_INFO,
119                    "MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
120                    LOG_MESSAGE("Suspending system..."),
121                    "SLEEP=%s", arg_verb,
122                    NULL);
123
124         r = write_state(&f, states);
125         if (r < 0)
126                 return r;
127
128         log_struct(LOG_INFO,
129                    "MESSAGE_ID=" SD_MESSAGE_SLEEP_STOP_STR,
130                    LOG_MESSAGE("System resumed."),
131                    "SLEEP=%s", arg_verb,
132                    NULL);
133
134         arguments[1] = (char*) "post";
135         execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
136
137         return r;
138 }
139
140 #if 0 /// elogind calls execute() by itself and does not need another binary
141 static void help(void) {
142         printf("%s COMMAND\n\n"
143                "Suspend the system, hibernate the system, or both.\n\n"
144                "Commands:\n"
145                "  -h --help            Show this help and exit\n"
146                "  --version            Print version string and exit\n"
147                "  suspend              Suspend the system\n"
148                "  hibernate            Hibernate the system\n"
149                "  hybrid-sleep         Both hibernate and suspend the system\n"
150                , program_invocation_short_name);
151 }
152
153 static int parse_argv(int argc, char *argv[]) {
154         enum {
155                 ARG_VERSION = 0x100,
156         };
157
158         static const struct option options[] = {
159                 { "help",         no_argument,       NULL, 'h'           },
160                 { "version",      no_argument,       NULL, ARG_VERSION   },
161                 {}
162         };
163
164         int c;
165
166         assert(argc >= 0);
167         assert(argv);
168
169         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
170                 switch(c) {
171                 case 'h':
172                         help();
173                         return 0; /* done */
174
175                 case ARG_VERSION:
176                         return version();
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 }
224 #else
225 int do_sleep(const char *verb, char **modes, char **states) {
226         assert(verb);
227         arg_verb = (char*)verb;
228         return execute(modes, states);
229 }
230 #endif // 0