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 { 10 * USEC_PER_MINUTE, USEC_PER_MINUTE },
161 { USEC_PER_HOUR, 15 * USEC_PER_MINUTE },
162 { 3 * USEC_PER_HOUR, 30 * USEC_PER_MINUTE }
168 /* If the time is already passed, then don't announce */
173 for (i = 0; i < ELEMENTSOF(table); i++)
174 if (n + table[i].delay >= elapse) {
175 sub = ((left / table[i].interval) * table[i].interval);
179 if (i >= ELEMENTSOF(table))
180 sub = ((left / USEC_PER_HOUR) * USEC_PER_HOUR);
182 return elapse > sub ? elapse - sub : 1;
185 static usec_t when_nologin(usec_t elapse) {
186 return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
189 static const char *mode_to_string(enum sd_shutdown_mode m) {
191 case SD_SHUTDOWN_REBOOT:
193 case SD_SHUTDOWN_POWEROFF:
195 case SD_SHUTDOWN_HALT:
197 case SD_SHUTDOWN_KEXEC:
204 static int update_schedule_file(struct sd_shutdown_command *c) {
211 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
213 log_error("Failed to create shutdown subdirectory: %s", strerror(-r));
217 t = cescape(c->wall_message);
221 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
223 log_error("Failed to save information about scheduled shutdowns: %s", strerror(-r));
228 fchmod(fileno(f), 0644);
234 (unsigned long long) c->usec,
236 mode_to_string(c->mode));
239 fputs("DRY_RUN=1\n", f);
242 fprintf(f, "WALL_MESSAGE=%s\n", t);
248 if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
249 log_error("Failed to write information about scheduled shutdowns: %m");
253 unlink("/run/systemd/shutdown/scheduled");
262 static bool scheduled(struct sd_shutdown_command *c) {
263 return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
266 int main(int argc, char *argv[]) {
275 int r = EXIT_FAILURE, n_fds;
276 union shutdown_buffer b;
277 struct pollfd pollfd[_FD_MAX];
278 bool exec_shutdown = false, unlink_nologin = false;
281 if (getppid() != 1) {
282 log_error("This program should be invoked by init only.");
287 log_error("This program does not take arguments.");
291 log_set_target(LOG_TARGET_AUTO);
292 log_parse_environment();
297 n_fds = sd_listen_fds(true);
299 log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
304 log_error("Need exactly one file descriptor.");
311 pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
312 pollfd[FD_SOCKET].events = POLLIN;
314 for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
315 pollfd[i].events = POLLIN;
316 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
317 if (pollfd[i].fd < 0) {
318 log_error("timerfd_create(): %m");
323 log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid());
327 "STATUS=Processing requests...");
333 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
336 if (errno == EAGAIN || errno == EINTR)
339 log_error("poll(): %m");
347 n = now(CLOCK_REALTIME);
349 if (pollfd[FD_SOCKET].revents) {
351 k = read_packet(pollfd[FD_SOCKET].fd, &b);
355 struct itimerspec its;
356 char date[FORMAT_TIMESTAMP_MAX];
358 if (!scheduled(&b.command)) {
359 log_info("Shutdown canceled.");
360 if (b.command.warn_wall)
361 warn_wall(0, &b.command);
366 if (b.command.warn_wall) {
367 /* Send wall messages every so often */
368 timespec_store(&its.it_value, when_wall(n, b.command.usec));
370 /* Warn immediately if less than 15 minutes are left */
371 if (n < b.command.usec &&
372 n + 15*USEC_PER_MINUTE >= b.command.usec)
373 warn_wall(n, &b.command);
375 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
376 log_error("timerfd_settime(): %m");
380 /* Disallow logins 5 minutes prior to shutdown */
382 timespec_store(&its.it_value, when_nologin(b.command.usec));
383 if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
384 log_error("timerfd_settime(): %m");
388 /* Shutdown after the specified time is reached */
390 timespec_store(&its.it_value, b.command.usec);
391 if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
392 log_error("timerfd_settime(): %m");
396 update_schedule_file(&b.command);
399 "STATUS=Shutting down at %s (%s)...",
400 format_timestamp(date, sizeof(date), b.command.usec),
401 mode_to_string(b.command.mode));
403 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
407 if (pollfd[FD_WALL_TIMER].revents) {
408 struct itimerspec its;
410 warn_wall(n, &b.command);
411 flush_fd(pollfd[FD_WALL_TIMER].fd);
415 timespec_store(&its.it_value, when_wall(n, b.command.usec));
416 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
417 log_error("timerfd_settime(): %m");
422 if (pollfd[FD_NOLOGIN_TIMER].revents) {
425 log_info("Creating /run/nologin, blocking further logins...");
427 e = write_one_line_file_atomic("/run/nologin", "System is going down.");
429 log_error("Failed to create /run/nologin: %s", strerror(-e));
431 unlink_nologin = true;
433 flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
436 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
437 exec_shutdown = true;
444 log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid());
448 for (i = 0; i < _FD_MAX; i++)
449 if (pollfd[i].fd >= 0)
450 close_nointr_nofail(pollfd[i].fd);
453 unlink("/run/nologin");
455 unlink("/run/systemd/shutdown/scheduled");
457 if (exec_shutdown && !b.command.dry_run) {
461 sw[1] = b.command.mode;
464 execl(SYSTEMCTL_BINARY_PATH,
468 (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
469 (b.command.warn_wall ? NULL : "--no-wall"),
472 log_error("Failed to execute /sbin/shutdown: %m");
476 "STATUS=Exiting...");