]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-core.c
logind: do not fail creating a session when request is not from a unit
[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 223 if (!i) {
26ed3ecf 224 r = inhibitor_new(m, id, &i);
81280b2a
LP
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);
eb56b564
LB
374 if (r >= 0)
375 s = hashmap_get(m->session_units, unit);
238794b1 376 }
14ef4a65
LP
377
378 if (ret)
379 *ret = s;
2b3ab29d 380
c9ee7160 381 return !!s;
2b3ab29d
ZJS
382}
383
14ef4a65 384int manager_get_user_by_pid(Manager *m, pid_t pid, User **ret) {
2b3ab29d 385 _cleanup_free_ char *unit = NULL;
c9ee7160 386 User *u = NULL;
2b3ab29d
ZJS
387 int r;
388
389 assert(m);
2b3ab29d 390
6f876815 391 if (!pid_is_valid(pid))
2b3ab29d
ZJS
392 return -EINVAL;
393
394 r = cg_pid_get_slice(pid, &unit);
c9ee7160
ZJS
395 if (r >= 0)
396 u = hashmap_get(m->user_units, unit);
14ef4a65
LP
397
398 if (ret)
399 *ret = u;
2b3ab29d 400
c9ee7160 401 return !!u;
2b3ab29d
ZJS
402}
403
404int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
405 Session *s;
406 bool idle_hint;
5cb14b37 407 dual_timestamp ts = DUAL_TIMESTAMP_NULL;
2b3ab29d
ZJS
408
409 assert(m);
410
85a428c6 411 idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
2b3ab29d 412
90e74a66 413 HASHMAP_FOREACH(s, m->sessions) {
2b3ab29d
ZJS
414 dual_timestamp k;
415 int ih;
416
b4f01bc1
LP
417 if (!SESSION_CLASS_CAN_IDLE(s->class))
418 continue;
419
2b3ab29d
ZJS
420 ih = session_get_idle_hint(s, &k);
421 if (ih < 0)
422 return ih;
423
424 if (!ih) {
425 if (!idle_hint) {
426 if (k.monotonic < ts.monotonic)
427 ts = k;
428 } else {
429 idle_hint = false;
430 ts = k;
431 }
432 } else if (idle_hint) {
433
434 if (k.monotonic > ts.monotonic)
435 ts = k;
436 }
437 }
438
439 if (t)
440 *t = ts;
441
442 return idle_hint;
443}
444
445bool manager_shall_kill(Manager *m, const char *user) {
446 assert(m);
447 assert(user);
448
a2ed7077
ZJS
449 if (!m->kill_exclude_users && streq(user, "root"))
450 return false;
451
2b3ab29d
ZJS
452 if (strv_contains(m->kill_exclude_users, user))
453 return false;
454
921f831d
ZJS
455 if (!strv_isempty(m->kill_only_users))
456 return strv_contains(m->kill_only_users, user);
2b3ab29d 457
921f831d 458 return m->kill_user_processes;
2b3ab29d
ZJS
459}
460
c29b65f7
AJ
461int config_parse_n_autovts(
462 const char *unit,
463 const char *filename,
464 unsigned line,
465 const char *section,
466 unsigned section_line,
467 const char *lvalue,
468 int ltype,
469 const char *rvalue,
470 void *data,
471 void *userdata) {
472
99534007 473 unsigned *n = ASSERT_PTR(data);
c29b65f7
AJ
474 unsigned o;
475 int r;
476
477 assert(filename);
478 assert(lvalue);
479 assert(rvalue);
c29b65f7
AJ
480
481 r = safe_atou(rvalue, &o);
482 if (r < 0) {
196d41bc
YW
483 log_syntax(unit, LOG_WARNING, filename, line, r,
484 "Failed to parse number of autovts, ignoring: %s", rvalue);
c29b65f7
AJ
485 return 0;
486 }
487
488 if (o > 15) {
196d41bc
YW
489 log_syntax(unit, LOG_WARNING, filename, line, 0,
490 "A maximum of 15 autovts are supported, ignoring: %s", rvalue);
c29b65f7
AJ
491 return 0;
492 }
493
494 *n = o;
495 return 0;
496}
497
14cb109d 498static int vt_is_busy(unsigned vtnr) {
2b3ab29d 499 struct vt_stat vt_stat;
6d95e7d9 500 int r;
254d1313 501 _cleanup_close_ int fd = -EBADF;
2b3ab29d
ZJS
502
503 assert(vtnr >= 1);
504
c29b65f7
AJ
505 /* VT_GETSTATE "cannot return state for more than 16 VTs, since v_state is short" */
506 assert(vtnr <= 15);
507
2b3ab29d
ZJS
508 /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
509 * we'd open the latter we'd open the foreground tty which
510 * hence would be unconditionally busy. By opening /dev/tty1
511 * we avoid this. Since tty1 is special and needs to be an
512 * explicitly loaded getty or DM this is safe. */
513
514 fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
515 if (fd < 0)
516 return -errno;
517
518 if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
519 r = -errno;
520 else
521 r = !!(vt_stat.v_state & (1 << vtnr));
522
2b3ab29d
ZJS
523 return r;
524}
525
14cb109d 526int manager_spawn_autovt(Manager *m, unsigned vtnr) {
4afd3348 527 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
14cb109d 528 char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned)];
2b3ab29d 529 int r;
2b3ab29d
ZJS
530
531 assert(m);
532 assert(vtnr >= 1);
533
92bd5ff3
DH
534 if (vtnr > m->n_autovts &&
535 vtnr != m->reserve_vt)
2b3ab29d
ZJS
536 return 0;
537
92bd5ff3 538 if (vtnr != m->reserve_vt) {
2b3ab29d
ZJS
539 /* If this is the reserved TTY, we'll start the getty
540 * on it in any case, but otherwise only if it is not
541 * busy. */
542
543 r = vt_is_busy(vtnr);
544 if (r < 0)
545 return r;
546 else if (r > 0)
547 return -EBUSY;
548 }
549
d7a0f1f4 550 xsprintf(name, "autovt@tty%u.service", vtnr);
59228d0d 551 r = bus_call_method(m->bus, bus_systemd_mgr, "StartUnit", &error, NULL, "ss", name, "fail");
cc377381 552 if (r < 0)
4ae25393 553 return log_error_errno(r, "Failed to start %s: %s", name, bus_error_message(&error, r));
2b3ab29d 554
4ae25393 555 return 0;
2b3ab29d 556}
2d62c530 557
9b9c23da 558bool manager_is_lid_closed(Manager *m) {
9b9c23da
LP
559 Button *b;
560
90e74a66 561 HASHMAP_FOREACH(b, m->buttons)
9b9c23da
LP
562 if (b->lid_closed)
563 return true;
564
565 return false;
566}
567
602a41c2 568static bool manager_is_docked(Manager *m) {
2d62c530
LP
569 Button *b;
570
90e74a66 571 HASHMAP_FOREACH(b, m->buttons)
2d62c530
LP
572 if (b->docked)
573 return true;
574
575 return false;
576}
6a79c586 577
602a41c2 578static int manager_count_external_displays(Manager *m) {
4f209af7 579 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
4f209af7 580 int r, n = 0;
6a79c586 581
4f209af7
YW
582 r = sd_device_enumerator_new(&e);
583 if (r < 0)
584 return r;
6a79c586 585
4f209af7 586 r = sd_device_enumerator_allow_uninitialized(e);
6a79c586
LP
587 if (r < 0)
588 return r;
589
4f209af7 590 r = sd_device_enumerator_add_match_subsystem(e, "drm", true);
6a79c586
LP
591 if (r < 0)
592 return r;
593
8437c059 594 FOREACH_DEVICE(e, d) {
fb53ee0a 595 const char *status, *enabled, *dash, *nn;
4f209af7 596 sd_device *p;
6a79c586 597
4f209af7 598 if (sd_device_get_parent(d, &p) < 0)
94036de8 599 continue;
6a79c586
LP
600
601 /* If the parent shares the same subsystem as the
602 * device we are looking at then it is a connector,
603 * which is what we are interested in. */
fb53ee0a 604 if (!device_in_subsystem(p, "drm"))
6a79c586
LP
605 continue;
606
4f209af7 607 if (sd_device_get_sysname(d, &nn) < 0)
602a41c2
LP
608 continue;
609
6b000af4
LP
610 /* Ignore internal displays: the type is encoded in the sysfs name, as the second dash
611 * separated item (the first is the card name, the last the connector number). We implement a
612 * deny list of external displays here, rather than an allow list of internal ones, to ensure
613 * we don't block suspends too eagerly. */
602a41c2
LP
614 dash = strchr(nn, '-');
615 if (!dash)
616 continue;
617
618 dash++;
49fe5c09
LP
619 if (!STARTSWITH_SET(dash,
620 "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
621 "Composite-", "SVIDEO-", "Component-",
622 "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-"))
602a41c2
LP
623 continue;
624
625 /* Ignore ports that are not enabled */
4f209af7 626 if (sd_device_get_sysattr_value(d, "enabled", &enabled) < 0 || !streq(enabled, "enabled"))
602a41c2
LP
627 continue;
628
6a79c586
LP
629 /* We count any connector which is not explicitly
630 * "disconnected" as connected. */
4f209af7 631 if (sd_device_get_sysattr_value(d, "status", &status) < 0 || !streq(status, "disconnected"))
6a79c586
LP
632 n++;
633 }
634
635 return n;
636}
3c56cab4 637
602a41c2 638bool manager_is_docked_or_external_displays(Manager *m) {
3c56cab4
BW
639 int n;
640
641 /* If we are docked don't react to lid closing */
642 if (manager_is_docked(m)) {
643 log_debug("System is docked.");
644 return true;
645 }
646
647 /* If we have more than one display connected,
648 * assume that we are docked. */
602a41c2 649 n = manager_count_external_displays(m);
3c56cab4 650 if (n < 0)
da927ba9 651 log_warning_errno(n, "Display counting failed: %m");
602a41c2
LP
652 else if (n >= 1) {
653 log_debug("External (%i) displays connected.", n);
3c56cab4
BW
654 return true;
655 }
656
657 return false;
658}
e25937a3
SF
659
660bool manager_is_on_external_power(void) {
661 int r;
662
e455380b
LP
663 /* For now we only check for AC power, but 'external power' can apply to anything that isn't an internal
664 * battery */
e25937a3
SF
665 r = on_ac_power();
666 if (r < 0)
667 log_warning_errno(r, "Failed to read AC power status: %m");
e25937a3 668
e455380b 669 return r != 0; /* Treat failure as 'on AC' */
e25937a3
SF
670}
671
672bool manager_all_buttons_ignored(Manager *m) {
864fe630
LP
673 assert(m);
674
e25937a3
SF
675 if (m->handle_power_key != HANDLE_IGNORE)
676 return false;
a520bb66
YA
677 if (m->handle_power_key_long_press != HANDLE_IGNORE)
678 return false;
e25937a3
SF
679 if (m->handle_suspend_key != HANDLE_IGNORE)
680 return false;
a520bb66
YA
681 if (m->handle_suspend_key_long_press != HANDLE_IGNORE)
682 return false;
e25937a3
SF
683 if (m->handle_hibernate_key != HANDLE_IGNORE)
684 return false;
a520bb66
YA
685 if (m->handle_hibernate_key_long_press != HANDLE_IGNORE)
686 return false;
687 if (m->handle_reboot_key != HANDLE_IGNORE)
688 return false;
689 if (m->handle_reboot_key_long_press != HANDLE_IGNORE)
690 return false;
e25937a3
SF
691 if (m->handle_lid_switch != HANDLE_IGNORE)
692 return false;
ed0cb346 693 if (!IN_SET(m->handle_lid_switch_ep, _HANDLE_ACTION_INVALID, HANDLE_IGNORE))
e25937a3
SF
694 return false;
695 if (m->handle_lid_switch_docked != HANDLE_IGNORE)
696 return false;
864fe630 697
e25937a3
SF
698 return true;
699}
3d0ef5c7
LP
700
701int manager_read_utmp(Manager *m) {
702#if ENABLE_UTMP
703 int r;
d7ac0952 704 _unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
3d0ef5c7
LP
705
706 assert(m);
707
708 if (utmpxname(_PATH_UTMPX) < 0)
709 return log_error_errno(errno, "Failed to set utmp path to " _PATH_UTMPX ": %m");
710
c2a99093 711 utmpx = utxent_start();
3d0ef5c7
LP
712
713 for (;;) {
714 _cleanup_free_ char *t = NULL;
715 struct utmpx *u;
716 const char *c;
717 Session *s;
718
719 errno = 0;
720 u = getutxent();
721 if (!u) {
9830d716
LP
722 if (errno == ENOENT)
723 log_debug_errno(errno, _PATH_UTMPX " does not exist, ignoring.");
724 else if (errno != 0)
3d0ef5c7 725 log_warning_errno(errno, "Failed to read " _PATH_UTMPX ", ignoring: %m");
c2a99093 726 return 0;
3d0ef5c7
LP
727 }
728
729 if (u->ut_type != USER_PROCESS)
730 continue;
731
732 if (!pid_is_valid(u->ut_pid))
733 continue;
734
735 t = strndup(u->ut_line, sizeof(u->ut_line));
c2a99093
ZJS
736 if (!t)
737 return log_oom();
3d0ef5c7
LP
738
739 c = path_startswith(t, "/dev/");
740 if (c) {
741 r = free_and_strdup(&t, c);
c2a99093
ZJS
742 if (r < 0)
743 return log_oom();
3d0ef5c7
LP
744 }
745
746 if (isempty(t))
747 continue;
748
8494f562 749 if (manager_get_session_by_pidref(m, &PIDREF_MAKE_FROM_PID(u->ut_pid), &s) <= 0)
3d0ef5c7
LP
750 continue;
751
752 if (s->tty_validity == TTY_FROM_UTMP && !streq_ptr(s->tty, t)) {
753 /* This may happen on multiplexed SSH connection (i.e. 'SSH connection sharing'). In
754 * this case PAM and utmp sessions don't match. In such a case let's invalidate the TTY
755 * information and never acquire it again. */
756
757 s->tty = mfree(s->tty);
758 s->tty_validity = TTY_UTMP_INCONSISTENT;
759 log_debug("Session '%s' has inconsistent TTY information, dropping TTY information.", s->id);
760 continue;
761 }
762
763 /* Never override what we figured out once */
764 if (s->tty || s->tty_validity >= 0)
765 continue;
766
767 s->tty = TAKE_PTR(t);
768 s->tty_validity = TTY_FROM_UTMP;
769 log_debug("Acquired TTY information '%s' from utmp for session '%s'.", s->tty, s->id);
770 }
771
3d0ef5c7 772#else
86cf4554 773 return 0;
3d0ef5c7
LP
774#endif
775}
776
777#if ENABLE_UTMP
778static int manager_dispatch_utmp(sd_event_source *s, const struct inotify_event *event, void *userdata) {
99534007 779 Manager *m = ASSERT_PTR(userdata);
3d0ef5c7
LP
780
781 /* If there's indication the file itself might have been removed or became otherwise unavailable, then let's
782 * reestablish the watch on whatever there's now. */
783 if ((event->mask & (IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF|IN_Q_OVERFLOW|IN_UNMOUNT)) != 0)
784 manager_connect_utmp(m);
785
786 (void) manager_read_utmp(m);
787 return 0;
788}
789#endif
790
791void manager_connect_utmp(Manager *m) {
792#if ENABLE_UTMP
793 sd_event_source *s = NULL;
794 int r;
795
796 assert(m);
797
798 /* Watch utmp for changes via inotify. We do this to deal with tools such as ssh, which will register the PAM
799 * session early, and acquire a TTY only much later for the connection. Thus during PAM the TTY won't be known
800 * yet. ssh will register itself with utmp when it finally acquired the TTY. Hence, let's make use of this, and
801 * watch utmp for the TTY asynchronously. We use the PAM session's leader PID as key, to find the right entry.
802 *
803 * Yes, relying on utmp is pretty ugly, but it's good enough for informational purposes, as well as idle
804 * detection (which, for tty sessions, relies on the TTY used) */
805
806 r = sd_event_add_inotify(m->event, &s, _PATH_UTMPX, IN_MODIFY|IN_MOVE_SELF|IN_DELETE_SELF|IN_ATTRIB, manager_dispatch_utmp, m);
807 if (r < 0)
808 log_full_errno(r == -ENOENT ? LOG_DEBUG: LOG_WARNING, r, "Failed to create inotify watch on " _PATH_UTMPX ", ignoring: %m");
809 else {
810 r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_IDLE);
811 if (r < 0)
812 log_warning_errno(r, "Failed to adjust utmp event source priority, ignoring: %m");
813
814 (void) sd_event_source_set_description(s, "utmp");
815 }
816
817 sd_event_source_unref(m->utmp_event_source);
818 m->utmp_event_source = s;
819#endif
820}
821
822void manager_reconnect_utmp(Manager *m) {
823#if ENABLE_UTMP
824 assert(m);
825
826 if (m->utmp_event_source)
827 return;
828
829 manager_connect_utmp(m);
830#endif
831}
d4bd786d
LP
832
833int manager_read_efi_boot_loader_entries(Manager *m) {
834#if ENABLE_EFI
835 int r;
836
837 assert(m);
838 if (m->efi_boot_loader_entries_set)
839 return 0;
840
841 r = efi_loader_get_entries(&m->efi_boot_loader_entries);
1209bf75
DL
842 if (r < 0) {
843 if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r)) {
844 log_debug_errno(r, "Boot loader reported no entries.");
845 m->efi_boot_loader_entries_set = true;
846 return 0;
847 }
d4bd786d 848 return log_error_errno(r, "Failed to determine entries reported by boot loader: %m");
1209bf75 849 }
d4bd786d
LP
850
851 m->efi_boot_loader_entries_set = true;
852 return 1;
853#else
854 return 0;
855#endif
856}