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