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 iovec.iov_len = sizeof(b) - 1,
59 struct cmsghdr cmsghdr;
60 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
62 struct msghdr msghdr = {
64 msghdr.msg_iovlen = 1,
65 msghdr.msg_control = &control,
66 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 _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) {
207 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
209 log_error("Failed to create shutdown subdirectory: %s", strerror(-r));
213 t = cescape(c->wall_message);
217 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
219 log_error("Failed to save information about scheduled shutdowns: %s", strerror(-r));
224 fchmod(fileno(f), 0644);
230 (unsigned long long) c->usec,
232 mode_to_string(c->mode));
235 fputs("DRY_RUN=1\n", f);
238 fprintf(f, "WALL_MESSAGE=%s\n", t);
244 if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
245 log_error("Failed to write information about scheduled shutdowns: %m");
249 unlink("/run/systemd/shutdown/scheduled");
258 static bool scheduled(struct sd_shutdown_command *c) {
259 return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
262 int main(int argc, char *argv[]) {
271 int r = EXIT_FAILURE, n_fds;
272 union shutdown_buffer b = {};
273 struct pollfd pollfd[_FD_MAX] = {};
274 bool exec_shutdown = false, unlink_nologin = false;
277 if (getppid() != 1) {
278 log_error("This program should be invoked by init only.");
283 log_error("This program does not take arguments.");
287 log_set_target(LOG_TARGET_AUTO);
288 log_parse_environment();
293 n_fds = sd_listen_fds(true);
295 log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
300 log_error("Need exactly one file descriptor.");
304 pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
305 pollfd[FD_SOCKET].events = POLLIN;
307 for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
308 pollfd[i].events = POLLIN;
309 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
310 if (pollfd[i].fd < 0) {
311 log_error("timerfd_create(): %m");
316 log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid());
320 "STATUS=Processing requests...");
326 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
329 if (errno == EAGAIN || errno == EINTR)
332 log_error("poll(): %m");
340 n = now(CLOCK_REALTIME);
342 if (pollfd[FD_SOCKET].revents) {
344 k = read_packet(pollfd[FD_SOCKET].fd, &b);
348 struct itimerspec its;
349 char date[FORMAT_TIMESTAMP_MAX];
351 if (!scheduled(&b.command)) {
352 log_info("Shutdown canceled.");
353 if (b.command.warn_wall)
354 warn_wall(0, &b.command);
359 if (b.command.warn_wall) {
360 /* Send wall messages every so often */
361 timespec_store(&its.it_value, when_wall(n, b.command.usec));
363 /* Warn immediately if less than 15 minutes are left */
364 if (n < b.command.usec &&
365 n + 15*USEC_PER_MINUTE >= b.command.usec)
366 warn_wall(n, &b.command);
368 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
369 log_error("timerfd_settime(): %m");
373 /* Disallow logins 5 minutes prior to shutdown */
375 timespec_store(&its.it_value, when_nologin(b.command.usec));
376 if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
377 log_error("timerfd_settime(): %m");
381 /* Shutdown after the specified time is reached */
383 timespec_store(&its.it_value, b.command.usec);
384 if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
385 log_error("timerfd_settime(): %m");
389 update_schedule_file(&b.command);
392 "STATUS=Shutting down at %s (%s)...",
393 format_timestamp(date, sizeof(date), b.command.usec),
394 mode_to_string(b.command.mode));
396 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
400 if (pollfd[FD_WALL_TIMER].revents) {
401 struct itimerspec its = {};
403 warn_wall(n, &b.command);
404 flush_fd(pollfd[FD_WALL_TIMER].fd);
407 timespec_store(&its.it_value, when_wall(n, b.command.usec));
408 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
409 log_error("timerfd_settime(): %m");
414 if (pollfd[FD_NOLOGIN_TIMER].revents) {
417 log_info("Creating /run/nologin, blocking further logins...");
419 e = write_string_file_atomic("/run/nologin", "System is going down.");
421 log_error("Failed to create /run/nologin: %s", strerror(-e));
423 unlink_nologin = true;
425 flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
428 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
429 exec_shutdown = true;
436 log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid());
440 for (i = 0; i < _FD_MAX; i++)
441 if (pollfd[i].fd >= 0)
442 close_nointr_nofail(pollfd[i].fd);
445 unlink("/run/nologin");
447 unlink("/run/systemd/shutdown/scheduled");
449 if (exec_shutdown && !b.command.dry_run) {
453 sw[1] = b.command.mode;
456 execl(SYSTEMCTL_BINARY_PATH,
460 (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
461 (b.command.warn_wall ? NULL : "--no-wall"),
464 log_error("Failed to execute /sbin/shutdown: %m");
468 "STATUS=Exiting...");