1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
22 #include <sys/socket.h>
24 #include <sys/types.h>
25 #include <sys/timerfd.h>
33 #include "systemd/sd-daemon.h"
34 #include "systemd/sd-shutdown.h"
39 #include "utmp-wtmp.h"
43 union shutdown_buffer {
44 struct sd_shutdown_command command;
45 char space[offsetof(struct sd_shutdown_command, wall_message) + LINE_MAX];
48 static int read_packet(int fd, union shutdown_buffer *_b) {
52 union shutdown_buffer b; /* We maintain our own copy here, in
53 * order not to corrupt the last message */
54 struct iovec iovec = {
56 .iov_len = sizeof(b) - 1,
59 struct cmsghdr cmsghdr;
60 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
62 struct msghdr msghdr = {
65 .msg_control = &control,
66 .msg_controllen = sizeof(control),
72 n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
74 if (errno == EAGAIN || errno == EINTR)
77 log_error_errno(errno, "recvmsg(): %m");
81 cmsg_close_all(&msghdr);
84 log_error("Short read");
88 if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
89 control.cmsghdr.cmsg_level != SOL_SOCKET ||
90 control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
91 control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
92 log_warning("Received message without credentials. Ignoring.");
96 ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
97 if (ucred->uid != 0) {
98 log_warning("Got request from unprivileged user. Ignoring.");
102 if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) {
103 log_warning("Message has invalid size. Ignoring.");
107 if (b.command.mode != SD_SHUTDOWN_NONE &&
108 b.command.mode != SD_SHUTDOWN_REBOOT &&
109 b.command.mode != SD_SHUTDOWN_POWEROFF &&
110 b.command.mode != SD_SHUTDOWN_HALT &&
111 b.command.mode != SD_SHUTDOWN_KEXEC) {
112 log_warning("Message has invalid mode. Ignoring.");
122 static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
123 char date[FORMAT_TIMESTAMP_MAX];
125 _cleanup_free_ char *l = NULL;
128 assert(c->warn_wall);
133 if (c->mode == SD_SHUTDOWN_HALT)
134 prefix = "The system is going down for system halt at ";
135 else if (c->mode == SD_SHUTDOWN_POWEROFF)
136 prefix = "The system is going down for power-off at ";
137 else if (c->mode == SD_SHUTDOWN_REBOOT)
138 prefix = "The system is going down for reboot at ";
139 else if (c->mode == SD_SHUTDOWN_KEXEC)
140 prefix = "The system is going down for kexec reboot at ";
141 else if (c->mode == SD_SHUTDOWN_NONE)
142 prefix = "The system shutdown has been cancelled at ";
144 assert_not_reached("Unknown mode!");
146 if (asprintf(&l, "%s%s%s%s!", c->wall_message, c->wall_message[0] ? "\n" : "",
147 prefix, format_timestamp(date, sizeof(date), c->usec)) >= 0)
148 utmp_wall(l, NULL, NULL);
150 log_error("Failed to allocate wall message");
153 _const_ static usec_t when_wall(usec_t n, usec_t elapse) {
155 static const struct {
159 { 0, USEC_PER_MINUTE },
160 { 10 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE },
161 { USEC_PER_HOUR, 30 * USEC_PER_MINUTE },
162 { 3 * USEC_PER_HOUR, USEC_PER_HOUR },
166 unsigned i = ELEMENTSOF(table) - 1;
168 /* If the time is already passed, then don't announce */
173 while (left < table[i].delay)
175 sub = (left / table[i].interval) * table[i].interval;
177 assert(sub < elapse);
181 static usec_t when_nologin(usec_t elapse) {
182 return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
185 static const char *mode_to_string(enum sd_shutdown_mode m) {
187 case SD_SHUTDOWN_REBOOT:
189 case SD_SHUTDOWN_POWEROFF:
191 case SD_SHUTDOWN_HALT:
193 case SD_SHUTDOWN_KEXEC:
200 static int update_schedule_file(struct sd_shutdown_command *c) {
202 _cleanup_fclose_ FILE *f = NULL;
203 _cleanup_free_ char *t = NULL, *temp_path = NULL;
207 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
209 return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
211 t = cescape(c->wall_message);
215 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
217 return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
219 fchmod(fileno(f), 0644);
227 mode_to_string(c->mode));
230 fputs("DRY_RUN=1\n", f);
233 fprintf(f, "WALL_MESSAGE=%s\n", t);
237 if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
238 log_error_errno(errno, "Failed to write information about scheduled shutdowns: %m");
242 unlink("/run/systemd/shutdown/scheduled");
248 static bool scheduled(struct sd_shutdown_command *c) {
249 return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
252 int main(int argc, char *argv[]) {
261 int r = EXIT_FAILURE, n_fds;
262 union shutdown_buffer b = {};
263 struct pollfd pollfd[_FD_MAX] = {};
264 bool exec_shutdown = false, unlink_nologin = false;
267 if (getppid() != 1) {
268 log_error("This program should be invoked by init only.");
273 log_error("This program does not take arguments.");
277 log_set_target(LOG_TARGET_AUTO);
278 log_parse_environment();
283 n_fds = sd_listen_fds(true);
285 log_error_errno(r, "Failed to read listening file descriptors from environment: %m");
290 log_error("Need exactly one file descriptor.");
294 pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
295 pollfd[FD_SOCKET].events = POLLIN;
297 for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
298 pollfd[i].events = POLLIN;
299 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
300 if (pollfd[i].fd < 0) {
301 log_error_errno(errno, "timerfd_create(): %m");
306 log_debug("systemd-shutdownd running as pid "PID_FMT, getpid());
310 "STATUS=Processing requests...");
316 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
319 if (errno == EAGAIN || errno == EINTR)
322 log_error_errno(errno, "poll(): %m");
330 n = now(CLOCK_REALTIME);
332 if (pollfd[FD_SOCKET].revents) {
334 k = read_packet(pollfd[FD_SOCKET].fd, &b);
338 struct itimerspec its;
339 char date[FORMAT_TIMESTAMP_MAX];
341 if (!scheduled(&b.command)) {
342 log_info("Shutdown canceled.");
343 if (b.command.warn_wall)
344 warn_wall(0, &b.command);
349 if (b.command.warn_wall) {
350 /* Send wall messages every so often */
351 timespec_store(&its.it_value, when_wall(n, b.command.usec));
353 /* Warn immediately if less than 15 minutes are left */
354 if (n < b.command.usec &&
355 n + 15*USEC_PER_MINUTE >= b.command.usec)
356 warn_wall(n, &b.command);
358 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
359 log_error_errno(errno, "timerfd_settime(): %m");
363 /* Disallow logins 5 minutes prior to shutdown */
365 timespec_store(&its.it_value, when_nologin(b.command.usec));
366 if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
367 log_error_errno(errno, "timerfd_settime(): %m");
371 /* Shutdown after the specified time is reached */
373 timespec_store(&its.it_value, b.command.usec);
374 if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
375 log_error_errno(errno, "timerfd_settime(): %m");
379 update_schedule_file(&b.command);
382 "STATUS=Shutting down at %s (%s)...",
383 format_timestamp(date, sizeof(date), b.command.usec),
384 mode_to_string(b.command.mode));
386 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
390 if (pollfd[FD_WALL_TIMER].revents) {
391 struct itimerspec its = {};
393 warn_wall(n, &b.command);
394 flush_fd(pollfd[FD_WALL_TIMER].fd);
397 timespec_store(&its.it_value, when_wall(n, b.command.usec));
398 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
399 log_error_errno(errno, "timerfd_settime(): %m");
404 if (pollfd[FD_NOLOGIN_TIMER].revents) {
407 log_info("Creating /run/nologin, blocking further logins...");
409 e = write_string_file_atomic("/run/nologin", "System is going down.");
411 log_error_errno(e, "Failed to create /run/nologin: %m");
413 unlink_nologin = true;
415 flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
418 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
419 exec_shutdown = true;
426 log_debug("systemd-shutdownd stopped as pid "PID_FMT, getpid());
430 for (i = 0; i < _FD_MAX; i++)
431 safe_close(pollfd[i].fd);
434 unlink("/run/nologin");
436 unlink("/run/systemd/shutdown/scheduled");
438 if (exec_shutdown && !b.command.dry_run) {
442 sw[1] = b.command.mode;
445 execl(SYSTEMCTL_BINARY_PATH,
449 (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
450 (b.command.warn_wall ? NULL : "--no-wall"),
453 log_error_errno(errno, "Failed to execute /sbin/shutdown: %m");
458 "STATUS=Exiting...");