]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shutdownd/shutdownd.c
use "Out of memory." consistantly (or with "\n")
[thirdparty/systemd.git] / src / shutdownd / shutdownd.c
CommitLineData
f6144808
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
f6144808
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
f6144808 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
f6144808
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <sys/socket.h>
23#include <sys/poll.h>
24#include <sys/types.h>
25#include <sys/timerfd.h>
26#include <assert.h>
27#include <string.h>
28#include <errno.h>
29#include <unistd.h>
30#include <fcntl.h>
04ebb595 31#include <stddef.h>
f6144808 32
81527be1 33#include <systemd/sd-daemon.h>
04ebb595 34#include <systemd/sd-shutdown.h>
81527be1 35
f6144808
LP
36#include "log.h"
37#include "macro.h"
38#include "util.h"
9be9828c 39#include "utmp-wtmp.h"
04ebb595 40#include "mkdir.h"
f6144808 41
04ebb595
LP
42union shutdown_buffer {
43 struct sd_shutdown_command command;
44 char space[offsetof(struct sd_shutdown_command, wall_message) + LINE_MAX];
45};
46
47static int read_packet(int fd, union shutdown_buffer *_b) {
f6144808
LP
48 struct msghdr msghdr;
49 struct iovec iovec;
50 struct ucred *ucred;
51 union {
52 struct cmsghdr cmsghdr;
53 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
54 } control;
f6144808 55 ssize_t n;
04ebb595 56 union shutdown_buffer b; /* We maintain our own copy here, in order not to corrupt the last message */
f6144808
LP
57
58 assert(fd >= 0);
04ebb595 59 assert(_b);
f6144808
LP
60
61 zero(iovec);
04ebb595
LP
62 iovec.iov_base = &b;
63 iovec.iov_len = sizeof(b) - 1;
f6144808
LP
64
65 zero(control);
66 zero(msghdr);
67 msghdr.msg_iov = &iovec;
68 msghdr.msg_iovlen = 1;
69 msghdr.msg_control = &control;
70 msghdr.msg_controllen = sizeof(control);
71
04ebb595
LP
72 n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
73 if (n <= 0) {
74 if (n == 0) {
f6144808
LP
75 log_error("Short read");
76 return -EIO;
77 }
78
79 if (errno == EAGAIN || errno == EINTR)
80 return 0;
81
82 log_error("recvmsg(): %m");
83 return -errno;
84 }
85
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.");
91 return 0;
92 }
93
94 ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
95 if (ucred->uid != 0) {
96 log_warning("Got request from unprivileged user. Ignoring.");
97 return 0;
98 }
99
04ebb595
LP
100 if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) {
101 log_warning("Message has invalid size. Ignoring.");
102 return 0;
103 }
104
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.");
f6144808
LP
111 return 0;
112 }
113
04ebb595 114 b.space[n] = 0;
9be9828c 115
04ebb595 116 *_b = b;
f6144808
LP
117 return 1;
118}
119
04ebb595 120static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
30923233
MS
121 char date[FORMAT_TIMESTAMP_MAX];
122 const char *prefix;
123 char *l = NULL;
9be9828c
LP
124
125 assert(c);
126 assert(c->warn_wall);
127
04ebb595 128 if (n >= c->usec)
08e4b1c5
LP
129 return;
130
04ebb595 131 if (c->mode == SD_SHUTDOWN_HALT)
30923233 132 prefix = "The system is going down for system halt at ";
04ebb595 133 else if (c->mode == SD_SHUTDOWN_POWEROFF)
30923233 134 prefix = "The system is going down for power-off at ";
04ebb595 135 else if (c->mode == SD_SHUTDOWN_REBOOT)
30923233 136 prefix = "The system is going down for reboot at ";
04ebb595
LP
137 else if (c->mode == SD_SHUTDOWN_KEXEC)
138 prefix = "The system is going down for kexec reboot at ";
30923233
MS
139 else
140 assert_not_reached("Unknown mode!");
141
142 if (asprintf(&l, "%s%s%s%s!", c->wall_message, c->wall_message[0] ? "\n" : "",
04ebb595 143 prefix, format_timestamp(date, sizeof(date), c->usec)) < 0)
30923233 144 log_error("Failed to allocate wall message");
9be9828c 145 else {
30923233
MS
146 utmp_wall(l, NULL);
147 free(l);
9be9828c
LP
148 }
149}
150
151static usec_t when_wall(usec_t n, usec_t elapse) {
152
153 static const struct {
154 usec_t delay;
155 usec_t interval;
156 } table[] = {
157 { 10 * USEC_PER_MINUTE, USEC_PER_MINUTE },
158 { USEC_PER_HOUR, 15 * USEC_PER_MINUTE },
159 { 3 * USEC_PER_HOUR, 30 * USEC_PER_MINUTE }
160 };
161
162 usec_t left, sub;
163 unsigned i;
164
165 /* If the time is already passed, then don't announce */
166 if (n >= elapse)
167 return 0;
168
169 left = elapse - n;
170 for (i = 0; i < ELEMENTSOF(table); i++)
08e4b1c5 171 if (n + table[i].delay >= elapse) {
9be9828c 172 sub = ((left / table[i].interval) * table[i].interval);
08e4b1c5
LP
173 break;
174 }
9be9828c
LP
175
176 if (i >= ELEMENTSOF(table))
177 sub = ((left / USEC_PER_HOUR) * USEC_PER_HOUR);
178
179 return elapse > sub ? elapse - sub : 1;
180}
181
182static usec_t when_nologin(usec_t elapse) {
183 return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
184}
185
04ebb595
LP
186static const char *mode_to_string(enum sd_shutdown_mode m) {
187 switch (m) {
188 case SD_SHUTDOWN_REBOOT:
189 return "reboot";
190 case SD_SHUTDOWN_POWEROFF:
191 return "poweroff";
192 case SD_SHUTDOWN_HALT:
193 return "halt";
194 case SD_SHUTDOWN_KEXEC:
195 return "kexec";
196 default:
197 return NULL;
198 }
199}
200
201static int update_schedule_file(struct sd_shutdown_command *c) {
202 int r;
203 FILE *f;
204 char *temp_path, *t;
205
206 assert(c);
207
d2e54fae 208 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
04ebb595
LP
209 if (r < 0) {
210 log_error("Failed to create shutdown subdirectory: %s", strerror(-r));
211 return r;
212 }
213
214 t = cescape(c->wall_message);
215 if (!t) {
669241a0 216 log_error("Out of memory.");
04ebb595
LP
217 return -ENOMEM;
218 }
219
220 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
221 if (r < 0) {
222 log_error("Failed to save information about scheduled shutdowns: %s", strerror(-r));
223 free(t);
224 return r;
225 }
226
227 fchmod(fileno(f), 0644);
228
229 fprintf(f,
230 "USEC=%llu\n"
231 "WARN_WALL=%i\n"
232 "MODE=%s\n",
233 (unsigned long long) c->usec,
234 c->warn_wall,
235 mode_to_string(c->mode));
236
237 if (c->dry_run)
238 fputs("DRY_RUN=1\n", f);
239
240 if (!isempty(t))
241 fprintf(f, "WALL_MESSAGE=%s\n", t);
242
243 free(t);
244
245 fflush(f);
246
247 if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
248 log_error("Failed to write information about scheduled shutdowns: %m");
249 r = -errno;
250
251 unlink(temp_path);
252 unlink("/run/systemd/shutdown/scheduled");
253 }
254
255 fclose(f);
256 free(temp_path);
257
258 return r;
259}
260
261static bool scheduled(struct sd_shutdown_command *c) {
262 return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
263}
264
f6144808
LP
265int main(int argc, char *argv[]) {
266 enum {
267 FD_SOCKET,
9be9828c 268 FD_WALL_TIMER,
f6144808 269 FD_NOLOGIN_TIMER,
9be9828c 270 FD_SHUTDOWN_TIMER,
f6144808
LP
271 _FD_MAX
272 };
273
22f4096c 274 int r = EXIT_FAILURE, n_fds;
04ebb595 275 union shutdown_buffer b;
f6144808 276 struct pollfd pollfd[_FD_MAX];
04ebb595 277 bool exec_shutdown = false, unlink_nologin = false;
9be9828c 278 unsigned i;
f6144808
LP
279
280 if (getppid() != 1) {
281 log_error("This program should be invoked by init only.");
22f4096c 282 return EXIT_FAILURE;
f6144808
LP
283 }
284
285 if (argc > 1) {
286 log_error("This program does not take arguments.");
22f4096c 287 return EXIT_FAILURE;
f6144808
LP
288 }
289
4cfa2c99 290 log_set_target(LOG_TARGET_AUTO);
f6144808 291 log_parse_environment();
2396fb04 292 log_open();
f6144808 293
4c12626c
LP
294 umask(0022);
295
04ebb595
LP
296 n_fds = sd_listen_fds(true);
297 if (n_fds < 0) {
f6144808 298 log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
22f4096c 299 return EXIT_FAILURE;
f6144808
LP
300 }
301
9be9828c 302 if (n_fds != 1) {
f6144808 303 log_error("Need exactly one file descriptor.");
22f4096c 304 return EXIT_FAILURE;
f6144808
LP
305 }
306
04ebb595 307 zero(b);
f6144808
LP
308 zero(pollfd);
309
310 pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
311 pollfd[FD_SOCKET].events = POLLIN;
9be9828c 312
04ebb595 313 for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
9be9828c 314 pollfd[i].events = POLLIN;
04ebb595
LP
315 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
316 if (pollfd[i].fd < 0) {
9be9828c 317 log_error("timerfd_create(): %m");
04ebb595 318 goto finish;
9be9828c
LP
319 }
320 }
321
f6144808
LP
322 log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid());
323
324 sd_notify(false,
325 "READY=1\n"
326 "STATUS=Processing requests...");
327
04ebb595 328 for (;;) {
f6144808 329 int k;
9be9828c 330 usec_t n;
f6144808 331
04ebb595
LP
332 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
333 if (k < 0) {
f6144808
LP
334
335 if (errno == EAGAIN || errno == EINTR)
336 continue;
337
338 log_error("poll(): %m");
339 goto finish;
340 }
341
04ebb595
LP
342 /* Exit on idle */
343 if (k == 0)
344 break;
345
9be9828c
LP
346 n = now(CLOCK_REALTIME);
347
f6144808
LP
348 if (pollfd[FD_SOCKET].revents) {
349
04ebb595
LP
350 k = read_packet(pollfd[FD_SOCKET].fd, &b);
351 if (k < 0)
f6144808 352 goto finish;
04ebb595 353 else if (k > 0) {
f6144808 354 struct itimerspec its;
11620592 355 char date[FORMAT_TIMESTAMP_MAX];
f6144808 356
04ebb595
LP
357 if (!scheduled(&b.command)) {
358 log_info("Shutdown canceled.");
359 break;
360 }
361
362 zero(its);
363 if (b.command.warn_wall) {
9be9828c 364 /* Send wall messages every so often */
04ebb595 365 timespec_store(&its.it_value, when_wall(n, b.command.usec));
f6144808 366
9be9828c 367 /* Warn immediately if less than 15 minutes are left */
04ebb595
LP
368 if (n < b.command.usec &&
369 n + 15*USEC_PER_MINUTE >= b.command.usec)
370 warn_wall(n, &b.command);
371 }
372 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
373 log_error("timerfd_settime(): %m");
374 goto finish;
9be9828c
LP
375 }
376
f6144808
LP
377 /* Disallow logins 5 minutes prior to shutdown */
378 zero(its);
04ebb595 379 timespec_store(&its.it_value, when_nologin(b.command.usec));
f6144808
LP
380 if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
381 log_error("timerfd_settime(): %m");
382 goto finish;
383 }
384
385 /* Shutdown after the specified time is reached */
386 zero(its);
04ebb595 387 timespec_store(&its.it_value, b.command.usec);
f6144808
LP
388 if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
389 log_error("timerfd_settime(): %m");
390 goto finish;
391 }
392
04ebb595
LP
393 update_schedule_file(&b.command);
394
f6144808 395 sd_notifyf(false,
04ebb595
LP
396 "STATUS=Shutting down at %s (%s)...",
397 format_timestamp(date, sizeof(date), b.command.usec),
398 mode_to_string(b.command.mode));
399
400 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
f6144808
LP
401 }
402 }
403
9be9828c
LP
404 if (pollfd[FD_WALL_TIMER].revents) {
405 struct itimerspec its;
406
04ebb595 407 warn_wall(n, &b.command);
9be9828c
LP
408 flush_fd(pollfd[FD_WALL_TIMER].fd);
409
410 /* Restart timer */
411 zero(its);
04ebb595 412 timespec_store(&its.it_value, when_wall(n, b.command.usec));
9be9828c
LP
413 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
414 log_error("timerfd_settime(): %m");
415 goto finish;
416 }
417 }
418
419 if (pollfd[FD_NOLOGIN_TIMER].revents) {
f6144808
LP
420 int e;
421
db019b8d 422 log_info("Creating /run/nologin, blocking further logins...");
08e4b1c5 423
04ebb595
LP
424 e = write_one_line_file_atomic("/run/nologin", "System is going down.");
425 if (e < 0)
db019b8d 426 log_error("Failed to create /run/nologin: %s", strerror(-e));
f6144808
LP
427 else
428 unlink_nologin = true;
429
9be9828c 430 flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
f6144808
LP
431 }
432
9be9828c 433 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
f6144808
LP
434 exec_shutdown = true;
435 goto finish;
436 }
04ebb595 437 }
f6144808 438
22f4096c 439 r = EXIT_SUCCESS;
f6144808
LP
440
441 log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid());
442
443finish:
f6144808 444
9be9828c
LP
445 for (i = 0; i < _FD_MAX; i++)
446 if (pollfd[i].fd >= 0)
447 close_nointr_nofail(pollfd[i].fd);
f6144808 448
16061c20 449 if (unlink_nologin)
db019b8d 450 unlink("/run/nologin");
16061c20 451
04ebb595
LP
452 unlink("/run/systemd/shutdown/scheduled");
453
454 if (exec_shutdown && !b.command.dry_run) {
f6144808
LP
455 char sw[3];
456
457 sw[0] = '-';
04ebb595 458 sw[1] = b.command.mode;
f6144808
LP
459 sw[2] = 0;
460
08e4b1c5
LP
461 execl(SYSTEMCTL_BINARY_PATH,
462 "shutdown",
463 sw,
464 "now",
04ebb595
LP
465 (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
466 (b.command.warn_wall ? NULL : "--no-wall"),
08e4b1c5
LP
467 NULL);
468
f6144808
LP
469 log_error("Failed to execute /sbin/shutdown: %m");
470 }
471
f6144808
LP
472 sd_notify(false,
473 "STATUS=Exiting...");
474
475 return r;
476}