Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2015 Daniel Mack
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 <errno.h>
23 : #include <string.h>
24 : #include <unistd.h>
25 : #include <pwd.h>
26 :
27 : #include "sd-messages.h"
28 : #include "strv.h"
29 : #include "special.h"
30 : #include "unit-name.h"
31 : #include "audit.h"
32 : #include "bus-util.h"
33 : #include "bus-error.h"
34 : #include "bus-common-errors.h"
35 : #include "logind.h"
36 : #include "formats-util.h"
37 : #include "utmp-wtmp.h"
38 :
39 0 : _const_ static usec_t when_wall(usec_t n, usec_t elapse) {
40 :
41 : usec_t left;
42 : unsigned int i;
43 : static const int wall_timers[] = {
44 : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
45 : 25, 40, 55, 70, 100, 130, 150, 180,
46 : };
47 :
48 : /* If the time is already passed, then don't announce */
49 0 : if (n >= elapse)
50 0 : return 0;
51 :
52 0 : left = elapse - n;
53 :
54 0 : for (i = 1; i < ELEMENTSOF(wall_timers); i++)
55 0 : if (wall_timers[i] * USEC_PER_MINUTE >= left)
56 0 : return left - wall_timers[i-1] * USEC_PER_MINUTE;
57 :
58 0 : return left % USEC_PER_HOUR;
59 : }
60 :
61 0 : bool logind_wall_tty_filter(const char *tty, void *userdata) {
62 :
63 0 : Manager *m = userdata;
64 :
65 0 : assert(m);
66 :
67 0 : if (!startswith(tty, "/dev/"))
68 0 : return true;
69 :
70 0 : return !streq(tty + 5, m->scheduled_shutdown_tty);
71 : }
72 :
73 0 : static int warn_wall(Manager *m, usec_t n) {
74 0 : char date[FORMAT_TIMESTAMP_MAX] = {};
75 0 : _cleanup_free_ char *l = NULL;
76 : usec_t left;
77 : int r;
78 :
79 0 : assert(m);
80 :
81 0 : if (!m->enable_wall_messages)
82 0 : return 0;
83 :
84 0 : left = m->scheduled_shutdown_timeout > n;
85 :
86 0 : r = asprintf(&l, "%s%sThe system is going down for %s %s%s!",
87 0 : strempty(m->wall_message),
88 0 : isempty(m->wall_message) ? "" : "\n",
89 : m->scheduled_shutdown_type,
90 : left ? "at " : "NOW",
91 0 : left ? format_timestamp(date, sizeof(date), m->scheduled_shutdown_timeout) : "");
92 0 : if (r < 0) {
93 0 : log_oom();
94 0 : return 0;
95 : }
96 :
97 0 : utmp_wall(l, lookup_uid(m->scheduled_shutdown_uid),
98 0 : m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
99 :
100 0 : return 1;
101 : }
102 :
103 0 : static int wall_message_timeout_handler(
104 : sd_event_source *s,
105 : uint64_t usec,
106 : void *userdata) {
107 :
108 0 : Manager *m = userdata;
109 : usec_t n, next;
110 : int r;
111 :
112 0 : assert(m);
113 0 : assert(s == m->wall_message_timeout_source);
114 :
115 0 : n = now(CLOCK_REALTIME);
116 :
117 0 : r = warn_wall(m, n);
118 0 : if (r == 0)
119 0 : return 0;
120 :
121 0 : next = when_wall(n, m->scheduled_shutdown_timeout);
122 0 : if (next > 0) {
123 0 : r = sd_event_source_set_time(s, n + next);
124 0 : if (r < 0)
125 0 : return log_error_errno(r, "sd_event_source_set_time() failed. %m");
126 :
127 0 : r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
128 0 : if (r < 0)
129 0 : return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
130 : }
131 :
132 0 : return 0;
133 : }
134 :
135 0 : int manager_setup_wall_message_timer(Manager *m) {
136 :
137 : usec_t n, elapse;
138 : int r;
139 :
140 0 : assert(m);
141 :
142 0 : n = now(CLOCK_REALTIME);
143 0 : elapse = m->scheduled_shutdown_timeout;
144 :
145 : /* wall message handling */
146 :
147 0 : if (isempty(m->scheduled_shutdown_type)) {
148 0 : warn_wall(m, n);
149 0 : return 0;
150 : }
151 :
152 0 : if (elapse < n)
153 0 : return 0;
154 :
155 : /* Warn immediately if less than 15 minutes are left */
156 0 : if (elapse - n < 15 * USEC_PER_MINUTE) {
157 0 : r = warn_wall(m, n);
158 0 : if (r == 0)
159 0 : return 0;
160 : }
161 :
162 0 : elapse = when_wall(n, elapse);
163 0 : if (elapse == 0)
164 0 : return 0;
165 :
166 0 : if (m->wall_message_timeout_source) {
167 0 : r = sd_event_source_set_time(m->wall_message_timeout_source, n + elapse);
168 0 : if (r < 0)
169 0 : return log_error_errno(r, "sd_event_source_set_time() failed. %m");
170 :
171 0 : r = sd_event_source_set_enabled(m->wall_message_timeout_source, SD_EVENT_ONESHOT);
172 0 : if (r < 0)
173 0 : return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
174 : } else {
175 0 : r = sd_event_add_time(m->event, &m->wall_message_timeout_source,
176 : CLOCK_REALTIME, n + elapse, 0, wall_message_timeout_handler, m);
177 0 : if (r < 0)
178 0 : return log_error_errno(r, "sd_event_add_time() failed. %m");
179 : }
180 :
181 0 : return 0;
182 : }
|