]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-utmp.c
tree-wide: sort includes
[thirdparty/systemd.git] / src / login / logind-utmp.c
CommitLineData
e2fa5721
DM
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>
cf0fbc49 23#include <pwd.h>
e2fa5721
DM
24#include <string.h>
25#include <unistd.h>
e2fa5721
DM
26
27#include "sd-messages.h"
b1d4f8e1 28
b5efdb8a 29#include "alloc-util.h"
430f0182 30#include "audit-util.h"
e2fa5721 31#include "bus-common-errors.h"
b1d4f8e1
LP
32#include "bus-error.h"
33#include "bus-util.h"
e2fa5721 34#include "formats-util.h"
b1d4f8e1
LP
35#include "logind.h"
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) {
65
66 Manager *m = userdata;
67
68 assert(m);
69
70 if (!startswith(tty, "/dev/"))
71 return true;
72
73 return !streq(tty + 5, m->scheduled_shutdown_tty);
74}
75
76static int warn_wall(Manager *m, usec_t n) {
77 char date[FORMAT_TIMESTAMP_MAX] = {};
78 _cleanup_free_ char *l = NULL;
79 usec_t left;
80 int r;
81
82 assert(m);
83
84 if (!m->enable_wall_messages)
85 return 0;
86
87 left = m->scheduled_shutdown_timeout > n;
88
89 r = asprintf(&l, "%s%sThe system is going down for %s %s%s!",
90 strempty(m->wall_message),
91 isempty(m->wall_message) ? "" : "\n",
92 m->scheduled_shutdown_type,
93 left ? "at " : "NOW",
94 left ? format_timestamp(date, sizeof(date), m->scheduled_shutdown_timeout) : "");
95 if (r < 0) {
96 log_oom();
97 return 0;
98 }
99
d0260817 100 utmp_wall(l, uid_to_name(m->scheduled_shutdown_uid),
e2fa5721
DM
101 m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
102
103 return 1;
104}
105
106static int wall_message_timeout_handler(
107 sd_event_source *s,
108 uint64_t usec,
109 void *userdata) {
110
111 Manager *m = userdata;
112 usec_t n, next;
113 int r;
114
115 assert(m);
116 assert(s == m->wall_message_timeout_source);
117
118 n = now(CLOCK_REALTIME);
119
120 r = warn_wall(m, n);
121 if (r == 0)
122 return 0;
123
124 next = when_wall(n, m->scheduled_shutdown_timeout);
125 if (next > 0) {
126 r = sd_event_source_set_time(s, n + next);
127 if (r < 0)
c2a23db0 128 return log_error_errno(r, "sd_event_source_set_time() failed. %m");
e2fa5721
DM
129
130 r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
131 if (r < 0)
c2a23db0 132 return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
e2fa5721
DM
133 }
134
135 return 0;
136}
137
138int manager_setup_wall_message_timer(Manager *m) {
139
140 usec_t n, elapse;
141 int r;
142
143 assert(m);
144
145 n = now(CLOCK_REALTIME);
146 elapse = m->scheduled_shutdown_timeout;
147
148 /* wall message handling */
149
150 if (isempty(m->scheduled_shutdown_type)) {
151 warn_wall(m, n);
152 return 0;
153 }
154
155 if (elapse < n)
156 return 0;
157
158 /* Warn immediately if less than 15 minutes are left */
159 if (elapse - n < 15 * USEC_PER_MINUTE) {
160 r = warn_wall(m, n);
161 if (r == 0)
162 return 0;
163 }
164
165 elapse = when_wall(n, elapse);
166 if (elapse == 0)
167 return 0;
168
169 if (m->wall_message_timeout_source) {
170 r = sd_event_source_set_time(m->wall_message_timeout_source, n + elapse);
171 if (r < 0)
c2a23db0 172 return log_error_errno(r, "sd_event_source_set_time() failed. %m");
e2fa5721
DM
173
174 r = sd_event_source_set_enabled(m->wall_message_timeout_source, SD_EVENT_ONESHOT);
175 if (r < 0)
c2a23db0 176 return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
e2fa5721
DM
177 } else {
178 r = sd_event_add_time(m->event, &m->wall_message_timeout_source,
179 CLOCK_REALTIME, n + elapse, 0, wall_message_timeout_handler, m);
180 if (r < 0)
c2a23db0 181 return log_error_errno(r, "sd_event_add_time() failed. %m");
e2fa5721
DM
182 }
183
184 return 0;
185}