]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-utmp.c
tree-wide: introduce new safe_fork() helper and port everything over
[thirdparty/systemd.git] / src / login / logind-utmp.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
e2fa5721
DM
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>
cf0fbc49 22#include <pwd.h>
e2fa5721
DM
23#include <string.h>
24#include <unistd.h>
e2fa5721
DM
25
26#include "sd-messages.h"
b1d4f8e1 27
b5efdb8a 28#include "alloc-util.h"
430f0182 29#include "audit-util.h"
e2fa5721 30#include "bus-common-errors.h"
b1d4f8e1
LP
31#include "bus-error.h"
32#include "bus-util.h"
f97b34a6 33#include "format-util.h"
b1d4f8e1 34#include "logind.h"
27458ed6 35#include "path-util.h"
b1d4f8e1
LP
36#include "special.h"
37#include "strv.h"
38#include "unit-name.h"
39#include "user-util.h"
e2fa5721
DM
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
64bool logind_wall_tty_filter(const char *tty, void *userdata) {
e2fa5721 65 Manager *m = userdata;
27458ed6 66 const char *p;
e2fa5721
DM
67
68 assert(m);
69
27458ed6
LP
70 if (!m->scheduled_shutdown_tty)
71 return true;
72
73 p = path_startswith(tty, "/dev/");
74 if (!p)
e2fa5721
DM
75 return true;
76
27458ed6 77 return !streq(p, m->scheduled_shutdown_tty);
e2fa5721
DM
78}
79
80static 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
d0260817 104 utmp_wall(l, uid_to_name(m->scheduled_shutdown_uid),
e2fa5721
DM
105 m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
106
107 return 1;
108}
109
110static 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)
c2a23db0 132 return log_error_errno(r, "sd_event_source_set_time() failed. %m");
e2fa5721
DM
133
134 r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
135 if (r < 0)
c2a23db0 136 return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
e2fa5721
DM
137 }
138
139 return 0;
140}
141
142int 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)
c2a23db0 176 return log_error_errno(r, "sd_event_source_set_time() failed. %m");
e2fa5721
DM
177
178 r = sd_event_source_set_enabled(m->wall_message_timeout_source, SD_EVENT_ONESHOT);
179 if (r < 0)
c2a23db0 180 return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
e2fa5721
DM
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)
c2a23db0 185 return log_error_errno(r, "sd_event_add_time() failed. %m");
e2fa5721
DM
186 }
187
188 return 0;
189}