]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl-logind.c
Merge pull request #29853 from YHNdnzj/sleep-automated
[thirdparty/systemd.git] / src / systemctl / systemctl-logind.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
daf71ef6
LP
2
3#include <unistd.h>
4
5#include "sd-login.h"
6
7#include "bus-error.h"
8#include "bus-locator.h"
8885fed4 9#include "login-util.h"
daf71ef6
LP
10#include "process-util.h"
11#include "systemctl-logind.h"
12#include "systemctl-start-unit.h"
13#include "systemctl-util.h"
14#include "systemctl.h"
15#include "terminal-util.h"
16#include "user-util.h"
17
346840b1 18static int logind_set_wall_message(sd_bus *bus) {
daf71ef6
LP
19#if ENABLE_LOGIND
20 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
daf71ef6
LP
21 _cleanup_free_ char *m = NULL;
22 int r;
23
9071eea0
MY
24 assert(bus);
25
daf71ef6
LP
26 m = strv_join(arg_wall, " ");
27 if (!m)
28 return log_oom();
29
30 log_debug("%s wall message \"%s\".", arg_dry_run ? "Would set" : "Setting", m);
31 if (arg_dry_run)
32 return 0;
33
34 r = bus_call_method(bus, bus_login_mgr, "SetWallMessage", &error, NULL, "sb", m, !arg_no_wall);
35 if (r < 0)
36 return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
37#endif
38 return 0;
39}
40
41/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
42int logind_reboot(enum action a) {
43#if ENABLE_LOGIND
1cc11a09
ZJS
44 static const char* actions[_ACTION_MAX] = {
45 [ACTION_POWEROFF] = "PowerOff",
46 [ACTION_REBOOT] = "Reboot",
47 [ACTION_KEXEC] = "Reboot",
34f21ff6 48 [ACTION_SOFT_REBOOT] = "Reboot",
1cc11a09
ZJS
49 [ACTION_HALT] = "Halt",
50 [ACTION_SUSPEND] = "Suspend",
51 [ACTION_HIBERNATE] = "Hibernate",
52 [ACTION_HYBRID_SLEEP] = "HybridSleep",
53 [ACTION_SUSPEND_THEN_HIBERNATE] = "SuspendThenHibernate",
5b356289 54 [ACTION_SLEEP] = "Sleep",
daf71ef6
LP
55 };
56
57 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
8885fed4 58 uint64_t flags = 0;
daf71ef6
LP
59 sd_bus *bus;
60 int r;
61
9071eea0
MY
62 assert(a >= 0);
63 assert(a < _ACTION_MAX);
64
65 if (!actions[a])
daf71ef6
LP
66 return -EINVAL;
67
68 r = acquire_bus(BUS_FULL, &bus);
69 if (r < 0)
70 return r;
71
72 polkit_agent_open_maybe();
346840b1 73 (void) logind_set_wall_message(bus);
daf71ef6 74
5b356289 75 const char *method_with_flags = a == ACTION_SLEEP ? actions[a] : strjoina(actions[a], "WithFlags");
1cc11a09
ZJS
76
77 log_debug("%s org.freedesktop.login1.Manager %s dbus call.",
78 arg_dry_run ? "Would execute" : "Executing", method_with_flags);
daf71ef6
LP
79
80 if (arg_dry_run)
81 return 0;
82
8885fed4 83 SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0);
665a3d6d
LB
84 SET_FLAG(flags,
85 SD_LOGIND_REBOOT_VIA_KEXEC,
86 a == ACTION_KEXEC || (a == ACTION_REBOOT && getenv_bool("SYSTEMCTL_SKIP_AUTO_KEXEC") <= 0));
87 SET_FLAG(flags,
88 SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP,
89 a == ACTION_REBOOT && getenv_bool("SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT") <= 0);
34f21ff6 90 SET_FLAG(flags, SD_LOGIND_SOFT_REBOOT, a == ACTION_SOFT_REBOOT);
8885fed4 91
8885fed4 92 r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags);
d334c121
LB
93 if (r < 0 && FLAGS_SET(flags, SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP) &&
94 sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
95 sd_bus_error_free(&error);
96 r = bus_call_method(
97 bus,
98 bus_login_mgr,
99 method_with_flags,
100 &error,
101 NULL,
102 "t",
103 flags & ~SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP);
104 }
8885fed4
DR
105 if (r >= 0)
106 return 0;
5b356289 107 if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD) || a == ACTION_SLEEP)
1cc11a09 108 return log_error_errno(r, "Call to %s failed: %s", actions[a], bus_error_message(&error, r));
8885fed4 109
1cc11a09
ZJS
110 /* Fall back to original methods in case there is an older version of systemd-logind */
111 log_debug("Method %s not available: %s. Falling back to %s", method_with_flags, bus_error_message(&error, r), actions[a]);
8885fed4
DR
112 sd_bus_error_free(&error);
113
1cc11a09 114 r = bus_call_method(bus, bus_login_mgr, actions[a], &error, NULL, "b", arg_ask_password);
daf71ef6 115 if (r < 0)
1cc11a09 116 return log_error_errno(r, "Call to %s failed: %s", actions[a], bus_error_message(&error, r));
daf71ef6
LP
117
118 return 0;
119#else
120 return -ENOSYS;
121#endif
122}
123
124int logind_check_inhibitors(enum action a) {
125#if ENABLE_LOGIND
126 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
127 _cleanup_strv_free_ char **sessions = NULL;
128 const char *what, *who, *why, *mode;
129 uint32_t uid, pid;
130 sd_bus *bus;
131 unsigned c = 0;
daf71ef6
LP
132 int r;
133
9071eea0
MY
134 assert(a >= 0);
135 assert(a < _ACTION_MAX);
136
4327574f 137 if (arg_check_inhibitors == 0 || arg_force > 0)
daf71ef6
LP
138 return 0;
139
140 if (arg_when > 0)
141 return 0;
142
4327574f
FS
143 if (arg_check_inhibitors < 0) {
144 if (geteuid() == 0)
145 return 0;
daf71ef6 146
4327574f
FS
147 if (!on_tty())
148 return 0;
149 }
daf71ef6
LP
150
151 if (arg_transport != BUS_TRANSPORT_LOCAL)
152 return 0;
153
154 r = acquire_bus(BUS_FULL, &bus);
155 if (r < 0)
156 return r;
157
158 r = bus_call_method(bus, bus_login_mgr, "ListInhibitors", NULL, &reply, NULL);
159 if (r < 0)
160 /* If logind is not around, then there are no inhibitors... */
161 return 0;
162
163 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
164 if (r < 0)
165 return bus_log_parse_error(r);
166
167 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
168 _cleanup_free_ char *comm = NULL, *user = NULL;
169 _cleanup_strv_free_ char **sv = NULL;
170
171 if (!streq(mode, "block"))
172 continue;
173
174 sv = strv_split(what, ":");
175 if (!sv)
176 return log_oom();
177
178 if (!pid_is_valid((pid_t) pid))
179 return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid PID "PID_FMT".", (pid_t) pid);
180
181 if (!strv_contains(sv,
182 IN_SET(a,
183 ACTION_HALT,
184 ACTION_POWEROFF,
185 ACTION_REBOOT,
186 ACTION_KEXEC) ? "shutdown" : "sleep"))
187 continue;
188
d7d74854 189 (void) pid_get_comm(pid, &comm);
daf71ef6
LP
190 user = uid_to_name(uid);
191
192 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
193 who, (pid_t) pid, strna(comm), strna(user), why);
194
195 c++;
196 }
197 if (r < 0)
198 return bus_log_parse_error(r);
199
200 r = sd_bus_message_exit_container(reply);
201 if (r < 0)
202 return bus_log_parse_error(r);
203
204 /* Check for current sessions */
205 sd_get_sessions(&sessions);
206 STRV_FOREACH(s, sessions) {
207 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
208
209 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
210 continue;
211
212 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
213 continue;
214
215 if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "wayland", "tty", "mir"))
216 continue;
217
218 sd_session_get_tty(*s, &tty);
219 sd_session_get_seat(*s, &seat);
220 sd_session_get_service(*s, &service);
221 user = uid_to_name(uid);
222
223 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
224 c++;
225 }
226
227 if (c <= 0)
228 return 0;
229
d7a0f1f4
FS
230 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
231 "Please retry operation after closing inhibitors and logging out other users.\n"
232 "Alternatively, ignore inhibitors and users with 'systemctl %s -i'.",
233 action_table[a].verb);
daf71ef6
LP
234#else
235 return 0;
236#endif
237}
238
239int prepare_firmware_setup(void) {
240
241 if (!arg_firmware_setup)
242 return 0;
243
244#if ENABLE_LOGIND
245 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
246 sd_bus *bus;
247 int r;
248
249 r = acquire_bus(BUS_FULL, &bus);
250 if (r < 0)
251 return r;
252
253 r = bus_call_method(bus, bus_login_mgr, "SetRebootToFirmwareSetup", &error, NULL, "b", true);
254 if (r < 0)
255 return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
256
257 return 0;
258#else
259 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
260 "Booting into firmware setup not supported.");
261#endif
262}
263
264int prepare_boot_loader_menu(void) {
265
266 if (arg_boot_loader_menu == USEC_INFINITY)
267 return 0;
268
269#if ENABLE_LOGIND
270 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
271 sd_bus *bus;
272 int r;
273
274 r = acquire_bus(BUS_FULL, &bus);
275 if (r < 0)
276 return r;
277
278 r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderMenu", &error, NULL, "t", arg_boot_loader_menu);
279 if (r < 0)
280 return log_error_errno(r, "Cannot indicate to boot loader to enter boot loader entry menu: %s", bus_error_message(&error, r));
281
282 return 0;
283#else
284 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
285 "Booting into boot loader menu not supported.");
286#endif
287}
288
289int prepare_boot_loader_entry(void) {
290
291 if (!arg_boot_loader_entry)
292 return 0;
293
294#if ENABLE_LOGIND
295 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
296 sd_bus *bus;
297 int r;
298
299 r = acquire_bus(BUS_FULL, &bus);
300 if (r < 0)
301 return r;
302
303 r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderEntry", &error, NULL, "s", arg_boot_loader_entry);
304 if (r < 0)
305 return log_error_errno(r, "Cannot set boot into loader entry '%s': %s", arg_boot_loader_entry, bus_error_message(&error, r));
306
307 return 0;
308#else
309 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
310 "Booting into boot loader entry not supported.");
311#endif
312}
313
92b00e86 314int logind_schedule_shutdown(enum action a) {
daf71ef6
LP
315#if ENABLE_LOGIND
316 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
daf71ef6 317 const char *action;
daf71ef6
LP
318 sd_bus *bus;
319 int r;
320
92b00e86
MY
321 assert(a >= 0);
322 assert(a < _ACTION_MAX);
323
daf71ef6
LP
324 r = acquire_bus(BUS_FULL, &bus);
325 if (r < 0)
326 return r;
327
92b00e86 328 action = action_table[a].verb;
00886e06
LN
329 if (!action)
330 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Scheduling not supported for this action.");
daf71ef6
LP
331
332 if (arg_dry_run)
333 action = strjoina("dry-", action);
334
346840b1 335 (void) logind_set_wall_message(bus);
daf71ef6
LP
336
337 r = bus_call_method(bus, bus_login_mgr, "ScheduleShutdown", &error, NULL, "st", action, arg_when);
338 if (r < 0)
38d55bf2 339 return log_warning_errno(r, "Failed to schedule shutdown: %s", bus_error_message(&error, r));
daf71ef6
LP
340
341 if (!arg_quiet)
8e985681
LN
342 logind_show_shutdown();
343
daf71ef6
LP
344 return 0;
345#else
346 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
347 "Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
348#endif
349}
350
351int logind_cancel_shutdown(void) {
352#if ENABLE_LOGIND
353 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
354 sd_bus *bus;
355 int r;
356
357 r = acquire_bus(BUS_FULL, &bus);
358 if (r < 0)
359 return r;
360
346840b1 361 (void) logind_set_wall_message(bus);
daf71ef6
LP
362
363 r = bus_call_method(bus, bus_login_mgr, "CancelScheduledShutdown", &error, NULL, NULL);
364 if (r < 0)
365 return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
366
367 return 0;
368#else
369 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
370 "Not compiled with logind support, cannot cancel scheduled shutdowns.");
371#endif
372}
373
a9c3cc8d
LN
374int logind_show_shutdown(void) {
375#if ENABLE_LOGIND
376 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
377 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
378 sd_bus *bus;
1433e1f9 379 const char *action, *pretty_action;
a9c3cc8d
LN
380 uint64_t elapse;
381 int r;
382
383 r = acquire_bus(BUS_FULL, &bus);
384 if (r < 0)
385 return r;
386
387 r = bus_get_property(bus, bus_login_mgr, "ScheduledShutdown", &error, &reply, "(st)");
388 if (r < 0)
389 return log_error_errno(r, "Failed to query scheduled shutdown: %s", bus_error_message(&error, r));
390
391 r = sd_bus_message_read(reply, "(st)", &action, &elapse);
392 if (r < 0)
393 return r;
394
395 if (isempty(action))
396 return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "No scheduled shutdown.");
397
f80c3d5c 398 if (STR_IN_SET(action, "halt", "poweroff", "exit"))
1433e1f9 399 pretty_action = "Shutdown";
8e985681 400 else if (streq(action, "kexec"))
1433e1f9 401 pretty_action = "Reboot via kexec";
8e985681 402 else if (streq(action, "reboot"))
1433e1f9
MY
403 pretty_action = "Reboot";
404 else /* If we don't recognize the action string, we'll show it as-is */
405 pretty_action = action;
406
407 if (arg_action == ACTION_SYSTEMCTL)
408 log_info("%s scheduled for %s, use 'systemctl %s --when=cancel' to cancel.",
409 pretty_action,
410 FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style),
411 action);
412 else
413 log_info("%s scheduled for %s, use 'shutdown -c' to cancel.",
414 pretty_action,
415 FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style));
a9c3cc8d
LN
416
417 return 0;
418#else
419 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
420 "Not compiled with logind support, cannot show scheduled shutdowns.");
421#endif
422}
423
daf71ef6
LP
424int help_boot_loader_entry(void) {
425#if ENABLE_LOGIND
426 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
427 _cleanup_strv_free_ char **l = NULL;
428 sd_bus *bus;
daf71ef6
LP
429 int r;
430
431 r = acquire_bus(BUS_FULL, &bus);
432 if (r < 0)
433 return r;
434
435 r = bus_get_property_strv(bus, bus_login_mgr, "BootLoaderEntries", &error, &l);
436 if (r < 0)
437 return log_error_errno(r, "Failed to enumerate boot loader entries: %s", bus_error_message(&error, r));
438
439 if (strv_isempty(l))
440 return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "No boot loader entries discovered.");
441
442 STRV_FOREACH(i, l)
443 puts(*i);
444
445 return 0;
446#else
447 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
448 "Not compiled with logind support, cannot display boot loader entries.");
449#endif
450}