chiark / gitweb /
Do no isolate in case of emergency or severe problems
[elogind.git] / src / shutdownd / shutdownd.c
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
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.
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
16   Lesser General Public License for more details.
17
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/>.
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>
31 #include <stddef.h>
32
33 #include <systemd/sd-daemon.h>
34 #include <systemd/sd-shutdown.h>
35
36 #include "log.h"
37 #include "macro.h"
38 #include "util.h"
39 #include "utmp-wtmp.h"
40 #include "mkdir.h"
41 #include "fileio.h"
42
43 union shutdown_buffer {
44         struct sd_shutdown_command command;
45         char space[offsetof(struct sd_shutdown_command, wall_message) + LINE_MAX];
46 };
47
48 static int read_packet(int fd, union shutdown_buffer *_b) {
49         struct msghdr msghdr;
50         struct iovec iovec;
51         struct ucred *ucred;
52         union {
53                 struct cmsghdr cmsghdr;
54                 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
55         } control;
56         ssize_t n;
57         union shutdown_buffer b; /* We maintain our own copy here, in order not to corrupt the last message */
58
59         assert(fd >= 0);
60         assert(_b);
61
62         zero(iovec);
63         iovec.iov_base = &b;
64         iovec.iov_len = sizeof(b) - 1;
65
66         zero(control);
67         zero(msghdr);
68         msghdr.msg_iov = &iovec;
69         msghdr.msg_iovlen = 1;
70         msghdr.msg_control = &control;
71         msghdr.msg_controllen = sizeof(control);
72
73         n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
74         if (n <= 0) {
75                 if (n == 0) {
76                         log_error("Short read");
77                         return -EIO;
78                 }
79
80                 if (errno == EAGAIN || errno == EINTR)
81                         return 0;
82
83                 log_error("recvmsg(): %m");
84                 return -errno;
85         }
86
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.");
92                 return 0;
93         }
94
95         ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
96         if (ucred->uid != 0) {
97                 log_warning("Got request from unprivileged user. Ignoring.");
98                 return 0;
99         }
100
101         if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) {
102                 log_warning("Message has invalid size. Ignoring.");
103                 return 0;
104         }
105
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.");
112                 return 0;
113         }
114
115         b.space[n] = 0;
116
117         *_b = b;
118         return 1;
119 }
120
121 static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
122         char date[FORMAT_TIMESTAMP_MAX];
123         const char *prefix;
124         char *l = NULL;
125
126         assert(c);
127         assert(c->warn_wall);
128
129         if (n >= c->usec)
130                 return;
131
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 ";
142         else
143                 assert_not_reached("Unknown mode!");
144
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");
148         else {
149                 utmp_wall(l, NULL);
150                 free(l);
151         }
152 }
153
154 static usec_t when_wall(usec_t n, usec_t elapse) {
155
156         static const struct {
157                 usec_t delay;
158                 usec_t interval;
159         } table[] = {
160                 { 0,                    USEC_PER_MINUTE      },
161                 { 10 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE },
162                 { USEC_PER_HOUR,        30 * USEC_PER_MINUTE },
163                 { 3 * USEC_PER_HOUR,    USEC_PER_HOUR        },
164         };
165
166         usec_t left, sub;
167         unsigned i = ELEMENTSOF(table) - 1;
168
169         /* If the time is already passed, then don't announce */
170         if (n >= elapse)
171                 return 0;
172
173         left = elapse - n;
174         while (left < table[i].delay)
175                 i--;
176         sub = (left / table[i].interval) * table[i].interval;
177
178         assert(sub < elapse);
179         return elapse - sub;
180 }
181
182 static usec_t when_nologin(usec_t elapse) {
183         return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
184 }
185
186 static 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
201 static 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
208         r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
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)
216                 return log_oom();
217
218         r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
219         if (r < 0) {
220                 log_error("Failed to save information about scheduled shutdowns: %s", strerror(-r));
221                 free(t);
222                 return r;
223         }
224
225         fchmod(fileno(f), 0644);
226
227         fprintf(f,
228                 "USEC=%llu\n"
229                 "WARN_WALL=%i\n"
230                 "MODE=%s\n",
231                 (unsigned long long) c->usec,
232                 c->warn_wall,
233                 mode_to_string(c->mode));
234
235         if (c->dry_run)
236                 fputs("DRY_RUN=1\n", f);
237
238         if (!isempty(t))
239                 fprintf(f, "WALL_MESSAGE=%s\n", t);
240
241         free(t);
242
243         fflush(f);
244
245         if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
246                 log_error("Failed to write information about scheduled shutdowns: %m");
247                 r = -errno;
248
249                 unlink(temp_path);
250                 unlink("/run/systemd/shutdown/scheduled");
251         }
252
253         fclose(f);
254         free(temp_path);
255
256         return r;
257 }
258
259 static bool scheduled(struct sd_shutdown_command *c) {
260         return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
261 }
262
263 int main(int argc, char *argv[]) {
264         enum {
265                 FD_SOCKET,
266                 FD_WALL_TIMER,
267                 FD_NOLOGIN_TIMER,
268                 FD_SHUTDOWN_TIMER,
269                 _FD_MAX
270         };
271
272         int r = EXIT_FAILURE, n_fds;
273         union shutdown_buffer b;
274         struct pollfd pollfd[_FD_MAX];
275         bool exec_shutdown = false, unlink_nologin = false;
276         unsigned i;
277
278         if (getppid() != 1) {
279                 log_error("This program should be invoked by init only.");
280                 return EXIT_FAILURE;
281         }
282
283         if (argc > 1) {
284                 log_error("This program does not take arguments.");
285                 return EXIT_FAILURE;
286         }
287
288         log_set_target(LOG_TARGET_AUTO);
289         log_parse_environment();
290         log_open();
291
292         umask(0022);
293
294         n_fds = sd_listen_fds(true);
295         if (n_fds < 0) {
296                 log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
297                 return EXIT_FAILURE;
298         }
299
300         if (n_fds != 1) {
301                 log_error("Need exactly one file descriptor.");
302                 return EXIT_FAILURE;
303         }
304
305         zero(b);
306         zero(pollfd);
307
308         pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
309         pollfd[FD_SOCKET].events = POLLIN;
310
311         for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
312                 pollfd[i].events = POLLIN;
313                 pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
314                 if (pollfd[i].fd < 0) {
315                         log_error("timerfd_create(): %m");
316                         goto finish;
317                 }
318         }
319
320         log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid());
321
322         sd_notify(false,
323                   "READY=1\n"
324                   "STATUS=Processing requests...");
325
326         for (;;) {
327                 int k;
328                 usec_t n;
329
330                 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
331                 if (k < 0) {
332
333                         if (errno == EAGAIN || errno == EINTR)
334                                 continue;
335
336                         log_error("poll(): %m");
337                         goto finish;
338                 }
339
340                 /* Exit on idle */
341                 if (k == 0)
342                         break;
343
344                 n = now(CLOCK_REALTIME);
345
346                 if (pollfd[FD_SOCKET].revents) {
347
348                         k = read_packet(pollfd[FD_SOCKET].fd, &b);
349                         if (k < 0)
350                                 goto finish;
351                         else if (k > 0) {
352                                 struct itimerspec its;
353                                 char date[FORMAT_TIMESTAMP_MAX];
354
355                                 if (!scheduled(&b.command)) {
356                                         log_info("Shutdown canceled.");
357                                         if (b.command.warn_wall)
358                                                 warn_wall(0, &b.command);
359                                         break;
360                                 }
361
362                                 zero(its);
363                                 if (b.command.warn_wall) {
364                                         /* Send wall messages every so often */
365                                         timespec_store(&its.it_value, when_wall(n, b.command.usec));
366
367                                         /* Warn immediately if less than 15 minutes are left */
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;
375                                 }
376
377                                 /* Disallow logins 5 minutes prior to shutdown */
378                                 zero(its);
379                                 timespec_store(&its.it_value, when_nologin(b.command.usec));
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);
387                                 timespec_store(&its.it_value, b.command.usec);
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
393                                 update_schedule_file(&b.command);
394
395                                 sd_notifyf(false,
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));
401                         }
402                 }
403
404                 if (pollfd[FD_WALL_TIMER].revents) {
405                         struct itimerspec its;
406
407                         warn_wall(n, &b.command);
408                         flush_fd(pollfd[FD_WALL_TIMER].fd);
409
410                         /* Restart timer */
411                         zero(its);
412                         timespec_store(&its.it_value, when_wall(n, b.command.usec));
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) {
420                         int e;
421
422                         log_info("Creating /run/nologin, blocking further logins...");
423
424                         e = write_one_line_file_atomic("/run/nologin", "System is going down.");
425                         if (e < 0)
426                                 log_error("Failed to create /run/nologin: %s", strerror(-e));
427                         else
428                                 unlink_nologin = true;
429
430                         flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
431                 }
432
433                 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
434                         exec_shutdown = true;
435                         goto finish;
436                 }
437         }
438
439         r = EXIT_SUCCESS;
440
441         log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid());
442
443 finish:
444
445         for (i = 0; i < _FD_MAX; i++)
446                 if (pollfd[i].fd >= 0)
447                         close_nointr_nofail(pollfd[i].fd);
448
449         if (unlink_nologin)
450                 unlink("/run/nologin");
451
452         unlink("/run/systemd/shutdown/scheduled");
453
454         if (exec_shutdown && !b.command.dry_run) {
455                 char sw[3];
456
457                 sw[0] = '-';
458                 sw[1] = b.command.mode;
459                 sw[2] = 0;
460
461                 execl(SYSTEMCTL_BINARY_PATH,
462                       "shutdown",
463                       sw,
464                       "now",
465                       (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
466                       (b.command.warn_wall ? NULL : "--no-wall"),
467                       NULL);
468
469                 log_error("Failed to execute /sbin/shutdown: %m");
470         }
471
472         sd_notify(false,
473                   "STATUS=Exiting...");
474
475         return r;
476 }