]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-utmp.c
Merge pull request #1695 from evverx/fix-cap-bounding-merging
[thirdparty/systemd.git] / src / login / logind-utmp.c
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
29 #include "alloc-util.h"
30 #include "audit-util.h"
31 #include "bus-common-errors.h"
32 #include "bus-error.h"
33 #include "bus-util.h"
34 #include "formats-util.h"
35 #include "logind.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
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
76 static 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
100 utmp_wall(l, uid_to_name(m->scheduled_shutdown_uid),
101 m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
102
103 return 1;
104 }
105
106 static 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)
128 return log_error_errno(r, "sd_event_source_set_time() failed. %m");
129
130 r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
131 if (r < 0)
132 return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
133 }
134
135 return 0;
136 }
137
138 int 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)
172 return log_error_errno(r, "sd_event_source_set_time() failed. %m");
173
174 r = sd_event_source_set_enabled(m->wall_message_timeout_source, SD_EVENT_ONESHOT);
175 if (r < 0)
176 return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
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)
181 return log_error_errno(r, "sd_event_add_time() failed. %m");
182 }
183
184 return 0;
185 }