]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shutdownd/shutdownd.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / shutdownd / shutdownd.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <sys/poll.h>
24 #include <sys/types.h>
25 #include <sys/timerfd.h>
26 #include <assert.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <stddef.h>
32
33 #include "systemd/sd-daemon.h"
34 #include "systemd/sd-shutdown.h"
35
36 #include "log.h"
37 #include "macro.h"
38 #include "util.h"
39 #include "utmp-wtmp.h"
40 #include "mkdir.h"
41 #include "fileio.h"
42
43 union shutdown_buffer {
44 struct sd_shutdown_command command;
45 char space[offsetof(struct sd_shutdown_command, wall_message) + LINE_MAX];
46 };
47
48 static int read_packet(int fd, union shutdown_buffer *_b) {
49 struct ucred *ucred;
50 ssize_t n;
51
52 union shutdown_buffer b; /* We maintain our own copy here, in
53 * order not to corrupt the last message */
54 struct iovec iovec = {
55 .iov_base = &b,
56 .iov_len = sizeof(b) - 1,
57 };
58 union {
59 struct cmsghdr cmsghdr;
60 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
61 } control = {};
62 struct msghdr msghdr = {
63 .msg_iov = &iovec,
64 .msg_iovlen = 1,
65 .msg_control = &control,
66 .msg_controllen = sizeof(control),
67 };
68
69 assert(fd >= 0);
70 assert(_b);
71
72 n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
73 if (n <= 0) {
74 if (n == 0) {
75 log_error("Short read");
76 return -EIO;
77 }
78
79 if (errno == EAGAIN || errno == EINTR)
80 return 0;
81
82 log_error_errno(errno, "recvmsg(): %m");
83 return -errno;
84 }
85
86 if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
87 control.cmsghdr.cmsg_level != SOL_SOCKET ||
88 control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
89 control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
90 log_warning("Received message without credentials. Ignoring.");
91 return 0;
92 }
93
94 ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
95 if (ucred->uid != 0) {
96 log_warning("Got request from unprivileged user. Ignoring.");
97 return 0;
98 }
99
100 if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) {
101 log_warning("Message has invalid size. Ignoring.");
102 return 0;
103 }
104
105 if (b.command.mode != SD_SHUTDOWN_NONE &&
106 b.command.mode != SD_SHUTDOWN_REBOOT &&
107 b.command.mode != SD_SHUTDOWN_POWEROFF &&
108 b.command.mode != SD_SHUTDOWN_HALT &&
109 b.command.mode != SD_SHUTDOWN_KEXEC) {
110 log_warning("Message has invalid mode. Ignoring.");
111 return 0;
112 }
113
114 b.space[n] = 0;
115
116 *_b = b;
117 return 1;
118 }
119
120 static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
121 char date[FORMAT_TIMESTAMP_MAX];
122 const char *prefix;
123 _cleanup_free_ char *l = NULL;
124
125 assert(c);
126 assert(c->warn_wall);
127
128 if (n >= c->usec)
129 return;
130
131 if (c->mode == SD_SHUTDOWN_HALT)
132 prefix = "The system is going down for system halt at ";
133 else if (c->mode == SD_SHUTDOWN_POWEROFF)
134 prefix = "The system is going down for power-off at ";
135 else if (c->mode == SD_SHUTDOWN_REBOOT)
136 prefix = "The system is going down for reboot at ";
137 else if (c->mode == SD_SHUTDOWN_KEXEC)
138 prefix = "The system is going down for kexec reboot at ";
139 else if (c->mode == SD_SHUTDOWN_NONE)
140 prefix = "The system shutdown has been cancelled at ";
141 else
142 assert_not_reached("Unknown mode!");
143
144 if (asprintf(&l, "%s%s%s%s!", c->wall_message, c->wall_message[0] ? "\n" : "",
145 prefix, format_timestamp(date, sizeof(date), c->usec)) >= 0)
146 utmp_wall(l, NULL, NULL);
147 else
148 log_error("Failed to allocate wall message");
149 }
150
151 _const_ static usec_t when_wall(usec_t n, usec_t elapse) {
152
153 static const struct {
154 usec_t delay;
155 usec_t interval;
156 } table[] = {
157 { 0, USEC_PER_MINUTE },
158 { 10 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE },
159 { USEC_PER_HOUR, 30 * USEC_PER_MINUTE },
160 { 3 * USEC_PER_HOUR, USEC_PER_HOUR },
161 };
162
163 usec_t left, sub;
164 unsigned i = ELEMENTSOF(table) - 1;
165
166 /* If the time is already passed, then don't announce */
167 if (n >= elapse)
168 return 0;
169
170 left = elapse - n;
171 while (left < table[i].delay)
172 i--;
173 sub = (left / table[i].interval) * table[i].interval;
174
175 assert(sub < elapse);
176 return elapse - sub;
177 }
178
179 static usec_t when_nologin(usec_t elapse) {
180 return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
181 }
182
183 static const char *mode_to_string(enum sd_shutdown_mode m) {
184 switch (m) {
185 case SD_SHUTDOWN_REBOOT:
186 return "reboot";
187 case SD_SHUTDOWN_POWEROFF:
188 return "poweroff";
189 case SD_SHUTDOWN_HALT:
190 return "halt";
191 case SD_SHUTDOWN_KEXEC:
192 return "kexec";
193 default:
194 return NULL;
195 }
196 }
197
198 static int update_schedule_file(struct sd_shutdown_command *c) {
199 int r;
200 _cleanup_fclose_ FILE *f = NULL;
201 _cleanup_free_ char *t = NULL, *temp_path = NULL;
202
203 assert(c);
204
205 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
206 if (r < 0)
207 return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
208
209 t = cescape(c->wall_message);
210 if (!t)
211 return log_oom();
212
213 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
214 if (r < 0)
215 return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
216
217 fchmod(fileno(f), 0644);
218
219 fprintf(f,
220 "USEC="USEC_FMT"\n"
221 "WARN_WALL=%i\n"
222 "MODE=%s\n",
223 c->usec,
224 c->warn_wall,
225 mode_to_string(c->mode));
226
227 if (c->dry_run)
228 fputs("DRY_RUN=1\n", f);
229
230 if (!isempty(t))
231 fprintf(f, "WALL_MESSAGE=%s\n", t);
232
233 fflush(f);
234
235 if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
236 log_error_errno(errno, "Failed to write information about scheduled shutdowns: %m");
237 r = -errno;
238
239 unlink(temp_path);
240 unlink("/run/systemd/shutdown/scheduled");
241 }
242
243 return r;
244 }
245
246 static bool scheduled(struct sd_shutdown_command *c) {
247 return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
248 }
249
250 int main(int argc, char *argv[]) {
251 enum {
252 FD_SOCKET,
253 FD_WALL_TIMER,
254 FD_NOLOGIN_TIMER,
255 FD_SHUTDOWN_TIMER,
256 _FD_MAX
257 };
258
259 int r = EXIT_FAILURE, n_fds;
260 union shutdown_buffer b = {};
261 struct pollfd pollfd[_FD_MAX] = {};
262 bool exec_shutdown = false, unlink_nologin = false;
263 unsigned i;
264
265 if (getppid() != 1) {
266 log_error("This program should be invoked by init only.");
267 return EXIT_FAILURE;
268 }
269
270 if (argc > 1) {
271 log_error("This program does not take arguments.");
272 return EXIT_FAILURE;
273 }
274
275 log_set_target(LOG_TARGET_AUTO);
276 log_parse_environment();
277 log_open();
278
279 umask(0022);
280
281 n_fds = sd_listen_fds(true);
282 if (n_fds < 0) {
283 log_error_errno(r, "Failed to read listening file descriptors from environment: %m");
284 return EXIT_FAILURE;
285 }
286
287 if (n_fds != 1) {
288 log_error("Need exactly one file descriptor.");
289 return EXIT_FAILURE;
290 }
291
292 pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
293 pollfd[FD_SOCKET].events = POLLIN;
294
295 for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
296 pollfd[i].events = POLLIN;
297 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
298 if (pollfd[i].fd < 0) {
299 log_error_errno(errno, "timerfd_create(): %m");
300 goto finish;
301 }
302 }
303
304 log_debug("systemd-shutdownd running as pid "PID_FMT, getpid());
305
306 sd_notify(false,
307 "READY=1\n"
308 "STATUS=Processing requests...");
309
310 for (;;) {
311 int k;
312 usec_t n;
313
314 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
315 if (k < 0) {
316
317 if (errno == EAGAIN || errno == EINTR)
318 continue;
319
320 log_error_errno(errno, "poll(): %m");
321 goto finish;
322 }
323
324 /* Exit on idle */
325 if (k == 0)
326 break;
327
328 n = now(CLOCK_REALTIME);
329
330 if (pollfd[FD_SOCKET].revents) {
331
332 k = read_packet(pollfd[FD_SOCKET].fd, &b);
333 if (k < 0)
334 goto finish;
335 else if (k > 0) {
336 struct itimerspec its;
337 char date[FORMAT_TIMESTAMP_MAX];
338
339 if (!scheduled(&b.command)) {
340 log_info("Shutdown canceled.");
341 if (b.command.warn_wall)
342 warn_wall(0, &b.command);
343 break;
344 }
345
346 zero(its);
347 if (b.command.warn_wall) {
348 /* Send wall messages every so often */
349 timespec_store(&its.it_value, when_wall(n, b.command.usec));
350
351 /* Warn immediately if less than 15 minutes are left */
352 if (n < b.command.usec &&
353 n + 15*USEC_PER_MINUTE >= b.command.usec)
354 warn_wall(n, &b.command);
355 }
356 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
357 log_error_errno(errno, "timerfd_settime(): %m");
358 goto finish;
359 }
360
361 /* Disallow logins 5 minutes prior to shutdown */
362 zero(its);
363 timespec_store(&its.it_value, when_nologin(b.command.usec));
364 if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
365 log_error_errno(errno, "timerfd_settime(): %m");
366 goto finish;
367 }
368
369 /* Shutdown after the specified time is reached */
370 zero(its);
371 timespec_store(&its.it_value, b.command.usec);
372 if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
373 log_error_errno(errno, "timerfd_settime(): %m");
374 goto finish;
375 }
376
377 update_schedule_file(&b.command);
378
379 sd_notifyf(false,
380 "STATUS=Shutting down at %s (%s)...",
381 format_timestamp(date, sizeof(date), b.command.usec),
382 mode_to_string(b.command.mode));
383
384 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
385 }
386 }
387
388 if (pollfd[FD_WALL_TIMER].revents) {
389 struct itimerspec its = {};
390
391 warn_wall(n, &b.command);
392 flush_fd(pollfd[FD_WALL_TIMER].fd);
393
394 /* Restart timer */
395 timespec_store(&its.it_value, when_wall(n, b.command.usec));
396 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
397 log_error_errno(errno, "timerfd_settime(): %m");
398 goto finish;
399 }
400 }
401
402 if (pollfd[FD_NOLOGIN_TIMER].revents) {
403 int e;
404
405 log_info("Creating /run/nologin, blocking further logins...");
406
407 e = write_string_file_atomic("/run/nologin", "System is going down.");
408 if (e < 0)
409 log_error_errno(e, "Failed to create /run/nologin: %m");
410 else
411 unlink_nologin = true;
412
413 flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
414 }
415
416 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
417 exec_shutdown = true;
418 goto finish;
419 }
420 }
421
422 r = EXIT_SUCCESS;
423
424 log_debug("systemd-shutdownd stopped as pid "PID_FMT, getpid());
425
426 finish:
427
428 for (i = 0; i < _FD_MAX; i++)
429 safe_close(pollfd[i].fd);
430
431 if (unlink_nologin)
432 unlink("/run/nologin");
433
434 unlink("/run/systemd/shutdown/scheduled");
435
436 if (exec_shutdown && !b.command.dry_run) {
437 char sw[3];
438
439 sw[0] = '-';
440 sw[1] = b.command.mode;
441 sw[2] = 0;
442
443 execl(SYSTEMCTL_BINARY_PATH,
444 "shutdown",
445 sw,
446 "now",
447 (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
448 (b.command.warn_wall ? NULL : "--no-wall"),
449 NULL);
450
451 log_error_errno(errno, "Failed to execute /sbin/shutdown: %m");
452 }
453
454 sd_notify(false,
455 "STOPPING=\n"
456 "STATUS=Exiting...");
457
458 return r;
459 }