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