chiark / gitweb /
Prep v228: Apply more cosmetic changes found in upstream.
[elogind.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 <pwd.h>
24 #include <string.h>
25 #include <unistd.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 }