1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "sd-messages.h"
8 #include "alloc-util.h"
9 #include "audit-util.h"
10 #include "bus-common-errors.h"
11 #include "bus-error.h"
13 #include "event-util.h"
14 #include "format-util.h"
16 #include "path-util.h"
19 #include "unit-name.h"
20 #include "user-util.h"
21 #include "utmp-wtmp.h"
23 _const_
static usec_t
when_wall(usec_t n
, usec_t elapse
) {
24 static const int wall_timers
[] = {
25 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
26 25, 40, 55, 70, 100, 130, 150, 180,
29 /* If the time is already passed, then don't announce */
33 usec_t left
= elapse
- n
;
35 for (unsigned i
= 1; i
< ELEMENTSOF(wall_timers
); i
++)
36 if (wall_timers
[i
] * USEC_PER_MINUTE
>= left
)
37 return left
- wall_timers
[i
-1] * USEC_PER_MINUTE
;
39 return left
% USEC_PER_HOUR
;
42 bool logind_wall_tty_filter(const char *tty
, bool is_local
, void *userdata
) {
43 Manager
*m
= ASSERT_PTR(userdata
);
45 assert(m
->scheduled_shutdown_action
);
47 const char *p
= path_startswith(tty
, "/dev/");
51 /* Do not send information about events which do not destroy local sessions to local terminals. We
52 * can assume that if the system enters sleep or hibernation, this will be visible in an obvious way
53 * for any local user. And once the systems exits sleep or hibernation, the notification would be
54 * just noise, in particular for auto-suspend. */
56 IN_SET(m
->scheduled_shutdown_action
->handle
,
60 HANDLE_SUSPEND_THEN_HIBERNATE
))
63 return !streq_ptr(p
, m
->scheduled_shutdown_tty
);
66 static int warn_wall(Manager
*m
, usec_t n
) {
69 if (!m
->scheduled_shutdown_action
)
72 bool left
= m
->scheduled_shutdown_timeout
> n
;
74 _cleanup_free_
char *l
= NULL
;
75 if (asprintf(&l
, "%s%sThe system will %s %s%s!",
76 strempty(m
->wall_message
),
77 isempty(m
->wall_message
) ? "" : "\n",
78 handle_action_verb_to_string(m
->scheduled_shutdown_action
->handle
),
80 left
? FORMAT_TIMESTAMP(m
->scheduled_shutdown_timeout
) : "") < 0) {
83 return 1; /* We're out-of-memory for now, but let's try to print the message later */
86 _cleanup_free_
char *username
= uid_to_name(m
->scheduled_shutdown_uid
);
88 int level
= left
? LOG_INFO
: LOG_NOTICE
;
92 "ACTION=%s", handle_action_to_string(m
->scheduled_shutdown_action
->handle
),
93 "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_SCHEDULED_STR
,
94 username
? "OPERATOR=%s" : NULL
, username
);
96 if (m
->enable_wall_messages
)
97 utmp_wall(l
, username
, m
->scheduled_shutdown_tty
, logind_wall_tty_filter
, m
);
102 static int wall_message_timeout_handler(
107 Manager
*m
= ASSERT_PTR(userdata
);
110 assert(s
== m
->wall_message_timeout_source
);
112 usec_t n
= now(CLOCK_REALTIME
);
118 usec_t next
= when_wall(n
, m
->scheduled_shutdown_timeout
);
120 r
= sd_event_source_set_time(s
, n
+ next
);
122 return log_error_errno(r
, "sd_event_source_set_time() failed. %m");
124 r
= sd_event_source_set_enabled(s
, SD_EVENT_ONESHOT
);
126 return log_error_errno(r
, "sd_event_source_set_enabled() failed. %m");
132 int manager_setup_wall_message_timer(Manager
*m
) {
137 usec_t n
= now(CLOCK_REALTIME
);
138 usec_t elapse
= m
->scheduled_shutdown_timeout
;
140 /* wall message handling */
142 if (!m
->scheduled_shutdown_action
)
145 if (elapse
> 0 && elapse
< n
)
148 /* Warn immediately if less than 15 minutes are left */
149 if (elapse
== 0 || elapse
- n
< 15 * USEC_PER_MINUTE
) {
155 elapse
= when_wall(n
, elapse
);
159 r
= event_reset_time(m
->event
, &m
->wall_message_timeout_source
,
162 wall_message_timeout_handler
, m
,
163 0, "wall-message-timer", true);
166 m
->wall_message_timeout_source
= sd_event_source_unref(m
->wall_message_timeout_source
);
167 return log_error_errno(r
, "Failed to set up wall message timer: %m");