]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl-logind.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[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"
9#include "process-util.h"
10#include "systemctl-logind.h"
11#include "systemctl-start-unit.h"
12#include "systemctl-util.h"
13#include "systemctl.h"
14#include "terminal-util.h"
15#include "user-util.h"
16
17int logind_set_wall_message(void) {
18#if ENABLE_LOGIND
19 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
20 sd_bus *bus;
21 _cleanup_free_ char *m = NULL;
22 int r;
23
24 r = acquire_bus(BUS_FULL, &bus);
25 if (r < 0)
26 return r;
27
28 m = strv_join(arg_wall, " ");
29 if (!m)
30 return log_oom();
31
32 log_debug("%s wall message \"%s\".", arg_dry_run ? "Would set" : "Setting", m);
33 if (arg_dry_run)
34 return 0;
35
36 r = bus_call_method(bus, bus_login_mgr, "SetWallMessage", &error, NULL, "sb", m, !arg_no_wall);
37 if (r < 0)
38 return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
39#endif
40 return 0;
41}
42
43/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
44int logind_reboot(enum action a) {
45#if ENABLE_LOGIND
46 static const struct {
47 const char *method;
48 const char *description;
49 } actions[_ACTION_MAX] = {
50 [ACTION_POWEROFF] = { "PowerOff", "power off system" },
51 [ACTION_REBOOT] = { "Reboot", "reboot system" },
52 [ACTION_HALT] = { "Halt", "halt system" },
53 [ACTION_SUSPEND] = { "Suspend", "suspend system" },
54 [ACTION_HIBERNATE] = { "Hibernate", "hibernate system" },
55 [ACTION_HYBRID_SLEEP] = { "HybridSleep", "put system into hybrid sleep" },
56 [ACTION_SUSPEND_THEN_HIBERNATE] = { "SuspendThenHibernate", "suspend system, hibernate later" },
57 };
58
59 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
60 sd_bus *bus;
61 int r;
62
63 if (a < 0 || a >= _ACTION_MAX || !actions[a].method)
64 return -EINVAL;
65
66 r = acquire_bus(BUS_FULL, &bus);
67 if (r < 0)
68 return r;
69
70 polkit_agent_open_maybe();
71 (void) logind_set_wall_message();
72
73 log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", actions[a].method);
74
75 if (arg_dry_run)
76 return 0;
77
78 r = bus_call_method(bus, bus_login_mgr, actions[a].method, &error, NULL, "b", arg_ask_password);
79 if (r < 0)
80 return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
81
82 return 0;
83#else
84 return -ENOSYS;
85#endif
86}
87
88int logind_check_inhibitors(enum action a) {
89#if ENABLE_LOGIND
90 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
91 _cleanup_strv_free_ char **sessions = NULL;
92 const char *what, *who, *why, *mode;
93 uint32_t uid, pid;
94 sd_bus *bus;
95 unsigned c = 0;
96 char **s;
97 int r;
98
99 if (arg_ignore_inhibitors || arg_force > 0)
100 return 0;
101
102 if (arg_when > 0)
103 return 0;
104
105 if (geteuid() == 0)
106 return 0;
107
108 if (!on_tty())
109 return 0;
110
111 if (arg_transport != BUS_TRANSPORT_LOCAL)
112 return 0;
113
114 r = acquire_bus(BUS_FULL, &bus);
115 if (r < 0)
116 return r;
117
118 r = bus_call_method(bus, bus_login_mgr, "ListInhibitors", NULL, &reply, NULL);
119 if (r < 0)
120 /* If logind is not around, then there are no inhibitors... */
121 return 0;
122
123 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
124 if (r < 0)
125 return bus_log_parse_error(r);
126
127 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
128 _cleanup_free_ char *comm = NULL, *user = NULL;
129 _cleanup_strv_free_ char **sv = NULL;
130
131 if (!streq(mode, "block"))
132 continue;
133
134 sv = strv_split(what, ":");
135 if (!sv)
136 return log_oom();
137
138 if (!pid_is_valid((pid_t) pid))
139 return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid PID "PID_FMT".", (pid_t) pid);
140
141 if (!strv_contains(sv,
142 IN_SET(a,
143 ACTION_HALT,
144 ACTION_POWEROFF,
145 ACTION_REBOOT,
146 ACTION_KEXEC) ? "shutdown" : "sleep"))
147 continue;
148
74d6421d 149 (void) get_process_comm(pid, &comm);
daf71ef6
LP
150 user = uid_to_name(uid);
151
152 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
153 who, (pid_t) pid, strna(comm), strna(user), why);
154
155 c++;
156 }
157 if (r < 0)
158 return bus_log_parse_error(r);
159
160 r = sd_bus_message_exit_container(reply);
161 if (r < 0)
162 return bus_log_parse_error(r);
163
164 /* Check for current sessions */
165 sd_get_sessions(&sessions);
166 STRV_FOREACH(s, sessions) {
167 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
168
169 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
170 continue;
171
172 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
173 continue;
174
175 if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "wayland", "tty", "mir"))
176 continue;
177
178 sd_session_get_tty(*s, &tty);
179 sd_session_get_seat(*s, &seat);
180 sd_session_get_service(*s, &service);
181 user = uid_to_name(uid);
182
183 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
184 c++;
185 }
186
187 if (c <= 0)
188 return 0;
189
d7a0f1f4
FS
190 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
191 "Please retry operation after closing inhibitors and logging out other users.\n"
192 "Alternatively, ignore inhibitors and users with 'systemctl %s -i'.",
193 action_table[a].verb);
daf71ef6
LP
194#else
195 return 0;
196#endif
197}
198
199int prepare_firmware_setup(void) {
200
201 if (!arg_firmware_setup)
202 return 0;
203
204#if ENABLE_LOGIND
205 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
206 sd_bus *bus;
207 int r;
208
209 r = acquire_bus(BUS_FULL, &bus);
210 if (r < 0)
211 return r;
212
213 r = bus_call_method(bus, bus_login_mgr, "SetRebootToFirmwareSetup", &error, NULL, "b", true);
214 if (r < 0)
215 return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
216
217 return 0;
218#else
219 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
220 "Booting into firmware setup not supported.");
221#endif
222}
223
224int prepare_boot_loader_menu(void) {
225
226 if (arg_boot_loader_menu == USEC_INFINITY)
227 return 0;
228
229#if ENABLE_LOGIND
230 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
231 sd_bus *bus;
232 int r;
233
234 r = acquire_bus(BUS_FULL, &bus);
235 if (r < 0)
236 return r;
237
238 r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderMenu", &error, NULL, "t", arg_boot_loader_menu);
239 if (r < 0)
240 return log_error_errno(r, "Cannot indicate to boot loader to enter boot loader entry menu: %s", bus_error_message(&error, r));
241
242 return 0;
243#else
244 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
245 "Booting into boot loader menu not supported.");
246#endif
247}
248
249int prepare_boot_loader_entry(void) {
250
251 if (!arg_boot_loader_entry)
252 return 0;
253
254#if ENABLE_LOGIND
255 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
256 sd_bus *bus;
257 int r;
258
259 r = acquire_bus(BUS_FULL, &bus);
260 if (r < 0)
261 return r;
262
263 r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderEntry", &error, NULL, "s", arg_boot_loader_entry);
264 if (r < 0)
265 return log_error_errno(r, "Cannot set boot into loader entry '%s': %s", arg_boot_loader_entry, bus_error_message(&error, r));
266
267 return 0;
268#else
269 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
270 "Booting into boot loader entry not supported.");
271#endif
272}
273
274int logind_schedule_shutdown(void) {
275
276#if ENABLE_LOGIND
277 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
278 char date[FORMAT_TIMESTAMP_MAX];
279 const char *action;
280 const char *log_action;
281 sd_bus *bus;
282 int r;
283
284 r = acquire_bus(BUS_FULL, &bus);
285 if (r < 0)
286 return r;
287
288 switch (arg_action) {
289 case ACTION_HALT:
290 action = "halt";
291 log_action = "Shutdown";
292 break;
293 case ACTION_POWEROFF:
294 action = "poweroff";
295 log_action = "Shutdown";
296 break;
297 case ACTION_KEXEC:
298 action = "kexec";
299 log_action = "Reboot via kexec";
300 break;
301 case ACTION_EXIT:
302 action = "exit";
303 log_action = "Shutdown";
304 break;
305 case ACTION_REBOOT:
306 default:
307 action = "reboot";
308 log_action = "Reboot";
309 break;
310 }
311
312 if (arg_dry_run)
313 action = strjoina("dry-", action);
314
315 (void) logind_set_wall_message();
316
317 r = bus_call_method(bus, bus_login_mgr, "ScheduleShutdown", &error, NULL, "st", action, arg_when);
318 if (r < 0)
319 return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
320
321 if (!arg_quiet)
322 log_info("%s scheduled for %s, use 'shutdown -c' to cancel.", log_action, format_timestamp_style(date, sizeof(date), arg_when, arg_timestamp_style));
323 return 0;
324#else
325 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
326 "Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
327#endif
328}
329
330int logind_cancel_shutdown(void) {
331#if ENABLE_LOGIND
332 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
333 sd_bus *bus;
334 int r;
335
336 r = acquire_bus(BUS_FULL, &bus);
337 if (r < 0)
338 return r;
339
340 (void) logind_set_wall_message();
341
342 r = bus_call_method(bus, bus_login_mgr, "CancelScheduledShutdown", &error, NULL, NULL);
343 if (r < 0)
344 return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
345
346 return 0;
347#else
348 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
349 "Not compiled with logind support, cannot cancel scheduled shutdowns.");
350#endif
351}
352
353int help_boot_loader_entry(void) {
354#if ENABLE_LOGIND
355 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
356 _cleanup_strv_free_ char **l = NULL;
357 sd_bus *bus;
358 char **i;
359 int r;
360
361 r = acquire_bus(BUS_FULL, &bus);
362 if (r < 0)
363 return r;
364
365 r = bus_get_property_strv(bus, bus_login_mgr, "BootLoaderEntries", &error, &l);
366 if (r < 0)
367 return log_error_errno(r, "Failed to enumerate boot loader entries: %s", bus_error_message(&error, r));
368
369 if (strv_isempty(l))
370 return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "No boot loader entries discovered.");
371
372 STRV_FOREACH(i, l)
373 puts(*i);
374
375 return 0;
376#else
377 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
378 "Not compiled with logind support, cannot display boot loader entries.");
379#endif
380}