]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-utmp.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / login / logind-utmp.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2015 Daniel Mack
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <pwd.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include "sd-messages.h"
27
28 #include "alloc-util.h"
29 #include "audit-util.h"
30 #include "bus-common-errors.h"
31 #include "bus-error.h"
32 #include "bus-util.h"
33 #include "format-util.h"
34 #include "logind.h"
35 #include "path-util.h"
36 #include "special.h"
37 #include "strv.h"
38 #include "unit-name.h"
39 #include "user-util.h"
40 #include "utmp-wtmp.h"
41
42 _const_ static usec_t when_wall(usec_t n, usec_t elapse) {
43
44 usec_t left;
45 unsigned int i;
46 static const int wall_timers[] = {
47 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
48 25, 40, 55, 70, 100, 130, 150, 180,
49 };
50
51 /* If the time is already passed, then don't announce */
52 if (n >= elapse)
53 return 0;
54
55 left = elapse - n;
56
57 for (i = 1; i < ELEMENTSOF(wall_timers); i++)
58 if (wall_timers[i] * USEC_PER_MINUTE >= left)
59 return left - wall_timers[i-1] * USEC_PER_MINUTE;
60
61 return left % USEC_PER_HOUR;
62 }
63
64 bool logind_wall_tty_filter(const char *tty, void *userdata) {
65 Manager *m = userdata;
66 const char *p;
67
68 assert(m);
69
70 if (!m->scheduled_shutdown_tty)
71 return true;
72
73 p = path_startswith(tty, "/dev/");
74 if (!p)
75 return true;
76
77 return !streq(p, m->scheduled_shutdown_tty);
78 }
79
80 static int warn_wall(Manager *m, usec_t n) {
81 char date[FORMAT_TIMESTAMP_MAX] = {};
82 _cleanup_free_ char *l = NULL;
83 usec_t left;
84 int r;
85
86 assert(m);
87
88 if (!m->enable_wall_messages)
89 return 0;
90
91 left = m->scheduled_shutdown_timeout > n;
92
93 r = asprintf(&l, "%s%sThe system is going down for %s %s%s!",
94 strempty(m->wall_message),
95 isempty(m->wall_message) ? "" : "\n",
96 m->scheduled_shutdown_type,
97 left ? "at " : "NOW",
98 left ? format_timestamp(date, sizeof(date), m->scheduled_shutdown_timeout) : "");
99 if (r < 0) {
100 log_oom();
101 return 0;
102 }
103
104 utmp_wall(l, uid_to_name(m->scheduled_shutdown_uid),
105 m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
106
107 return 1;
108 }
109
110 static int wall_message_timeout_handler(
111 sd_event_source *s,
112 uint64_t usec,
113 void *userdata) {
114
115 Manager *m = userdata;
116 usec_t n, next;
117 int r;
118
119 assert(m);
120 assert(s == m->wall_message_timeout_source);
121
122 n = now(CLOCK_REALTIME);
123
124 r = warn_wall(m, n);
125 if (r == 0)
126 return 0;
127
128 next = when_wall(n, m->scheduled_shutdown_timeout);
129 if (next > 0) {
130 r = sd_event_source_set_time(s, n + next);
131 if (r < 0)
132 return log_error_errno(r, "sd_event_source_set_time() failed. %m");
133
134 r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
135 if (r < 0)
136 return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
137 }
138
139 return 0;
140 }
141
142 int manager_setup_wall_message_timer(Manager *m) {
143
144 usec_t n, elapse;
145 int r;
146
147 assert(m);
148
149 n = now(CLOCK_REALTIME);
150 elapse = m->scheduled_shutdown_timeout;
151
152 /* wall message handling */
153
154 if (isempty(m->scheduled_shutdown_type)) {
155 warn_wall(m, n);
156 return 0;
157 }
158
159 if (elapse < n)
160 return 0;
161
162 /* Warn immediately if less than 15 minutes are left */
163 if (elapse - n < 15 * USEC_PER_MINUTE) {
164 r = warn_wall(m, n);
165 if (r == 0)
166 return 0;
167 }
168
169 elapse = when_wall(n, elapse);
170 if (elapse == 0)
171 return 0;
172
173 if (m->wall_message_timeout_source) {
174 r = sd_event_source_set_time(m->wall_message_timeout_source, n + elapse);
175 if (r < 0)
176 return log_error_errno(r, "sd_event_source_set_time() failed. %m");
177
178 r = sd_event_source_set_enabled(m->wall_message_timeout_source, SD_EVENT_ONESHOT);
179 if (r < 0)
180 return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
181 } else {
182 r = sd_event_add_time(m->event, &m->wall_message_timeout_source,
183 CLOCK_REALTIME, n + elapse, 0, wall_message_timeout_handler, m);
184 if (r < 0)
185 return log_error_errno(r, "sd_event_add_time() failed. %m");
186 }
187
188 return 0;
189 }