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 = {
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("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 log_error("Failed to create shutdown subdirectory: %s", strerror(-r));
211 t = cescape(c->wall_message);
215 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
217 log_error("Failed to save information about scheduled shutdowns: %s", strerror(-r));
221 fchmod(fileno(f), 0644);
229 mode_to_string(c->mode));
232 fputs("DRY_RUN=1\n", f);
235 fprintf(f, "WALL_MESSAGE=%s\n", t);
239 if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
240 log_error("Failed to write information about scheduled shutdowns: %m");
244 unlink("/run/systemd/shutdown/scheduled");
250 static bool scheduled(struct sd_shutdown_command *c) {
251 return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
254 int main(int argc, char *argv[]) {
263 int r = EXIT_FAILURE, n_fds;
264 union shutdown_buffer b = {};
265 struct pollfd pollfd[_FD_MAX] = {};
266 bool exec_shutdown = false, unlink_nologin = false;
269 if (getppid() != 1) {
270 log_error("This program should be invoked by init only.");
275 log_error("This program does not take arguments.");
279 log_set_target(LOG_TARGET_AUTO);
280 log_parse_environment();
285 n_fds = sd_listen_fds(true);
287 log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
292 log_error("Need exactly one file descriptor.");
296 pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
297 pollfd[FD_SOCKET].events = POLLIN;
299 for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
300 pollfd[i].events = POLLIN;
301 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
302 if (pollfd[i].fd < 0) {
303 log_error("timerfd_create(): %m");
308 log_debug("systemd-shutdownd running as pid "PID_FMT, getpid());
312 "STATUS=Processing requests...");
318 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
321 if (errno == EAGAIN || errno == EINTR)
324 log_error("poll(): %m");
332 n = now(CLOCK_REALTIME);
334 if (pollfd[FD_SOCKET].revents) {
336 k = read_packet(pollfd[FD_SOCKET].fd, &b);
340 struct itimerspec its;
341 char date[FORMAT_TIMESTAMP_MAX];
343 if (!scheduled(&b.command)) {
344 log_info("Shutdown canceled.");
345 if (b.command.warn_wall)
346 warn_wall(0, &b.command);
351 if (b.command.warn_wall) {
352 /* Send wall messages every so often */
353 timespec_store(&its.it_value, when_wall(n, b.command.usec));
355 /* Warn immediately if less than 15 minutes are left */
356 if (n < b.command.usec &&
357 n + 15*USEC_PER_MINUTE >= b.command.usec)
358 warn_wall(n, &b.command);
360 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
361 log_error("timerfd_settime(): %m");
365 /* Disallow logins 5 minutes prior to shutdown */
367 timespec_store(&its.it_value, when_nologin(b.command.usec));
368 if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
369 log_error("timerfd_settime(): %m");
373 /* Shutdown after the specified time is reached */
375 timespec_store(&its.it_value, b.command.usec);
376 if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
377 log_error("timerfd_settime(): %m");
381 update_schedule_file(&b.command);
384 "STATUS=Shutting down at %s (%s)...",
385 format_timestamp(date, sizeof(date), b.command.usec),
386 mode_to_string(b.command.mode));
388 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
392 if (pollfd[FD_WALL_TIMER].revents) {
393 struct itimerspec its = {};
395 warn_wall(n, &b.command);
396 flush_fd(pollfd[FD_WALL_TIMER].fd);
399 timespec_store(&its.it_value, when_wall(n, b.command.usec));
400 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
401 log_error("timerfd_settime(): %m");
406 if (pollfd[FD_NOLOGIN_TIMER].revents) {
409 log_info("Creating /run/nologin, blocking further logins...");
411 e = write_string_file_atomic("/run/nologin", "System is going down.");
413 log_error("Failed to create /run/nologin: %s", strerror(-e));
415 unlink_nologin = true;
417 flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
420 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
421 exec_shutdown = true;
428 log_debug("systemd-shutdownd stopped as pid "PID_FMT, getpid());
432 for (i = 0; i < _FD_MAX; i++)
433 safe_close(pollfd[i].fd);
436 unlink("/run/nologin");
438 unlink("/run/systemd/shutdown/scheduled");
440 if (exec_shutdown && !b.command.dry_run) {
444 sw[1] = b.command.mode;
447 execl(SYSTEMCTL_BINARY_PATH,
451 (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
452 (b.command.warn_wall ? NULL : "--no-wall"),
455 log_error("Failed to execute /sbin/shutdown: %m");
459 "STATUS=Exiting...");