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"
42 union shutdown_buffer {
43 struct sd_shutdown_command command;
44 char space[offsetof(struct sd_shutdown_command, wall_message) + LINE_MAX];
47 static int read_packet(int fd, union shutdown_buffer *_b) {
52 struct cmsghdr cmsghdr;
53 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
56 union shutdown_buffer b; /* We maintain our own copy here, in order not to corrupt the last message */
63 iovec.iov_len = sizeof(b) - 1;
67 msghdr.msg_iov = &iovec;
68 msghdr.msg_iovlen = 1;
69 msghdr.msg_control = &control;
70 msghdr.msg_controllen = sizeof(control);
72 n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
75 log_error("Short read");
79 if (errno == EAGAIN || errno == EINTR)
82 log_error("recvmsg(): %m");
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.");
94 ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
95 if (ucred->uid != 0) {
96 log_warning("Got request from unprivileged user. Ignoring.");
100 if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) {
101 log_warning("Message has invalid size. Ignoring.");
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.");
120 static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
121 char date[FORMAT_TIMESTAMP_MAX];
126 assert(c->warn_wall);
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 ";
142 assert_not_reached("Unknown mode!");
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 log_error("Failed to allocate wall message");
153 static usec_t when_wall(usec_t n, usec_t elapse) {
155 static const struct {
159 { 10 * USEC_PER_MINUTE, USEC_PER_MINUTE },
160 { USEC_PER_HOUR, 15 * USEC_PER_MINUTE },
161 { 3 * USEC_PER_HOUR, 30 * USEC_PER_MINUTE }
167 /* If the time is already passed, then don't announce */
172 for (i = 0; i < ELEMENTSOF(table); i++)
173 if (n + table[i].delay >= elapse) {
174 sub = ((left / table[i].interval) * table[i].interval);
178 if (i >= ELEMENTSOF(table))
179 sub = ((left / USEC_PER_HOUR) * USEC_PER_HOUR);
181 return elapse > sub ? elapse - sub : 1;
184 static usec_t when_nologin(usec_t elapse) {
185 return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
188 static const char *mode_to_string(enum sd_shutdown_mode m) {
190 case SD_SHUTDOWN_REBOOT:
192 case SD_SHUTDOWN_POWEROFF:
194 case SD_SHUTDOWN_HALT:
196 case SD_SHUTDOWN_KEXEC:
203 static int update_schedule_file(struct sd_shutdown_command *c) {
210 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
212 log_error("Failed to create shutdown subdirectory: %s", strerror(-r));
216 t = cescape(c->wall_message);
220 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
222 log_error("Failed to save information about scheduled shutdowns: %s", strerror(-r));
227 fchmod(fileno(f), 0644);
233 (unsigned long long) c->usec,
235 mode_to_string(c->mode));
238 fputs("DRY_RUN=1\n", f);
241 fprintf(f, "WALL_MESSAGE=%s\n", t);
247 if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
248 log_error("Failed to write information about scheduled shutdowns: %m");
252 unlink("/run/systemd/shutdown/scheduled");
261 static bool scheduled(struct sd_shutdown_command *c) {
262 return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
265 int main(int argc, char *argv[]) {
274 int r = EXIT_FAILURE, n_fds;
275 union shutdown_buffer b;
276 struct pollfd pollfd[_FD_MAX];
277 bool exec_shutdown = false, unlink_nologin = false;
280 if (getppid() != 1) {
281 log_error("This program should be invoked by init only.");
286 log_error("This program does not take arguments.");
290 log_set_target(LOG_TARGET_AUTO);
291 log_parse_environment();
296 n_fds = sd_listen_fds(true);
298 log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
303 log_error("Need exactly one file descriptor.");
310 pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
311 pollfd[FD_SOCKET].events = POLLIN;
313 for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
314 pollfd[i].events = POLLIN;
315 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
316 if (pollfd[i].fd < 0) {
317 log_error("timerfd_create(): %m");
322 log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid());
326 "STATUS=Processing requests...");
332 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
335 if (errno == EAGAIN || errno == EINTR)
338 log_error("poll(): %m");
346 n = now(CLOCK_REALTIME);
348 if (pollfd[FD_SOCKET].revents) {
350 k = read_packet(pollfd[FD_SOCKET].fd, &b);
354 struct itimerspec its;
355 char date[FORMAT_TIMESTAMP_MAX];
357 if (!scheduled(&b.command)) {
358 log_info("Shutdown canceled.");
359 if (b.command.warn_wall)
360 warn_wall(0, &b.command);
365 if (b.command.warn_wall) {
366 /* Send wall messages every so often */
367 timespec_store(&its.it_value, when_wall(n, b.command.usec));
369 /* Warn immediately if less than 15 minutes are left */
370 if (n < b.command.usec &&
371 n + 15*USEC_PER_MINUTE >= b.command.usec)
372 warn_wall(n, &b.command);
374 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
375 log_error("timerfd_settime(): %m");
379 /* Disallow logins 5 minutes prior to shutdown */
381 timespec_store(&its.it_value, when_nologin(b.command.usec));
382 if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
383 log_error("timerfd_settime(): %m");
387 /* Shutdown after the specified time is reached */
389 timespec_store(&its.it_value, b.command.usec);
390 if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
391 log_error("timerfd_settime(): %m");
395 update_schedule_file(&b.command);
398 "STATUS=Shutting down at %s (%s)...",
399 format_timestamp(date, sizeof(date), b.command.usec),
400 mode_to_string(b.command.mode));
402 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
406 if (pollfd[FD_WALL_TIMER].revents) {
407 struct itimerspec its;
409 warn_wall(n, &b.command);
410 flush_fd(pollfd[FD_WALL_TIMER].fd);
414 timespec_store(&its.it_value, when_wall(n, b.command.usec));
415 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
416 log_error("timerfd_settime(): %m");
421 if (pollfd[FD_NOLOGIN_TIMER].revents) {
424 log_info("Creating /run/nologin, blocking further logins...");
426 e = write_one_line_file_atomic("/run/nologin", "System is going down.");
428 log_error("Failed to create /run/nologin: %s", strerror(-e));
430 unlink_nologin = true;
432 flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
435 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
436 exec_shutdown = true;
443 log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid());
447 for (i = 0; i < _FD_MAX; i++)
448 if (pollfd[i].fd >= 0)
449 close_nointr_nofail(pollfd[i].fd);
452 unlink("/run/nologin");
454 unlink("/run/systemd/shutdown/scheduled");
456 if (exec_shutdown && !b.command.dry_run) {
460 sw[1] = b.command.mode;
463 execl(SYSTEMCTL_BINARY_PATH,
467 (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
468 (b.command.warn_wall ? NULL : "--no-wall"),
471 log_error("Failed to execute /sbin/shutdown: %m");
475 "STATUS=Exiting...");