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 .iov_len = sizeof(b) - 1,
59 struct cmsghdr cmsghdr;
60 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
62 struct msghdr msghdr = {
65 .msg_control = &control,
66 .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_errno(errno, "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];
123 _cleanup_free_ char *l = NULL;
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 utmp_wall(l, NULL, NULL);
148 log_error("Failed to allocate wall message");
151 _const_ static usec_t when_wall(usec_t n, usec_t elapse) {
153 static const struct {
157 { 0, USEC_PER_MINUTE },
158 { 10 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE },
159 { USEC_PER_HOUR, 30 * USEC_PER_MINUTE },
160 { 3 * USEC_PER_HOUR, USEC_PER_HOUR },
164 unsigned i = ELEMENTSOF(table) - 1;
166 /* If the time is already passed, then don't announce */
171 while (left < table[i].delay)
173 sub = (left / table[i].interval) * table[i].interval;
175 assert(sub < elapse);
179 static usec_t when_nologin(usec_t elapse) {
180 return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
183 static const char *mode_to_string(enum sd_shutdown_mode m) {
185 case SD_SHUTDOWN_REBOOT:
187 case SD_SHUTDOWN_POWEROFF:
189 case SD_SHUTDOWN_HALT:
191 case SD_SHUTDOWN_KEXEC:
198 static int update_schedule_file(struct sd_shutdown_command *c) {
200 _cleanup_fclose_ FILE *f = NULL;
201 _cleanup_free_ char *t = NULL, *temp_path = NULL;
205 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
207 return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
209 t = cescape(c->wall_message);
213 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
215 return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
217 fchmod(fileno(f), 0644);
225 mode_to_string(c->mode));
228 fputs("DRY_RUN=1\n", f);
231 fprintf(f, "WALL_MESSAGE=%s\n", t);
235 if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
236 log_error_errno(errno, "Failed to write information about scheduled shutdowns: %m");
240 unlink("/run/systemd/shutdown/scheduled");
246 static bool scheduled(struct sd_shutdown_command *c) {
247 return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
250 int main(int argc, char *argv[]) {
259 int r = EXIT_FAILURE, n_fds;
260 union shutdown_buffer b = {};
261 struct pollfd pollfd[_FD_MAX] = {};
262 bool exec_shutdown = false, unlink_nologin = false;
265 if (getppid() != 1) {
266 log_error("This program should be invoked by init only.");
271 log_error("This program does not take arguments.");
275 log_set_target(LOG_TARGET_AUTO);
276 log_parse_environment();
281 n_fds = sd_listen_fds(true);
283 log_error_errno(r, "Failed to read listening file descriptors from environment: %m");
288 log_error("Need exactly one file descriptor.");
292 pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
293 pollfd[FD_SOCKET].events = POLLIN;
295 for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
296 pollfd[i].events = POLLIN;
297 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
298 if (pollfd[i].fd < 0) {
299 log_error_errno(errno, "timerfd_create(): %m");
304 log_debug("systemd-shutdownd running as pid "PID_FMT, getpid());
308 "STATUS=Processing requests...");
314 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
317 if (errno == EAGAIN || errno == EINTR)
320 log_error_errno(errno, "poll(): %m");
328 n = now(CLOCK_REALTIME);
330 if (pollfd[FD_SOCKET].revents) {
332 k = read_packet(pollfd[FD_SOCKET].fd, &b);
336 struct itimerspec its;
337 char date[FORMAT_TIMESTAMP_MAX];
339 if (!scheduled(&b.command)) {
340 log_info("Shutdown canceled.");
341 if (b.command.warn_wall)
342 warn_wall(0, &b.command);
347 if (b.command.warn_wall) {
348 /* Send wall messages every so often */
349 timespec_store(&its.it_value, when_wall(n, b.command.usec));
351 /* Warn immediately if less than 15 minutes are left */
352 if (n < b.command.usec &&
353 n + 15*USEC_PER_MINUTE >= b.command.usec)
354 warn_wall(n, &b.command);
356 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
357 log_error_errno(errno, "timerfd_settime(): %m");
361 /* Disallow logins 5 minutes prior to shutdown */
363 timespec_store(&its.it_value, when_nologin(b.command.usec));
364 if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
365 log_error_errno(errno, "timerfd_settime(): %m");
369 /* Shutdown after the specified time is reached */
371 timespec_store(&its.it_value, b.command.usec);
372 if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
373 log_error_errno(errno, "timerfd_settime(): %m");
377 update_schedule_file(&b.command);
380 "STATUS=Shutting down at %s (%s)...",
381 format_timestamp(date, sizeof(date), b.command.usec),
382 mode_to_string(b.command.mode));
384 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
388 if (pollfd[FD_WALL_TIMER].revents) {
389 struct itimerspec its = {};
391 warn_wall(n, &b.command);
392 flush_fd(pollfd[FD_WALL_TIMER].fd);
395 timespec_store(&its.it_value, when_wall(n, b.command.usec));
396 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
397 log_error_errno(errno, "timerfd_settime(): %m");
402 if (pollfd[FD_NOLOGIN_TIMER].revents) {
405 log_info("Creating /run/nologin, blocking further logins...");
407 e = write_string_file_atomic("/run/nologin", "System is going down.");
409 log_error_errno(e, "Failed to create /run/nologin: %m");
411 unlink_nologin = true;
413 flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
416 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
417 exec_shutdown = true;
424 log_debug("systemd-shutdownd stopped as pid "PID_FMT, getpid());
428 for (i = 0; i < _FD_MAX; i++)
429 safe_close(pollfd[i].fd);
432 unlink("/run/nologin");
434 unlink("/run/systemd/shutdown/scheduled");
436 if (exec_shutdown && !b.command.dry_run) {
440 sw[1] = b.command.mode;
443 execl(SYSTEMCTL_BINARY_PATH,
447 (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
448 (b.command.warn_wall ? NULL : "--no-wall"),
451 log_error_errno(errno, "Failed to execute /sbin/shutdown: %m");
456 "STATUS=Exiting...");