]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-core.c
polkit: turn "interactive" flag to polkit APIs into a proper flags field (#31715)
[thirdparty/systemd.git] / src / login / logind-core.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2b3ab29d 2
2b3ab29d 3#include <fcntl.h>
cf0fbc49
TA
4#include <sys/ioctl.h>
5#include <sys/types.h>
2b3ab29d
ZJS
6#include <linux/vt.h>
7
4f209af7
YW
8#include "sd-device.h"
9
b5efdb8a 10#include "alloc-util.h"
af4e8e86 11#include "battery-util.h"
cc377381 12#include "bus-error.h"
59228d0d 13#include "bus-locator.h"
3ffd4af2
LP
14#include "bus-util.h"
15#include "cgroup-util.h"
ae98d374 16#include "conf-parser.h"
8437c059 17#include "device-util.h"
d4bd786d 18#include "efi-loader.h"
66855de7 19#include "errno-util.h"
3ffd4af2 20#include "fd-util.h"
eefc66aa 21#include "limits-util.h"
cc377381 22#include "logind.h"
c29b65f7 23#include "parse-util.h"
3d0ef5c7 24#include "path-util.h"
dccca82b 25#include "process-util.h"
d7a0f1f4 26#include "stdio-util.h"
3ffd4af2 27#include "strv.h"
288a74cc 28#include "terminal-util.h"
91bd2c34 29#include "udev-util.h"
b1d4f8e1 30#include "user-util.h"
22c902fa 31#include "userdb.h"
c2a99093 32#include "utmp-wtmp.h"
2b3ab29d 33
ae98d374 34void manager_reset_config(Manager *m) {
23462168
LP
35 assert(m);
36
ae98d374
ZJS
37 m->n_autovts = 6;
38 m->reserve_vt = 6;
39 m->remove_ipc = true;
40 m->inhibit_delay_max = 5 * USEC_PER_SEC;
9afe9efb
LP
41 m->user_stop_delay = 10 * USEC_PER_SEC;
42
cd4dd90b
MY
43 m->handle_action_sleep_mask = HANDLE_ACTION_SLEEP_MASK_DEFAULT;
44
ae98d374 45 m->handle_power_key = HANDLE_POWEROFF;
a520bb66
YA
46 m->handle_power_key_long_press = HANDLE_IGNORE;
47 m->handle_reboot_key = HANDLE_REBOOT;
48 m->handle_reboot_key_long_press = HANDLE_POWEROFF;
ae98d374 49 m->handle_suspend_key = HANDLE_SUSPEND;
a520bb66 50 m->handle_suspend_key_long_press = HANDLE_HIBERNATE;
ae98d374 51 m->handle_hibernate_key = HANDLE_HIBERNATE;
a520bb66
YA
52 m->handle_hibernate_key_long_press = HANDLE_IGNORE;
53
ae98d374
ZJS
54 m->handle_lid_switch = HANDLE_SUSPEND;
55 m->handle_lid_switch_ep = _HANDLE_ACTION_INVALID;
56 m->handle_lid_switch_docked = HANDLE_IGNORE;
a520bb66 57
ae98d374
ZJS
58 m->power_key_ignore_inhibited = false;
59 m->suspend_key_ignore_inhibited = false;
60 m->hibernate_key_ignore_inhibited = false;
61 m->lid_switch_ignore_inhibited = true;
adbb2b6a 62 m->reboot_key_ignore_inhibited = false;
ae98d374
ZJS
63
64 m->holdoff_timeout_usec = 30 * USEC_PER_SEC;
65
66 m->idle_action_usec = 30 * USEC_PER_MINUTE;
67 m->idle_action = HANDLE_IGNORE;
68
69 m->runtime_dir_size = physical_memory_scale(10U, 100U); /* 10% */
cc1c85fb 70 m->runtime_dir_inodes = DIV_ROUND_UP(m->runtime_dir_size, 4096); /* 4k per inode */
ae98d374
ZJS
71 m->sessions_max = 8192;
72 m->inhibitors_max = 8192;
73
74 m->kill_user_processes = KILL_USER_PROCESSES;
75
76 m->kill_only_users = strv_free(m->kill_only_users);
77 m->kill_exclude_users = strv_free(m->kill_exclude_users);
82325af3
MS
78
79 m->stop_idle_session_usec = USEC_INFINITY;
ae98d374
ZJS
80}
81
82int manager_parse_config_file(Manager *m) {
83 assert(m);
84
6378f257
ZJS
85 return config_parse_standard_file_with_dropins(
86 "systemd/logind.conf",
87 "Login\0",
88 config_item_perf_lookup, logind_gperf_lookup,
89 CONFIG_PARSE_WARN,
90 /* userdata= */ m);
ae98d374
ZJS
91}
92
f68d1485 93int manager_add_device(Manager *m, const char *sysfs, bool master, Device **ret_device) {
2b3ab29d
ZJS
94 Device *d;
95
96 assert(m);
97 assert(sysfs);
98
99 d = hashmap_get(m->devices, sysfs);
61376f96 100 if (d)
2b3ab29d
ZJS
101 /* we support adding master-flags, but not removing them */
102 d->master = d->master || master;
61376f96
ZJS
103 else {
104 d = device_new(m, sysfs, master);
105 if (!d)
106 return -ENOMEM;
2b3ab29d
ZJS
107 }
108
f68d1485
ZJS
109 if (ret_device)
110 *ret_device = d;
2b3ab29d
ZJS
111
112 return 0;
113}
114
f68d1485 115int manager_add_seat(Manager *m, const char *id, Seat **ret_seat) {
2b3ab29d 116 Seat *s;
8c29a457 117 int r;
2b3ab29d
ZJS
118
119 assert(m);
120 assert(id);
121
122 s = hashmap_get(m->seats, id);
61376f96 123 if (!s) {
2454cee3 124 r = seat_new(m, id, &s);
8c29a457
LP
125 if (r < 0)
126 return r;
2b3ab29d
ZJS
127 }
128
f68d1485
ZJS
129 if (ret_seat)
130 *ret_seat = s;
2b3ab29d
ZJS
131
132 return 0;
133}
134
f68d1485 135int manager_add_session(Manager *m, const char *id, Session **ret_session) {
2b3ab29d 136 Session *s;
8c29a457 137 int r;
2b3ab29d
ZJS
138
139 assert(m);
140 assert(id);
141
142 s = hashmap_get(m->sessions, id);
61376f96 143 if (!s) {
2454cee3 144 r = session_new(m, id, &s);
8c29a457
LP
145 if (r < 0)
146 return r;
2b3ab29d
ZJS
147 }
148
f68d1485
ZJS
149 if (ret_session)
150 *ret_session = s;
2b3ab29d
ZJS
151
152 return 0;
153}
154
d5ac9d06
LP
155int manager_add_user(
156 Manager *m,
22c902fa 157 UserRecord *ur,
f68d1485 158 User **ret_user) {
d5ac9d06 159
2b3ab29d 160 User *u;
157f5057 161 int r;
2b3ab29d
ZJS
162
163 assert(m);
22c902fa 164 assert(ur);
2b3ab29d 165
22c902fa 166 u = hashmap_get(m->users, UID_TO_PTR(ur->uid));
61376f96 167 if (!u) {
2454cee3 168 r = user_new(m, ur, &u);
157f5057
DH
169 if (r < 0)
170 return r;
2b3ab29d
ZJS
171 }
172
f68d1485
ZJS
173 if (ret_user)
174 *ret_user = u;
2b3ab29d
ZJS
175
176 return 0;
177}
178
d5ac9d06
LP
179int manager_add_user_by_name(
180 Manager *m,
181 const char *name,
f68d1485 182 User **ret_user) {
d5ac9d06 183
22c902fa 184 _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
2b3ab29d
ZJS
185 int r;
186
187 assert(m);
188 assert(name);
189
80d88a82 190 r = userdb_by_name(name, USERDB_SUPPRESS_SHADOW, &ur);
2b3ab29d
ZJS
191 if (r < 0)
192 return r;
193
22c902fa 194 return manager_add_user(m, ur, ret_user);
2b3ab29d
ZJS
195}
196
22c902fa
LP
197int manager_add_user_by_uid(
198 Manager *m,
199 uid_t uid,
200 User **ret_user) {
201
202 _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
203 int r;
2b3ab29d
ZJS
204
205 assert(m);
22c902fa 206 assert(uid_is_valid(uid));
2b3ab29d 207
80d88a82 208 r = userdb_by_uid(uid, USERDB_SUPPRESS_SHADOW, &ur);
22c902fa
LP
209 if (r < 0)
210 return r;
2b3ab29d 211
22c902fa 212 return manager_add_user(m, ur, ret_user);
2b3ab29d
ZJS
213}
214
81280b2a 215int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **ret) {
2b3ab29d 216 Inhibitor *i;
81280b2a 217 int r;
2b3ab29d
ZJS
218
219 assert(m);
220 assert(id);
221
222 i = hashmap_get(m->inhibitors, id);
81280b2a
LP
223 if (!i) {
224 r = inhibitor_new(&i, m, id);
225 if (r < 0)
226 return r;
2b3ab29d
ZJS
227 }
228
81280b2a
LP
229 if (ret)
230 *ret = i;
2b3ab29d
ZJS
231
232 return 0;
233}
234
f68d1485 235int manager_add_button(Manager *m, const char *name, Button **ret_button) {
2b3ab29d
ZJS
236 Button *b;
237
238 assert(m);
239 assert(name);
240
241 b = hashmap_get(m->buttons, name);
61376f96
ZJS
242 if (!b) {
243 b = button_new(m, name);
244 if (!b)
245 return -ENOMEM;
2b3ab29d
ZJS
246 }
247
f68d1485
ZJS
248 if (ret_button)
249 *ret_button = b;
2b3ab29d
ZJS
250
251 return 0;
252}
253
4f209af7 254int manager_process_seat_device(Manager *m, sd_device *d) {
2b3ab29d
ZJS
255 Device *device;
256 int r;
257
258 assert(m);
259
a1130022 260 if (device_for_action(d, SD_DEVICE_REMOVE) ||
643bb924 261 sd_device_has_current_tag(d, "seat") <= 0) {
4f209af7
YW
262 const char *syspath;
263
264 r = sd_device_get_syspath(d, &syspath);
265 if (r < 0)
266 return 0;
2b3ab29d 267
4f209af7 268 device = hashmap_get(m->devices, syspath);
2b3ab29d
ZJS
269 if (!device)
270 return 0;
271
272 seat_add_to_gc_queue(device->seat);
273 device_free(device);
274
275 } else {
4f209af7 276 const char *sn, *syspath;
2b3ab29d 277 bool master;
4f209af7 278 Seat *seat;
2b3ab29d 279
4f209af7 280 if (sd_device_get_property_value(d, "ID_SEAT", &sn) < 0 || isempty(sn))
2b3ab29d
ZJS
281 sn = "seat0";
282
283 if (!seat_name_is_valid(sn)) {
76386309 284 log_device_warning(d, "Device with invalid seat name %s found, ignoring.", sn);
2b3ab29d
ZJS
285 return 0;
286 }
287
6a79c586 288 seat = hashmap_get(m->seats, sn);
643bb924 289 master = sd_device_has_current_tag(d, "master-of-seat") > 0;
6a79c586
LP
290
291 /* Ignore non-master devices for unknown seats */
292 if (!master && !seat)
2b3ab29d
ZJS
293 return 0;
294
4f209af7
YW
295 r = sd_device_get_syspath(d, &syspath);
296 if (r < 0)
297 return r;
298
299 r = manager_add_device(m, syspath, master, &device);
2b3ab29d
ZJS
300 if (r < 0)
301 return r;
302
303 if (!seat) {
304 r = manager_add_seat(m, sn, &seat);
305 if (r < 0) {
306 if (!device->seat)
307 device_free(device);
308
309 return r;
310 }
311 }
312
313 device_attach(device, seat);
314 seat_start(seat);
315 }
316
317 return 0;
318}
319
4f209af7 320int manager_process_button_device(Manager *m, sd_device *d) {
91bd2c34 321 const char *sysname;
2b3ab29d 322 Button *b;
2b3ab29d
ZJS
323 int r;
324
325 assert(m);
326
4f209af7
YW
327 r = sd_device_get_sysname(d, &sysname);
328 if (r < 0)
329 return r;
330
a1130022 331 if (device_for_action(d, SD_DEVICE_REMOVE) ||
3d01bfa7 332 sd_device_has_current_tag(d, "power-switch") <= 0)
2b3ab29d 333
3d01bfa7 334 button_free(hashmap_get(m->buttons, sysname));
2b3ab29d 335
3d01bfa7 336 else {
c679e12a 337 const char *sn;
2b3ab29d 338
4f209af7 339 r = manager_add_button(m, sysname, &b);
2b3ab29d
ZJS
340 if (r < 0)
341 return r;
342
4f209af7 343 if (sd_device_get_property_value(d, "ID_SEAT", &sn) < 0 || isempty(sn))
2b3ab29d
ZJS
344 sn = "seat0";
345
346 button_set_seat(b, sn);
2546b70a
LP
347
348 r = button_open(b);
349 if (r < 0) /* event device doesn't have any keys or switches relevant to us? (or any other error
350 * opening the device?) let's close the button again. */
351 button_free(b);
2b3ab29d
ZJS
352 }
353
354 return 0;
355}
356
8494f562 357int manager_get_session_by_pidref(Manager *m, const PidRef *pid, Session **ret) {
2b3ab29d
ZJS
358 _cleanup_free_ char *unit = NULL;
359 Session *s;
360 int r;
361
362 assert(m);
2b3ab29d 363
8494f562 364 if (!pidref_is_set(pid))
2b3ab29d
ZJS
365 return -EINVAL;
366
8494f562
MY
367 s = hashmap_get(m->sessions_by_leader, pid);
368 if (s) {
369 r = pidref_verify(pid);
370 if (r < 0)
371 return r;
372 } else {
373 r = cg_pidref_get_unit(pid, &unit);
374 if (r < 0)
375 return r;
376
377 s = hashmap_get(m->session_units, unit);
238794b1 378 }
14ef4a65
LP
379
380 if (ret)
381 *ret = s;
2b3ab29d 382
c9ee7160 383 return !!s;
2b3ab29d
ZJS
384}
385
14ef4a65 386int manager_get_user_by_pid(Manager *m, pid_t pid, User **ret) {
2b3ab29d 387 _cleanup_free_ char *unit = NULL;
c9ee7160 388 User *u = NULL;
2b3ab29d
ZJS
389 int r;
390
391 assert(m);
2b3ab29d 392
6f876815 393 if (!pid_is_valid(pid))
2b3ab29d
ZJS
394 return -EINVAL;
395
396 r = cg_pid_get_slice(pid, &unit);
c9ee7160
ZJS
397 if (r >= 0)
398 u = hashmap_get(m->user_units, unit);
14ef4a65
LP
399
400 if (ret)
401 *ret = u;
2b3ab29d 402
c9ee7160 403 return !!u;
2b3ab29d
ZJS
404}
405
406int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
407 Session *s;
408 bool idle_hint;
5cb14b37 409 dual_timestamp ts = DUAL_TIMESTAMP_NULL;
2b3ab29d
ZJS
410
411 assert(m);
412
85a428c6 413 idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
2b3ab29d 414
90e74a66 415 HASHMAP_FOREACH(s, m->sessions) {
2b3ab29d
ZJS
416 dual_timestamp k;
417 int ih;
418
b4f01bc1
LP
419 if (!SESSION_CLASS_CAN_IDLE(s->class))
420 continue;
421
2b3ab29d
ZJS
422 ih = session_get_idle_hint(s, &k);
423 if (ih < 0)
424 return ih;
425
426 if (!ih) {
427 if (!idle_hint) {
428 if (k.monotonic < ts.monotonic)
429 ts = k;
430 } else {
431 idle_hint = false;
432 ts = k;
433 }
434 } else if (idle_hint) {
435
436 if (k.monotonic > ts.monotonic)
437 ts = k;
438 }
439 }
440
441 if (t)
442 *t = ts;
443
444 return idle_hint;
445}
446
447bool manager_shall_kill(Manager *m, const char *user) {
448 assert(m);
449 assert(user);
450
a2ed7077
ZJS
451 if (!m->kill_exclude_users && streq(user, "root"))
452 return false;
453
2b3ab29d
ZJS
454 if (strv_contains(m->kill_exclude_users, user))
455 return false;
456
921f831d
ZJS
457 if (!strv_isempty(m->kill_only_users))
458 return strv_contains(m->kill_only_users, user);
2b3ab29d 459
921f831d 460 return m->kill_user_processes;
2b3ab29d
ZJS
461}
462
c29b65f7
AJ
463int config_parse_n_autovts(
464 const char *unit,
465 const char *filename,
466 unsigned line,
467 const char *section,
468 unsigned section_line,
469 const char *lvalue,
470 int ltype,
471 const char *rvalue,
472 void *data,
473 void *userdata) {
474
99534007 475 unsigned *n = ASSERT_PTR(data);
c29b65f7
AJ
476 unsigned o;
477 int r;
478
479 assert(filename);
480 assert(lvalue);
481 assert(rvalue);
c29b65f7
AJ
482
483 r = safe_atou(rvalue, &o);
484 if (r < 0) {
196d41bc
YW
485 log_syntax(unit, LOG_WARNING, filename, line, r,
486 "Failed to parse number of autovts, ignoring: %s", rvalue);
c29b65f7
AJ
487 return 0;
488 }
489
490 if (o > 15) {
196d41bc
YW
491 log_syntax(unit, LOG_WARNING, filename, line, 0,
492 "A maximum of 15 autovts are supported, ignoring: %s", rvalue);
c29b65f7
AJ
493 return 0;
494 }
495
496 *n = o;
497 return 0;
498}
499
14cb109d 500static int vt_is_busy(unsigned vtnr) {
2b3ab29d 501 struct vt_stat vt_stat;
6d95e7d9 502 int r;
254d1313 503 _cleanup_close_ int fd = -EBADF;
2b3ab29d
ZJS
504
505 assert(vtnr >= 1);
506
c29b65f7
AJ
507 /* VT_GETSTATE "cannot return state for more than 16 VTs, since v_state is short" */
508 assert(vtnr <= 15);
509
2b3ab29d
ZJS
510 /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
511 * we'd open the latter we'd open the foreground tty which
512 * hence would be unconditionally busy. By opening /dev/tty1
513 * we avoid this. Since tty1 is special and needs to be an
514 * explicitly loaded getty or DM this is safe. */
515
516 fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
517 if (fd < 0)
518 return -errno;
519
520 if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
521 r = -errno;
522 else
523 r = !!(vt_stat.v_state & (1 << vtnr));
524
2b3ab29d
ZJS
525 return r;
526}
527
14cb109d 528int manager_spawn_autovt(Manager *m, unsigned vtnr) {
4afd3348 529 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
14cb109d 530 char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned)];
2b3ab29d 531 int r;
2b3ab29d
ZJS
532
533 assert(m);
534 assert(vtnr >= 1);
535
92bd5ff3
DH
536 if (vtnr > m->n_autovts &&
537 vtnr != m->reserve_vt)
2b3ab29d
ZJS
538 return 0;
539
92bd5ff3 540 if (vtnr != m->reserve_vt) {
2b3ab29d
ZJS
541 /* If this is the reserved TTY, we'll start the getty
542 * on it in any case, but otherwise only if it is not
543 * busy. */
544
545 r = vt_is_busy(vtnr);
546 if (r < 0)
547 return r;
548 else if (r > 0)
549 return -EBUSY;
550 }
551
d7a0f1f4 552 xsprintf(name, "autovt@tty%u.service", vtnr);
59228d0d 553 r = bus_call_method(m->bus, bus_systemd_mgr, "StartUnit", &error, NULL, "ss", name, "fail");
cc377381 554 if (r < 0)
4ae25393 555 return log_error_errno(r, "Failed to start %s: %s", name, bus_error_message(&error, r));
2b3ab29d 556
4ae25393 557 return 0;
2b3ab29d 558}
2d62c530 559
9b9c23da 560bool manager_is_lid_closed(Manager *m) {
9b9c23da
LP
561 Button *b;
562
90e74a66 563 HASHMAP_FOREACH(b, m->buttons)
9b9c23da
LP
564 if (b->lid_closed)
565 return true;
566
567 return false;
568}
569
602a41c2 570static bool manager_is_docked(Manager *m) {
2d62c530
LP
571 Button *b;
572
90e74a66 573 HASHMAP_FOREACH(b, m->buttons)
2d62c530
LP
574 if (b->docked)
575 return true;
576
577 return false;
578}
6a79c586 579
602a41c2 580static int manager_count_external_displays(Manager *m) {
4f209af7 581 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
4f209af7 582 int r, n = 0;
6a79c586 583
4f209af7
YW
584 r = sd_device_enumerator_new(&e);
585 if (r < 0)
586 return r;
6a79c586 587
4f209af7 588 r = sd_device_enumerator_allow_uninitialized(e);
6a79c586
LP
589 if (r < 0)
590 return r;
591
4f209af7 592 r = sd_device_enumerator_add_match_subsystem(e, "drm", true);
6a79c586
LP
593 if (r < 0)
594 return r;
595
8437c059 596 FOREACH_DEVICE(e, d) {
fb53ee0a 597 const char *status, *enabled, *dash, *nn;
4f209af7 598 sd_device *p;
6a79c586 599
4f209af7 600 if (sd_device_get_parent(d, &p) < 0)
94036de8 601 continue;
6a79c586
LP
602
603 /* If the parent shares the same subsystem as the
604 * device we are looking at then it is a connector,
605 * which is what we are interested in. */
fb53ee0a 606 if (!device_in_subsystem(p, "drm"))
6a79c586
LP
607 continue;
608
4f209af7 609 if (sd_device_get_sysname(d, &nn) < 0)
602a41c2
LP
610 continue;
611
6b000af4
LP
612 /* Ignore internal displays: the type is encoded in the sysfs name, as the second dash
613 * separated item (the first is the card name, the last the connector number). We implement a
614 * deny list of external displays here, rather than an allow list of internal ones, to ensure
615 * we don't block suspends too eagerly. */
602a41c2
LP
616 dash = strchr(nn, '-');
617 if (!dash)
618 continue;
619
620 dash++;
49fe5c09
LP
621 if (!STARTSWITH_SET(dash,
622 "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
623 "Composite-", "SVIDEO-", "Component-",
624 "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-"))
602a41c2
LP
625 continue;
626
627 /* Ignore ports that are not enabled */
4f209af7 628 if (sd_device_get_sysattr_value(d, "enabled", &enabled) < 0 || !streq(enabled, "enabled"))
602a41c2
LP
629 continue;
630
6a79c586
LP
631 /* We count any connector which is not explicitly
632 * "disconnected" as connected. */
4f209af7 633 if (sd_device_get_sysattr_value(d, "status", &status) < 0 || !streq(status, "disconnected"))
6a79c586
LP
634 n++;
635 }
636
637 return n;
638}
3c56cab4 639
602a41c2 640bool manager_is_docked_or_external_displays(Manager *m) {
3c56cab4
BW
641 int n;
642
643 /* If we are docked don't react to lid closing */
644 if (manager_is_docked(m)) {
645 log_debug("System is docked.");
646 return true;
647 }
648
649 /* If we have more than one display connected,
650 * assume that we are docked. */
602a41c2 651 n = manager_count_external_displays(m);
3c56cab4 652 if (n < 0)
da927ba9 653 log_warning_errno(n, "Display counting failed: %m");
602a41c2
LP
654 else if (n >= 1) {
655 log_debug("External (%i) displays connected.", n);
3c56cab4
BW
656 return true;
657 }
658
659 return false;
660}
e25937a3
SF
661
662bool manager_is_on_external_power(void) {
663 int r;
664
e455380b
LP
665 /* For now we only check for AC power, but 'external power' can apply to anything that isn't an internal
666 * battery */
e25937a3
SF
667 r = on_ac_power();
668 if (r < 0)
669 log_warning_errno(r, "Failed to read AC power status: %m");
e25937a3 670
e455380b 671 return r != 0; /* Treat failure as 'on AC' */
e25937a3
SF
672}
673
674bool manager_all_buttons_ignored(Manager *m) {
864fe630
LP
675 assert(m);
676
e25937a3
SF
677 if (m->handle_power_key != HANDLE_IGNORE)
678 return false;
a520bb66
YA
679 if (m->handle_power_key_long_press != HANDLE_IGNORE)
680 return false;
e25937a3
SF
681 if (m->handle_suspend_key != HANDLE_IGNORE)
682 return false;
a520bb66
YA
683 if (m->handle_suspend_key_long_press != HANDLE_IGNORE)
684 return false;
e25937a3
SF
685 if (m->handle_hibernate_key != HANDLE_IGNORE)
686 return false;
a520bb66
YA
687 if (m->handle_hibernate_key_long_press != HANDLE_IGNORE)
688 return false;
689 if (m->handle_reboot_key != HANDLE_IGNORE)
690 return false;
691 if (m->handle_reboot_key_long_press != HANDLE_IGNORE)
692 return false;
e25937a3
SF
693 if (m->handle_lid_switch != HANDLE_IGNORE)
694 return false;
ed0cb346 695 if (!IN_SET(m->handle_lid_switch_ep, _HANDLE_ACTION_INVALID, HANDLE_IGNORE))
e25937a3
SF
696 return false;
697 if (m->handle_lid_switch_docked != HANDLE_IGNORE)
698 return false;
864fe630 699
e25937a3
SF
700 return true;
701}
3d0ef5c7
LP
702
703int manager_read_utmp(Manager *m) {
704#if ENABLE_UTMP
705 int r;
d7ac0952 706 _unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
3d0ef5c7
LP
707
708 assert(m);
709
710 if (utmpxname(_PATH_UTMPX) < 0)
711 return log_error_errno(errno, "Failed to set utmp path to " _PATH_UTMPX ": %m");
712
c2a99093 713 utmpx = utxent_start();
3d0ef5c7
LP
714
715 for (;;) {
716 _cleanup_free_ char *t = NULL;
717 struct utmpx *u;
718 const char *c;
719 Session *s;
720
721 errno = 0;
722 u = getutxent();
723 if (!u) {
9830d716
LP
724 if (errno == ENOENT)
725 log_debug_errno(errno, _PATH_UTMPX " does not exist, ignoring.");
726 else if (errno != 0)
3d0ef5c7 727 log_warning_errno(errno, "Failed to read " _PATH_UTMPX ", ignoring: %m");
c2a99093 728 return 0;
3d0ef5c7
LP
729 }
730
731 if (u->ut_type != USER_PROCESS)
732 continue;
733
734 if (!pid_is_valid(u->ut_pid))
735 continue;
736
737 t = strndup(u->ut_line, sizeof(u->ut_line));
c2a99093
ZJS
738 if (!t)
739 return log_oom();
3d0ef5c7
LP
740
741 c = path_startswith(t, "/dev/");
742 if (c) {
743 r = free_and_strdup(&t, c);
c2a99093
ZJS
744 if (r < 0)
745 return log_oom();
3d0ef5c7
LP
746 }
747
748 if (isempty(t))
749 continue;
750
8494f562 751 if (manager_get_session_by_pidref(m, &PIDREF_MAKE_FROM_PID(u->ut_pid), &s) <= 0)
3d0ef5c7
LP
752 continue;
753
754 if (s->tty_validity == TTY_FROM_UTMP && !streq_ptr(s->tty, t)) {
755 /* This may happen on multiplexed SSH connection (i.e. 'SSH connection sharing'). In
756 * this case PAM and utmp sessions don't match. In such a case let's invalidate the TTY
757 * information and never acquire it again. */
758
759 s->tty = mfree(s->tty);
760 s->tty_validity = TTY_UTMP_INCONSISTENT;
761 log_debug("Session '%s' has inconsistent TTY information, dropping TTY information.", s->id);
762 continue;
763 }
764
765 /* Never override what we figured out once */
766 if (s->tty || s->tty_validity >= 0)
767 continue;
768
769 s->tty = TAKE_PTR(t);
770 s->tty_validity = TTY_FROM_UTMP;
771 log_debug("Acquired TTY information '%s' from utmp for session '%s'.", s->tty, s->id);
772 }
773
3d0ef5c7 774#else
86cf4554 775 return 0;
3d0ef5c7
LP
776#endif
777}
778
779#if ENABLE_UTMP
780static int manager_dispatch_utmp(sd_event_source *s, const struct inotify_event *event, void *userdata) {
99534007 781 Manager *m = ASSERT_PTR(userdata);
3d0ef5c7
LP
782
783 /* If there's indication the file itself might have been removed or became otherwise unavailable, then let's
784 * reestablish the watch on whatever there's now. */
785 if ((event->mask & (IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF|IN_Q_OVERFLOW|IN_UNMOUNT)) != 0)
786 manager_connect_utmp(m);
787
788 (void) manager_read_utmp(m);
789 return 0;
790}
791#endif
792
793void manager_connect_utmp(Manager *m) {
794#if ENABLE_UTMP
795 sd_event_source *s = NULL;
796 int r;
797
798 assert(m);
799
800 /* Watch utmp for changes via inotify. We do this to deal with tools such as ssh, which will register the PAM
801 * session early, and acquire a TTY only much later for the connection. Thus during PAM the TTY won't be known
802 * yet. ssh will register itself with utmp when it finally acquired the TTY. Hence, let's make use of this, and
803 * watch utmp for the TTY asynchronously. We use the PAM session's leader PID as key, to find the right entry.
804 *
805 * Yes, relying on utmp is pretty ugly, but it's good enough for informational purposes, as well as idle
806 * detection (which, for tty sessions, relies on the TTY used) */
807
808 r = sd_event_add_inotify(m->event, &s, _PATH_UTMPX, IN_MODIFY|IN_MOVE_SELF|IN_DELETE_SELF|IN_ATTRIB, manager_dispatch_utmp, m);
809 if (r < 0)
810 log_full_errno(r == -ENOENT ? LOG_DEBUG: LOG_WARNING, r, "Failed to create inotify watch on " _PATH_UTMPX ", ignoring: %m");
811 else {
812 r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_IDLE);
813 if (r < 0)
814 log_warning_errno(r, "Failed to adjust utmp event source priority, ignoring: %m");
815
816 (void) sd_event_source_set_description(s, "utmp");
817 }
818
819 sd_event_source_unref(m->utmp_event_source);
820 m->utmp_event_source = s;
821#endif
822}
823
824void manager_reconnect_utmp(Manager *m) {
825#if ENABLE_UTMP
826 assert(m);
827
828 if (m->utmp_event_source)
829 return;
830
831 manager_connect_utmp(m);
832#endif
833}
d4bd786d
LP
834
835int manager_read_efi_boot_loader_entries(Manager *m) {
836#if ENABLE_EFI
837 int r;
838
839 assert(m);
840 if (m->efi_boot_loader_entries_set)
841 return 0;
842
843 r = efi_loader_get_entries(&m->efi_boot_loader_entries);
1209bf75
DL
844 if (r < 0) {
845 if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r)) {
846 log_debug_errno(r, "Boot loader reported no entries.");
847 m->efi_boot_loader_entries_set = true;
848 return 0;
849 }
d4bd786d 850 return log_error_errno(r, "Failed to determine entries reported by boot loader: %m");
1209bf75 851 }
d4bd786d
LP
852
853 m->efi_boot_loader_entries_set = true;
854 return 1;
855#else
856 return 0;
857#endif
858}