]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-core.c
Merge pull request #8575 from keszybz/non-absolute-paths
[thirdparty/systemd.git] / src / login / logind-core.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6 ***/
7
8 #include <fcntl.h>
9 #include <pwd.h>
10 #include <sys/ioctl.h>
11 #include <sys/types.h>
12 #include <linux/vt.h>
13
14 #include "alloc-util.h"
15 #include "bus-error.h"
16 #include "bus-util.h"
17 #include "cgroup-util.h"
18 #include "fd-util.h"
19 #include "logind.h"
20 #include "parse-util.h"
21 #include "process-util.h"
22 #include "strv.h"
23 #include "terminal-util.h"
24 #include "udev-util.h"
25 #include "user-util.h"
26
27 int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
28 Device *d;
29
30 assert(m);
31 assert(sysfs);
32
33 d = hashmap_get(m->devices, sysfs);
34 if (d)
35 /* we support adding master-flags, but not removing them */
36 d->master = d->master || master;
37 else {
38 d = device_new(m, sysfs, master);
39 if (!d)
40 return -ENOMEM;
41 }
42
43 if (_device)
44 *_device = d;
45
46 return 0;
47 }
48
49 int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
50 Seat *s;
51
52 assert(m);
53 assert(id);
54
55 s = hashmap_get(m->seats, id);
56 if (!s) {
57 s = seat_new(m, id);
58 if (!s)
59 return -ENOMEM;
60 }
61
62 if (_seat)
63 *_seat = s;
64
65 return 0;
66 }
67
68 int manager_add_session(Manager *m, const char *id, Session **_session) {
69 Session *s;
70
71 assert(m);
72 assert(id);
73
74 s = hashmap_get(m->sessions, id);
75 if (!s) {
76 s = session_new(m, id);
77 if (!s)
78 return -ENOMEM;
79 }
80
81 if (_session)
82 *_session = s;
83
84 return 0;
85 }
86
87 int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
88 User *u;
89 int r;
90
91 assert(m);
92 assert(name);
93
94 u = hashmap_get(m->users, UID_TO_PTR(uid));
95 if (!u) {
96 r = user_new(&u, m, uid, gid, name);
97 if (r < 0)
98 return r;
99 }
100
101 if (_user)
102 *_user = u;
103
104 return 0;
105 }
106
107 int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
108 uid_t uid;
109 gid_t gid;
110 int r;
111
112 assert(m);
113 assert(name);
114
115 r = get_user_creds(&name, &uid, &gid, NULL, NULL);
116 if (r < 0)
117 return r;
118
119 return manager_add_user(m, uid, gid, name, _user);
120 }
121
122 int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
123 struct passwd *p;
124
125 assert(m);
126
127 errno = 0;
128 p = getpwuid(uid);
129 if (!p)
130 return errno > 0 ? -errno : -ENOENT;
131
132 return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
133 }
134
135 int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) {
136 Inhibitor *i;
137
138 assert(m);
139 assert(id);
140
141 i = hashmap_get(m->inhibitors, id);
142 if (i) {
143 if (_inhibitor)
144 *_inhibitor = i;
145
146 return 0;
147 }
148
149 i = inhibitor_new(m, id);
150 if (!i)
151 return -ENOMEM;
152
153 if (_inhibitor)
154 *_inhibitor = i;
155
156 return 0;
157 }
158
159 int manager_add_button(Manager *m, const char *name, Button **_button) {
160 Button *b;
161
162 assert(m);
163 assert(name);
164
165 b = hashmap_get(m->buttons, name);
166 if (!b) {
167 b = button_new(m, name);
168 if (!b)
169 return -ENOMEM;
170 }
171
172 if (_button)
173 *_button = b;
174
175 return 0;
176 }
177
178 int manager_process_seat_device(Manager *m, struct udev_device *d) {
179 Device *device;
180 int r;
181
182 assert(m);
183
184 if (streq_ptr(udev_device_get_action(d), "remove")) {
185
186 device = hashmap_get(m->devices, udev_device_get_syspath(d));
187 if (!device)
188 return 0;
189
190 seat_add_to_gc_queue(device->seat);
191 device_free(device);
192
193 } else {
194 const char *sn;
195 Seat *seat = NULL;
196 bool master;
197
198 sn = udev_device_get_property_value(d, "ID_SEAT");
199 if (isempty(sn))
200 sn = "seat0";
201
202 if (!seat_name_is_valid(sn)) {
203 log_warning("Device with invalid seat name %s found, ignoring.", sn);
204 return 0;
205 }
206
207 seat = hashmap_get(m->seats, sn);
208 master = udev_device_has_tag(d, "master-of-seat");
209
210 /* Ignore non-master devices for unknown seats */
211 if (!master && !seat)
212 return 0;
213
214 r = manager_add_device(m, udev_device_get_syspath(d), master, &device);
215 if (r < 0)
216 return r;
217
218 if (!seat) {
219 r = manager_add_seat(m, sn, &seat);
220 if (r < 0) {
221 if (!device->seat)
222 device_free(device);
223
224 return r;
225 }
226 }
227
228 device_attach(device, seat);
229 seat_start(seat);
230 }
231
232 return 0;
233 }
234
235 int manager_process_button_device(Manager *m, struct udev_device *d) {
236 Button *b;
237
238 int r;
239
240 assert(m);
241
242 if (streq_ptr(udev_device_get_action(d), "remove")) {
243
244 b = hashmap_get(m->buttons, udev_device_get_sysname(d));
245 if (!b)
246 return 0;
247
248 button_free(b);
249
250 } else {
251 const char *sn;
252
253 r = manager_add_button(m, udev_device_get_sysname(d), &b);
254 if (r < 0)
255 return r;
256
257 sn = udev_device_get_property_value(d, "ID_SEAT");
258 if (isempty(sn))
259 sn = "seat0";
260
261 button_set_seat(b, sn);
262
263 r = button_open(b);
264 if (r < 0) /* event device doesn't have any keys or switches relevant to us? (or any other error
265 * opening the device?) let's close the button again. */
266 button_free(b);
267 }
268
269 return 0;
270 }
271
272 int manager_get_session_by_pid(Manager *m, pid_t pid, Session **ret) {
273 _cleanup_free_ char *unit = NULL;
274 Session *s;
275 int r;
276
277 assert(m);
278
279 if (!pid_is_valid(pid))
280 return -EINVAL;
281
282 r = cg_pid_get_unit(pid, &unit);
283 if (r < 0)
284 goto not_found;
285
286 s = hashmap_get(m->session_units, unit);
287 if (!s)
288 goto not_found;
289
290 if (ret)
291 *ret = s;
292
293 return 1;
294
295 not_found:
296 if (ret)
297 *ret = NULL;
298 return 0;
299 }
300
301 int manager_get_user_by_pid(Manager *m, pid_t pid, User **ret) {
302 _cleanup_free_ char *unit = NULL;
303 User *u;
304 int r;
305
306 assert(m);
307
308 if (!pid_is_valid(pid))
309 return -EINVAL;
310
311 r = cg_pid_get_slice(pid, &unit);
312 if (r < 0)
313 goto not_found;
314
315 u = hashmap_get(m->user_units, unit);
316 if (!u)
317 goto not_found;
318
319 if (ret)
320 *ret = u;
321
322 return 1;
323
324 not_found:
325 if (ret)
326 *ret = NULL;
327
328 return 0;
329 }
330
331 int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
332 Session *s;
333 bool idle_hint;
334 dual_timestamp ts = DUAL_TIMESTAMP_NULL;
335 Iterator i;
336
337 assert(m);
338
339 idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
340
341 HASHMAP_FOREACH(s, m->sessions, i) {
342 dual_timestamp k;
343 int ih;
344
345 ih = session_get_idle_hint(s, &k);
346 if (ih < 0)
347 return ih;
348
349 if (!ih) {
350 if (!idle_hint) {
351 if (k.monotonic < ts.monotonic)
352 ts = k;
353 } else {
354 idle_hint = false;
355 ts = k;
356 }
357 } else if (idle_hint) {
358
359 if (k.monotonic > ts.monotonic)
360 ts = k;
361 }
362 }
363
364 if (t)
365 *t = ts;
366
367 return idle_hint;
368 }
369
370 bool manager_shall_kill(Manager *m, const char *user) {
371 assert(m);
372 assert(user);
373
374 if (!m->kill_exclude_users && streq(user, "root"))
375 return false;
376
377 if (strv_contains(m->kill_exclude_users, user))
378 return false;
379
380 if (!strv_isempty(m->kill_only_users))
381 return strv_contains(m->kill_only_users, user);
382
383 return m->kill_user_processes;
384 }
385
386 int config_parse_n_autovts(
387 const char *unit,
388 const char *filename,
389 unsigned line,
390 const char *section,
391 unsigned section_line,
392 const char *lvalue,
393 int ltype,
394 const char *rvalue,
395 void *data,
396 void *userdata) {
397
398 unsigned *n = data;
399 unsigned o;
400 int r;
401
402 assert(filename);
403 assert(lvalue);
404 assert(rvalue);
405 assert(data);
406
407 r = safe_atou(rvalue, &o);
408 if (r < 0) {
409 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse number of autovts, ignoring: %s", rvalue);
410 return 0;
411 }
412
413 if (o > 15) {
414 log_syntax(unit, LOG_ERR, filename, line, r, "A maximum of 15 autovts are supported, ignoring: %s", rvalue);
415 return 0;
416 }
417
418 *n = o;
419 return 0;
420 }
421
422 static int vt_is_busy(unsigned int vtnr) {
423 struct vt_stat vt_stat;
424 int r = 0;
425 _cleanup_close_ int fd;
426
427 assert(vtnr >= 1);
428
429 /* VT_GETSTATE "cannot return state for more than 16 VTs, since v_state is short" */
430 assert(vtnr <= 15);
431
432 /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
433 * we'd open the latter we'd open the foreground tty which
434 * hence would be unconditionally busy. By opening /dev/tty1
435 * we avoid this. Since tty1 is special and needs to be an
436 * explicitly loaded getty or DM this is safe. */
437
438 fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
439 if (fd < 0)
440 return -errno;
441
442 if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
443 r = -errno;
444 else
445 r = !!(vt_stat.v_state & (1 << vtnr));
446
447 return r;
448 }
449
450 int manager_spawn_autovt(Manager *m, unsigned int vtnr) {
451 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
452 char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned int)];
453 int r;
454
455 assert(m);
456 assert(vtnr >= 1);
457
458 if (vtnr > m->n_autovts &&
459 vtnr != m->reserve_vt)
460 return 0;
461
462 if (vtnr != m->reserve_vt) {
463 /* If this is the reserved TTY, we'll start the getty
464 * on it in any case, but otherwise only if it is not
465 * busy. */
466
467 r = vt_is_busy(vtnr);
468 if (r < 0)
469 return r;
470 else if (r > 0)
471 return -EBUSY;
472 }
473
474 snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
475 r = sd_bus_call_method(
476 m->bus,
477 "org.freedesktop.systemd1",
478 "/org/freedesktop/systemd1",
479 "org.freedesktop.systemd1.Manager",
480 "StartUnit",
481 &error,
482 NULL,
483 "ss", name, "fail");
484 if (r < 0)
485 log_error("Failed to start %s: %s", name, bus_error_message(&error, r));
486
487 return r;
488 }
489
490 static bool manager_is_docked(Manager *m) {
491 Iterator i;
492 Button *b;
493
494 HASHMAP_FOREACH(b, m->buttons, i)
495 if (b->docked)
496 return true;
497
498 return false;
499 }
500
501 static int manager_count_external_displays(Manager *m) {
502 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
503 struct udev_list_entry *item = NULL, *first = NULL;
504 int r;
505 int n = 0;
506
507 e = udev_enumerate_new(m->udev);
508 if (!e)
509 return -ENOMEM;
510
511 r = udev_enumerate_add_match_subsystem(e, "drm");
512 if (r < 0)
513 return r;
514
515 r = udev_enumerate_scan_devices(e);
516 if (r < 0)
517 return r;
518
519 first = udev_enumerate_get_list_entry(e);
520 udev_list_entry_foreach(item, first) {
521 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
522 struct udev_device *p;
523 const char *status, *enabled, *dash, *nn, *i;
524 bool external = false;
525
526 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
527 if (!d)
528 return -ENOMEM;
529
530 p = udev_device_get_parent(d);
531 if (!p)
532 continue;
533
534 /* If the parent shares the same subsystem as the
535 * device we are looking at then it is a connector,
536 * which is what we are interested in. */
537 if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
538 continue;
539
540 nn = udev_device_get_sysname(d);
541 if (!nn)
542 continue;
543
544 /* Ignore internal displays: the type is encoded in
545 * the sysfs name, as the second dash separated item
546 * (the first is the card name, the last the connector
547 * number). We implement a whitelist of external
548 * displays here, rather than a whitelist, to ensure
549 * we don't block suspends too eagerly. */
550 dash = strchr(nn, '-');
551 if (!dash)
552 continue;
553
554 dash++;
555 FOREACH_STRING(i, "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
556 "Composite-", "SVIDEO-", "Component-",
557 "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
558
559 if (startswith(dash, i)) {
560 external = true;
561 break;
562 }
563 }
564 if (!external)
565 continue;
566
567 /* Ignore ports that are not enabled */
568 enabled = udev_device_get_sysattr_value(d, "enabled");
569 if (!enabled)
570 continue;
571 if (!streq_ptr(enabled, "enabled"))
572 continue;
573
574 /* We count any connector which is not explicitly
575 * "disconnected" as connected. */
576 status = udev_device_get_sysattr_value(d, "status");
577 if (!streq_ptr(status, "disconnected"))
578 n++;
579 }
580
581 return n;
582 }
583
584 bool manager_is_docked_or_external_displays(Manager *m) {
585 int n;
586
587 /* If we are docked don't react to lid closing */
588 if (manager_is_docked(m)) {
589 log_debug("System is docked.");
590 return true;
591 }
592
593 /* If we have more than one display connected,
594 * assume that we are docked. */
595 n = manager_count_external_displays(m);
596 if (n < 0)
597 log_warning_errno(n, "Display counting failed: %m");
598 else if (n >= 1) {
599 log_debug("External (%i) displays connected.", n);
600 return true;
601 }
602
603 return false;
604 }
605
606 bool manager_is_on_external_power(void) {
607 int r;
608
609 /* For now we only check for AC power, but 'external power' can apply
610 * to anything that isn't an internal battery */
611 r = on_ac_power();
612 if (r < 0)
613 log_warning_errno(r, "Failed to read AC power status: %m");
614 else if (r > 0)
615 return true;
616
617 return false;
618 }
619
620 bool manager_all_buttons_ignored(Manager *m) {
621 assert(m);
622
623 if (m->handle_power_key != HANDLE_IGNORE)
624 return false;
625 if (m->handle_suspend_key != HANDLE_IGNORE)
626 return false;
627 if (m->handle_hibernate_key != HANDLE_IGNORE)
628 return false;
629 if (m->handle_lid_switch != HANDLE_IGNORE)
630 return false;
631 if (m->handle_lid_switch_ep != _HANDLE_ACTION_INVALID &&
632 m->handle_lid_switch_ep != HANDLE_IGNORE)
633 return false;
634 if (m->handle_lid_switch_docked != HANDLE_IGNORE)
635 return false;
636
637 return true;
638 }