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) {
53 struct cmsghdr cmsghdr;
54 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
57 union shutdown_buffer b; /* We maintain our own copy here, in order not to corrupt the last message */
64 iovec.iov_len = sizeof(b) - 1;
68 msghdr.msg_iov = &iovec;
69 msghdr.msg_iovlen = 1;
70 msghdr.msg_control = &control;
71 msghdr.msg_controllen = sizeof(control);
73 n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
76 log_error("Short read");
80 if (errno == EAGAIN || errno == EINTR)
83 log_error("recvmsg(): %m");
87 if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
88 control.cmsghdr.cmsg_level != SOL_SOCKET ||
89 control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
90 control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
91 log_warning("Received message without credentials. Ignoring.");
95 ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
96 if (ucred->uid != 0) {
97 log_warning("Got request from unprivileged user. Ignoring.");
101 if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) {
102 log_warning("Message has invalid size. Ignoring.");
106 if (b.command.mode != SD_SHUTDOWN_NONE &&
107 b.command.mode != SD_SHUTDOWN_REBOOT &&
108 b.command.mode != SD_SHUTDOWN_POWEROFF &&
109 b.command.mode != SD_SHUTDOWN_HALT &&
110 b.command.mode != SD_SHUTDOWN_KEXEC) {
111 log_warning("Message has invalid mode. Ignoring.");
121 static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
122 char date[FORMAT_TIMESTAMP_MAX];
127 assert(c->warn_wall);
132 if (c->mode == SD_SHUTDOWN_HALT)
133 prefix = "The system is going down for system halt at ";
134 else if (c->mode == SD_SHUTDOWN_POWEROFF)
135 prefix = "The system is going down for power-off at ";
136 else if (c->mode == SD_SHUTDOWN_REBOOT)
137 prefix = "The system is going down for reboot at ";
138 else if (c->mode == SD_SHUTDOWN_KEXEC)
139 prefix = "The system is going down for kexec reboot at ";
140 else if (c->mode == SD_SHUTDOWN_NONE)
141 prefix = "The system shutdown has been cancelled at ";
143 assert_not_reached("Unknown mode!");
145 if (asprintf(&l, "%s%s%s%s!", c->wall_message, c->wall_message[0] ? "\n" : "",
146 prefix, format_timestamp(date, sizeof(date), c->usec)) < 0)
147 log_error("Failed to allocate wall message");
154 static usec_t when_wall(usec_t n, usec_t elapse) {
156 static const struct {
160 { 0, USEC_PER_MINUTE },
161 { 10 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE },
162 { USEC_PER_HOUR, 30 * USEC_PER_MINUTE },
163 { 3 * USEC_PER_HOUR, USEC_PER_HOUR },
167 unsigned i = ELEMENTSOF(table) - 1;
169 /* If the time is already passed, then don't announce */
174 while (left < table[i].delay)
176 sub = (left / table[i].interval) * table[i].interval;
178 assert(sub < elapse);
182 static usec_t when_nologin(usec_t elapse) {
183 return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
186 static const char *mode_to_string(enum sd_shutdown_mode m) {
188 case SD_SHUTDOWN_REBOOT:
190 case SD_SHUTDOWN_POWEROFF:
192 case SD_SHUTDOWN_HALT:
194 case SD_SHUTDOWN_KEXEC:
201 static int update_schedule_file(struct sd_shutdown_command *c) {
208 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
210 log_error("Failed to create shutdown subdirectory: %s", strerror(-r));
214 t = cescape(c->wall_message);
218 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
220 log_error("Failed to save information about scheduled shutdowns: %s", strerror(-r));
225 fchmod(fileno(f), 0644);
231 (unsigned long long) c->usec,
233 mode_to_string(c->mode));
236 fputs("DRY_RUN=1\n", f);
239 fprintf(f, "WALL_MESSAGE=%s\n", t);
245 if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
246 log_error("Failed to write information about scheduled shutdowns: %m");
250 unlink("/run/systemd/shutdown/scheduled");
259 static bool scheduled(struct sd_shutdown_command *c) {
260 return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
263 int main(int argc, char *argv[]) {
272 int r = EXIT_FAILURE, n_fds;
273 union shutdown_buffer b;
274 struct pollfd pollfd[_FD_MAX];
275 bool exec_shutdown = false, unlink_nologin = false;
278 if (getppid() != 1) {
279 log_error("This program should be invoked by init only.");
284 log_error("This program does not take arguments.");
288 log_set_target(LOG_TARGET_AUTO);
289 log_parse_environment();
294 n_fds = sd_listen_fds(true);
296 log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
301 log_error("Need exactly one file descriptor.");
308 pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
309 pollfd[FD_SOCKET].events = POLLIN;
311 for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
312 pollfd[i].events = POLLIN;
313 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
314 if (pollfd[i].fd < 0) {
315 log_error("timerfd_create(): %m");
320 log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid());
324 "STATUS=Processing requests...");
330 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
333 if (errno == EAGAIN || errno == EINTR)
336 log_error("poll(): %m");
344 n = now(CLOCK_REALTIME);
346 if (pollfd[FD_SOCKET].revents) {
348 k = read_packet(pollfd[FD_SOCKET].fd, &b);
352 struct itimerspec its;
353 char date[FORMAT_TIMESTAMP_MAX];
355 if (!scheduled(&b.command)) {
356 log_info("Shutdown canceled.");
357 if (b.command.warn_wall)
358 warn_wall(0, &b.command);
363 if (b.command.warn_wall) {
364 /* Send wall messages every so often */
365 timespec_store(&its.it_value, when_wall(n, b.command.usec));
367 /* Warn immediately if less than 15 minutes are left */
368 if (n < b.command.usec &&
369 n + 15*USEC_PER_MINUTE >= b.command.usec)
370 warn_wall(n, &b.command);
372 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
373 log_error("timerfd_settime(): %m");
377 /* Disallow logins 5 minutes prior to shutdown */
379 timespec_store(&its.it_value, when_nologin(b.command.usec));
380 if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
381 log_error("timerfd_settime(): %m");
385 /* Shutdown after the specified time is reached */
387 timespec_store(&its.it_value, b.command.usec);
388 if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
389 log_error("timerfd_settime(): %m");
393 update_schedule_file(&b.command);
396 "STATUS=Shutting down at %s (%s)...",
397 format_timestamp(date, sizeof(date), b.command.usec),
398 mode_to_string(b.command.mode));
400 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
404 if (pollfd[FD_WALL_TIMER].revents) {
405 struct itimerspec its;
407 warn_wall(n, &b.command);
408 flush_fd(pollfd[FD_WALL_TIMER].fd);
412 timespec_store(&its.it_value, when_wall(n, b.command.usec));
413 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
414 log_error("timerfd_settime(): %m");
419 if (pollfd[FD_NOLOGIN_TIMER].revents) {
422 log_info("Creating /run/nologin, blocking further logins...");
424 e = write_string_file_atomic("/run/nologin", "System is going down.");
426 log_error("Failed to create /run/nologin: %s", strerror(-e));
428 unlink_nologin = true;
430 flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
433 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
434 exec_shutdown = true;
441 log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid());
445 for (i = 0; i < _FD_MAX; i++)
446 if (pollfd[i].fd >= 0)
447 close_nointr_nofail(pollfd[i].fd);
450 unlink("/run/nologin");
452 unlink("/run/systemd/shutdown/scheduled");
454 if (exec_shutdown && !b.command.dry_run) {
458 sw[1] = b.command.mode;
461 execl(SYSTEMCTL_BINARY_PATH,
465 (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
466 (b.command.warn_wall ? NULL : "--no-wall"),
469 log_error("Failed to execute /sbin/shutdown: %m");
473 "STATUS=Exiting...");