chiark / gitweb /
systemctl: prefix list-units and list-machines output with a circle indicating a...
[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 ucred *ucred;
50         ssize_t n;
51
52         union shutdown_buffer b; /* We maintain our own copy here, in
53                                   * order not to corrupt the last message */
54         struct iovec iovec = {
55                 iovec.iov_base = &b,
56                 iovec.iov_len = sizeof(b) - 1,
57         };
58         union {
59                 struct cmsghdr cmsghdr;
60                 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
61         } control = {};
62         struct msghdr msghdr = {
63                 .msg_iov = &iovec,
64                 .msg_iovlen = 1,
65                 .msg_control = &control,
66                 .msg_controllen = sizeof(control),
67         };
68
69         assert(fd >= 0);
70         assert(_b);
71
72         n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
73         if (n <= 0) {
74                 if (n == 0) {
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
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.");
111                 return 0;
112         }
113
114         b.space[n] = 0;
115
116         *_b = b;
117         return 1;
118 }
119
120 static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
121         char date[FORMAT_TIMESTAMP_MAX];
122         const char *prefix;
123         _cleanup_free_ char *l = NULL;
124
125         assert(c);
126         assert(c->warn_wall);
127
128         if (n >= c->usec)
129                 return;
130
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 ";
141         else
142                 assert_not_reached("Unknown mode!");
143
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);
147         else
148                 log_error("Failed to allocate wall message");
149 }
150
151 _const_ static 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                 { 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        },
161         };
162
163         usec_t left, sub;
164         unsigned i = ELEMENTSOF(table) - 1;
165
166         /* If the time is already passed, then don't announce */
167         if (n >= elapse)
168                 return 0;
169
170         left = elapse - n;
171         while (left < table[i].delay)
172                 i--;
173         sub = (left / table[i].interval) * table[i].interval;
174
175         assert(sub < elapse);
176         return elapse - sub;
177 }
178
179 static usec_t when_nologin(usec_t elapse) {
180         return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
181 }
182
183 static const char *mode_to_string(enum sd_shutdown_mode m) {
184         switch (m) {
185         case SD_SHUTDOWN_REBOOT:
186                 return "reboot";
187         case SD_SHUTDOWN_POWEROFF:
188                 return "poweroff";
189         case SD_SHUTDOWN_HALT:
190                 return "halt";
191         case SD_SHUTDOWN_KEXEC:
192                 return "kexec";
193         default:
194                 return NULL;
195         }
196 }
197
198 static int update_schedule_file(struct sd_shutdown_command *c) {
199         int r;
200         _cleanup_fclose_ FILE *f = NULL;
201         _cleanup_free_ char *t = NULL, *temp_path = NULL;
202
203         assert(c);
204
205         r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
206         if (r < 0) {
207                 log_error("Failed to create shutdown subdirectory: %s", strerror(-r));
208                 return r;
209         }
210
211         t = cescape(c->wall_message);
212         if (!t)
213                 return log_oom();
214
215         r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
216         if (r < 0) {
217                 log_error("Failed to save information about scheduled shutdowns: %s", strerror(-r));
218                 return r;
219         }
220
221         fchmod(fileno(f), 0644);
222
223         fprintf(f,
224                 "USEC="USEC_FMT"\n"
225                 "WARN_WALL=%i\n"
226                 "MODE=%s\n",
227                 c->usec,
228                 c->warn_wall,
229                 mode_to_string(c->mode));
230
231         if (c->dry_run)
232                 fputs("DRY_RUN=1\n", f);
233
234         if (!isempty(t))
235                 fprintf(f, "WALL_MESSAGE=%s\n", t);
236
237         fflush(f);
238
239         if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
240                 log_error("Failed to write information about scheduled shutdowns: %m");
241                 r = -errno;
242
243                 unlink(temp_path);
244                 unlink("/run/systemd/shutdown/scheduled");
245         }
246
247         return r;
248 }
249
250 static bool scheduled(struct sd_shutdown_command *c) {
251         return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
252 }
253
254 int main(int argc, char *argv[]) {
255         enum {
256                 FD_SOCKET,
257                 FD_WALL_TIMER,
258                 FD_NOLOGIN_TIMER,
259                 FD_SHUTDOWN_TIMER,
260                 _FD_MAX
261         };
262
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;
267         unsigned i;
268
269         if (getppid() != 1) {
270                 log_error("This program should be invoked by init only.");
271                 return EXIT_FAILURE;
272         }
273
274         if (argc > 1) {
275                 log_error("This program does not take arguments.");
276                 return EXIT_FAILURE;
277         }
278
279         log_set_target(LOG_TARGET_AUTO);
280         log_parse_environment();
281         log_open();
282
283         umask(0022);
284
285         n_fds = sd_listen_fds(true);
286         if (n_fds < 0) {
287                 log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
288                 return EXIT_FAILURE;
289         }
290
291         if (n_fds != 1) {
292                 log_error("Need exactly one file descriptor.");
293                 return EXIT_FAILURE;
294         }
295
296         pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
297         pollfd[FD_SOCKET].events = POLLIN;
298
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");
304                         goto finish;
305                 }
306         }
307
308         log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid());
309
310         sd_notify(false,
311                   "READY=1\n"
312                   "STATUS=Processing requests...");
313
314         for (;;) {
315                 int k;
316                 usec_t n;
317
318                 k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
319                 if (k < 0) {
320
321                         if (errno == EAGAIN || errno == EINTR)
322                                 continue;
323
324                         log_error("poll(): %m");
325                         goto finish;
326                 }
327
328                 /* Exit on idle */
329                 if (k == 0)
330                         break;
331
332                 n = now(CLOCK_REALTIME);
333
334                 if (pollfd[FD_SOCKET].revents) {
335
336                         k = read_packet(pollfd[FD_SOCKET].fd, &b);
337                         if (k < 0)
338                                 goto finish;
339                         else if (k > 0) {
340                                 struct itimerspec its;
341                                 char date[FORMAT_TIMESTAMP_MAX];
342
343                                 if (!scheduled(&b.command)) {
344                                         log_info("Shutdown canceled.");
345                                         if (b.command.warn_wall)
346                                                 warn_wall(0, &b.command);
347                                         break;
348                                 }
349
350                                 zero(its);
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));
354
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);
359                                 }
360                                 if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
361                                         log_error("timerfd_settime(): %m");
362                                         goto finish;
363                                 }
364
365                                 /* Disallow logins 5 minutes prior to shutdown */
366                                 zero(its);
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");
370                                         goto finish;
371                                 }
372
373                                 /* Shutdown after the specified time is reached */
374                                 zero(its);
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");
378                                         goto finish;
379                                 }
380
381                                 update_schedule_file(&b.command);
382
383                                 sd_notifyf(false,
384                                            "STATUS=Shutting down at %s (%s)...",
385                                            format_timestamp(date, sizeof(date), b.command.usec),
386                                            mode_to_string(b.command.mode));
387
388                                 log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
389                         }
390                 }
391
392                 if (pollfd[FD_WALL_TIMER].revents) {
393                         struct itimerspec its = {};
394
395                         warn_wall(n, &b.command);
396                         flush_fd(pollfd[FD_WALL_TIMER].fd);
397
398                         /* Restart timer */
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");
402                                 goto finish;
403                         }
404                 }
405
406                 if (pollfd[FD_NOLOGIN_TIMER].revents) {
407                         int e;
408
409                         log_info("Creating /run/nologin, blocking further logins...");
410
411                         e = write_string_file_atomic("/run/nologin", "System is going down.");
412                         if (e < 0)
413                                 log_error("Failed to create /run/nologin: %s", strerror(-e));
414                         else
415                                 unlink_nologin = true;
416
417                         flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
418                 }
419
420                 if (pollfd[FD_SHUTDOWN_TIMER].revents) {
421                         exec_shutdown = true;
422                         goto finish;
423                 }
424         }
425
426         r = EXIT_SUCCESS;
427
428         log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid());
429
430 finish:
431
432         for (i = 0; i < _FD_MAX; i++)
433                 if (pollfd[i].fd >= 0)
434                         close_nointr_nofail(pollfd[i].fd);
435
436         if (unlink_nologin)
437                 unlink("/run/nologin");
438
439         unlink("/run/systemd/shutdown/scheduled");
440
441         if (exec_shutdown && !b.command.dry_run) {
442                 char sw[3];
443
444                 sw[0] = '-';
445                 sw[1] = b.command.mode;
446                 sw[2] = 0;
447
448                 execl(SYSTEMCTL_BINARY_PATH,
449                       "shutdown",
450                       sw,
451                       "now",
452                       (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
453                       (b.command.warn_wall ? NULL : "--no-wall"),
454                       NULL);
455
456                 log_error("Failed to execute /sbin/shutdown: %m");
457         }
458
459         sd_notify(false,
460                   "STATUS=Exiting...");
461
462         return r;
463 }