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/timerfd.h>
29 #include "systemd/sd-daemon.h"
30 #include "systemd/sd-shutdown.h"
35 #include "utmp-wtmp.h"
39 union shutdown_buffer {
40 struct sd_shutdown_command command;
41 char space[offsetof(struct sd_shutdown_command, wall_message) + LINE_MAX];
44 static int read_packet(int fd, union shutdown_buffer *_b) {
48 union shutdown_buffer b; /* We maintain our own copy here, in
49 * order not to corrupt the last message */
50 struct iovec iovec = {
52 .iov_len = sizeof(b) - 1,
55 struct cmsghdr cmsghdr;
56 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
58 struct msghdr msghdr = {
61 .msg_control = &control,
62 .msg_controllen = sizeof(control),
68 n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
70 if (errno == EAGAIN || errno == EINTR)
73 log_error_errno(errno, "recvmsg(): %m");
77 cmsg_close_all(&msghdr);
80 log_error("Short read");
84 if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
85 control.cmsghdr.cmsg_level != SOL_SOCKET ||
86 control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
87 control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
88 log_warning("Received message without credentials. Ignoring.");
92 ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
93 if (ucred->uid != 0) {
94 log_warning("Got request from unprivileged user. Ignoring.");
98 if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) {
99 log_warning("Message has invalid size. Ignoring.");
103 if (b.command.mode != SD_SHUTDOWN_NONE &&
104 b.command.mode != SD_SHUTDOWN_REBOOT &&
105 b.command.mode != SD_SHUTDOWN_POWEROFF &&
106 b.command.mode != SD_SHUTDOWN_HALT &&
107 b.command.mode != SD_SHUTDOWN_KEXEC) {
108 log_warning("Message has invalid mode. Ignoring.");
118 static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
119 char date[FORMAT_TIMESTAMP_MAX];
121 _cleanup_free_ char *l = NULL;
124 assert(c->warn_wall);
129 if (c->mode == SD_SHUTDOWN_HALT)
130 prefix = "The system is going down for system halt at ";
131 else if (c->mode == SD_SHUTDOWN_POWEROFF)
132 prefix = "The system is going down for power-off at ";
133 else if (c->mode == SD_SHUTDOWN_REBOOT)
134 prefix = "The system is going down for reboot at ";
135 else if (c->mode == SD_SHUTDOWN_KEXEC)
136 prefix = "The system is going down for kexec reboot at ";
137 else if (c->mode == SD_SHUTDOWN_NONE)
138 prefix = "The system shutdown has been cancelled at ";
140 assert_not_reached("Unknown mode!");
142 if (asprintf(&l, "%s%s%s%s!", c->wall_message, c->wall_message[0] ? "\n" : "",
143 prefix, format_timestamp(date, sizeof(date), c->usec)) >= 0)
144 utmp_wall(l, NULL, NULL);
146 log_error("Failed to allocate wall message");
149 _const_ static usec_t when_wall(usec_t n, usec_t elapse) {
151 static const struct {
155 { 0, USEC_PER_MINUTE },
156 { 10 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE },
157 { USEC_PER_HOUR, 30 * USEC_PER_MINUTE },
158 { 3 * USEC_PER_HOUR, USEC_PER_HOUR },
162 unsigned i = ELEMENTSOF(table) - 1;
164 /* If the time is already passed, then don't announce */
169 while (left < table[i].delay)
171 sub = (left / table[i].interval) * table[i].interval;
173 assert(sub < elapse);
177 static usec_t when_nologin(usec_t elapse) {
178 return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
181 static const char *mode_to_string(enum sd_shutdown_mode m) {
183 case SD_SHUTDOWN_REBOOT:
185 case SD_SHUTDOWN_POWEROFF:
187 case SD_SHUTDOWN_HALT:
189 case SD_SHUTDOWN_KEXEC:
196 static int update_schedule_file(struct sd_shutdown_command *c) {
198 _cleanup_fclose_ FILE *f = NULL;
199 _cleanup_free_ char *t = NULL, *temp_path = NULL;
203 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
205 return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
207 t = cescape(c->wall_message);
211 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
213 return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
215 fchmod(fileno(f), 0644);
223 mode_to_string(c->mode));
226 fputs("DRY_RUN=1\n", f);
229 fprintf(f, "WALL_MESSAGE=%s\n", t);
233 if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
234 log_error_errno(errno, "Failed to write information about scheduled shutdowns: %m");
238 unlink("/run/systemd/shutdown/scheduled");
244 static bool scheduled(struct sd_shutdown_command *c) {
245 return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
248 int main(int argc, char *argv[]) {
257 int r = EXIT_FAILURE, n_fds;
258 union shutdown_buffer b = {};
259 struct pollfd pollfd[_FD_MAX] = {};
260 bool exec_shutdown = false, unlink_nologin = false;
263 if (getppid() != 1) {
264 log_error("This program should be invoked by init only.");
269 log_error("This program does not take arguments.");
273 log_set_target(LOG_TARGET_AUTO);
274 log_parse_environment();
279 n_fds = sd_listen_fds(true);
281 log_error_errno(r, "Failed to read listening file descriptors from environment: %m");
286 log_error("Need exactly one file descriptor.");
290 pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
291 pollfd[FD_SOCKET].events = POLLIN;
293 for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
294 pollfd[i].events = POLLIN;
295 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
296 if (pollfd[i].fd < 0) {
297 log_error_errno(errno, "timerfd_create(): %m");
302 log_debug("systemd-shutdownd running as pid "PID_FMT, getpid());
306 "STATUS=Processing requests...");
312 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
315 if (errno == EAGAIN || errno == EINTR)
318 log_error_errno(errno, "poll(): %m");
326 n = now(CLOCK_REALTIME);
328 if (pollfd[FD_SOCKET].revents) {
330 k = read_packet(pollfd[FD_SOCKET].fd, &b);
334 struct itimerspec its;
335 char date[FORMAT_TIMESTAMP_MAX];
337 if (!scheduled(&b.command)) {
338 log_info("Shutdown canceled.");
339 if (b.command.warn_wall)
340 warn_wall(0, &b.command);
345 if (b.command.warn_wall) {
346 /* Send wall messages every so often */
347 timespec_store(&its.it_value, when_wall(n, b.command.usec));
349 /* Warn immediately if less than 15 minutes are left */
350 if (n < b.command.usec &&
351 n + 15*USEC_PER_MINUTE >= b.command.usec)
352 warn_wall(n, &b.command);
354 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
355 log_error_errno(errno, "timerfd_settime(): %m");
359 /* Disallow logins 5 minutes prior to shutdown */
361 timespec_store(&its.it_value, when_nologin(b.command.usec));
362 if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
363 log_error_errno(errno, "timerfd_settime(): %m");
367 /* Shutdown after the specified time is reached */
369 timespec_store(&its.it_value, b.command.usec);
370 if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
371 log_error_errno(errno, "timerfd_settime(): %m");
375 update_schedule_file(&b.command);
378 "STATUS=Shutting down at %s (%s)...",
379 format_timestamp(date, sizeof(date), b.command.usec),
380 mode_to_string(b.command.mode));
382 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
386 if (pollfd[FD_WALL_TIMER].revents) {
387 struct itimerspec its = {};
389 warn_wall(n, &b.command);
390 flush_fd(pollfd[FD_WALL_TIMER].fd);
393 timespec_store(&its.it_value, when_wall(n, b.command.usec));
394 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
395 log_error_errno(errno, "timerfd_settime(): %m");
400 if (pollfd[FD_NOLOGIN_TIMER].revents) {
403 log_info("Creating /run/nologin, blocking further logins...");
405 e = write_string_file_atomic("/run/nologin", "System is going down.");
407 log_error_errno(e, "Failed to create /run/nologin: %m");
409 unlink_nologin = true;
411 flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
414 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
415 exec_shutdown = true;
422 log_debug("systemd-shutdownd stopped as pid "PID_FMT, getpid());
426 for (i = 0; i < _FD_MAX; i++)
427 safe_close(pollfd[i].fd);
430 unlink("/run/nologin");
432 unlink("/run/systemd/shutdown/scheduled");
434 if (exec_shutdown && !b.command.dry_run) {
438 sw[1] = b.command.mode;
441 execl(SYSTEMCTL_BINARY_PATH,
445 (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
446 (b.command.warn_wall ? NULL : "--no-wall"),
449 log_error_errno(errno, "Failed to execute /sbin/shutdown: %m");
454 "STATUS=Exiting...");