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