chiark / gitweb /
tree-wide: drop license boilerplate
[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 "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 #if 0 /// elogind does not support systemd units, but its own session system
274         _cleanup_free_ char *unit = NULL;
275 #else
276         _cleanup_free_ char *session_name = NULL;
277 #endif // 0
278         Session *s;
279         int r;
280
281         assert(m);
282
283         if (!pid_is_valid(pid))
284                 return -EINVAL;
285
286 #if 0 /// elogind does not support systemd units, but its own session system
287         r = cg_pid_get_unit(pid, &unit);
288         if (r < 0)
289                 goto not_found;
290
291         s = hashmap_get(m->session_units, unit);
292         if (!s)
293                 goto not_found;
294
295         if (ret)
296                 *ret = s;
297 #else
298         log_debug_elogind("Searching session for PID %u", pid);
299         r = cg_pid_get_session(pid, &session_name);
300         if (r < 0)
301                 return 0;
302
303         s = hashmap_get(m->sessions, session_name);
304         log_debug_elogind("Session Name \"%s\" -> Session \"%s\"",
305                           session_name, s && s->id ? s->id : "NULL");
306 #endif // 0
307
308         return 1;
309
310 not_found:
311         if (ret)
312                 *ret = NULL;
313         return 0;
314 }
315
316 int manager_get_user_by_pid(Manager *m, pid_t pid, User **ret) {
317 #if 0 /// elogind does not support systemd units, but its own session system
318         _cleanup_free_ char *unit = NULL;
319         User *u;
320 #else
321         Session *s;
322 #endif // 0
323         int r;
324
325         assert(m);
326
327         if (!pid_is_valid(pid))
328                 return -EINVAL;
329
330 #if 0 /// elogind does not support systemd units, but its own session system
331         r = cg_pid_get_slice(pid, &unit);
332         if (r < 0)
333                 goto not_found;
334
335         u = hashmap_get(m->user_units, unit);
336         if (!u)
337                 goto not_found;
338
339         if (ret)
340                 *ret = u;
341
342         return 1;
343
344 not_found:
345         if (ret)
346                 *ret = NULL;
347
348         return 0;
349 #else
350         r = manager_get_session_by_pid (m, pid, &s);
351         if (r <= 0)
352                 return r;
353         if (ret)
354                 *ret = u;
355
356         *user = s->user;
357 #endif // 0
358 }
359
360 int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
361         Session *s;
362         bool idle_hint;
363         dual_timestamp ts = DUAL_TIMESTAMP_NULL;
364         Iterator i;
365
366         assert(m);
367
368         idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
369
370         HASHMAP_FOREACH(s, m->sessions, i) {
371                 dual_timestamp k;
372                 int ih;
373
374                 ih = session_get_idle_hint(s, &k);
375                 if (ih < 0)
376                         return ih;
377
378                 if (!ih) {
379                         if (!idle_hint) {
380                                 if (k.monotonic < ts.monotonic)
381                                         ts = k;
382                         } else {
383                                 idle_hint = false;
384                                 ts = k;
385                         }
386                 } else if (idle_hint) {
387
388                         if (k.monotonic > ts.monotonic)
389                                 ts = k;
390                 }
391         }
392
393         if (t)
394                 *t = ts;
395
396         return idle_hint;
397 }
398
399 bool manager_shall_kill(Manager *m, const char *user) {
400         assert(m);
401         assert(user);
402
403         if (!m->kill_exclude_users && streq(user, "root"))
404                 return false;
405
406         if (strv_contains(m->kill_exclude_users, user))
407                 return false;
408
409         if (!strv_isempty(m->kill_only_users))
410                 return strv_contains(m->kill_only_users, user);
411
412         return m->kill_user_processes;
413 }
414
415 #if 0 /// UNNEEDED by elogind
416 int config_parse_n_autovts(
417                 const char *unit,
418                 const char *filename,
419                 unsigned line,
420                 const char *section,
421                 unsigned section_line,
422                 const char *lvalue,
423                 int ltype,
424                 const char *rvalue,
425                 void *data,
426                 void *userdata) {
427
428         unsigned *n = data;
429         unsigned o;
430         int r;
431
432         assert(filename);
433         assert(lvalue);
434         assert(rvalue);
435         assert(data);
436
437         r = safe_atou(rvalue, &o);
438         if (r < 0) {
439                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse number of autovts, ignoring: %s", rvalue);
440                 return 0;
441         }
442
443         if (o > 15) {
444                 log_syntax(unit, LOG_ERR, filename, line, r, "A maximum of 15 autovts are supported, ignoring: %s", rvalue);
445                 return 0;
446         }
447
448         *n = o;
449         return 0;
450 }
451
452 static int vt_is_busy(unsigned int vtnr) {
453         struct vt_stat vt_stat;
454         int r = 0;
455         _cleanup_close_ int fd;
456
457         assert(vtnr >= 1);
458
459         /* VT_GETSTATE "cannot return state for more than 16 VTs, since v_state is short" */
460         assert(vtnr <= 15);
461
462         /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
463          * we'd open the latter we'd open the foreground tty which
464          * hence would be unconditionally busy. By opening /dev/tty1
465          * we avoid this. Since tty1 is special and needs to be an
466          * explicitly loaded getty or DM this is safe. */
467
468         fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
469         if (fd < 0)
470                 return -errno;
471
472         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
473                 r = -errno;
474         else
475                 r = !!(vt_stat.v_state & (1 << vtnr));
476
477         return r;
478 }
479
480 int manager_spawn_autovt(Manager *m, unsigned int vtnr) {
481         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
482         char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned int)];
483         int r;
484
485         assert(m);
486         assert(vtnr >= 1);
487
488         if (vtnr > m->n_autovts &&
489             vtnr != m->reserve_vt)
490                 return 0;
491
492         if (vtnr != m->reserve_vt) {
493                 /* If this is the reserved TTY, we'll start the getty
494                  * on it in any case, but otherwise only if it is not
495                  * busy. */
496
497                 r = vt_is_busy(vtnr);
498                 if (r < 0)
499                         return r;
500                 else if (r > 0)
501                         return -EBUSY;
502         }
503
504         snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
505         r = sd_bus_call_method(
506                         m->bus,
507                         "org.freedesktop.systemd1",
508                         "/org/freedesktop/systemd1",
509                         "org.freedesktop.systemd1.Manager",
510                         "StartUnit",
511                         &error,
512                         NULL,
513                         "ss", name, "fail");
514         if (r < 0)
515                 log_error("Failed to start %s: %s", name, bus_error_message(&error, r));
516
517         return r;
518 }
519 #endif // 0
520
521 static bool manager_is_docked(Manager *m) {
522         Iterator i;
523         Button *b;
524
525         HASHMAP_FOREACH(b, m->buttons, i)
526                 if (b->docked)
527                         return true;
528
529         return false;
530 }
531
532 static int manager_count_external_displays(Manager *m) {
533         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
534         struct udev_list_entry *item = NULL, *first = NULL;
535         int r;
536         int n = 0;
537
538         e = udev_enumerate_new(m->udev);
539         if (!e)
540                 return -ENOMEM;
541
542         r = udev_enumerate_add_match_subsystem(e, "drm");
543         if (r < 0)
544                 return r;
545
546         r = udev_enumerate_scan_devices(e);
547         if (r < 0)
548                 return r;
549
550         first = udev_enumerate_get_list_entry(e);
551         udev_list_entry_foreach(item, first) {
552                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
553                 struct udev_device *p;
554                 const char *status, *enabled, *dash, *nn, *i;
555                 bool external = false;
556
557                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
558                 if (!d)
559                         return -ENOMEM;
560
561                 p = udev_device_get_parent(d);
562                 if (!p)
563                         continue;
564
565                 /* If the parent shares the same subsystem as the
566                  * device we are looking at then it is a connector,
567                  * which is what we are interested in. */
568                 if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
569                         continue;
570
571                 nn = udev_device_get_sysname(d);
572                 if (!nn)
573                         continue;
574
575                 /* Ignore internal displays: the type is encoded in
576                  * the sysfs name, as the second dash separated item
577                  * (the first is the card name, the last the connector
578                  * number). We implement a whitelist of external
579                  * displays here, rather than a whitelist, to ensure
580                  * we don't block suspends too eagerly. */
581                 dash = strchr(nn, '-');
582                 if (!dash)
583                         continue;
584
585                 dash++;
586                 FOREACH_STRING(i, "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
587                                "Composite-", "SVIDEO-", "Component-",
588                                "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
589
590                         if (startswith(dash, i)) {
591                                 external = true;
592                                 break;
593                         }
594                 }
595                 if (!external)
596                         continue;
597
598                 /* Ignore ports that are not enabled */
599                 enabled = udev_device_get_sysattr_value(d, "enabled");
600                 if (!enabled)
601                         continue;
602                 if (!streq_ptr(enabled, "enabled"))
603                         continue;
604
605                 /* We count any connector which is not explicitly
606                  * "disconnected" as connected. */
607                 status = udev_device_get_sysattr_value(d, "status");
608                 if (!streq_ptr(status, "disconnected"))
609                         n++;
610         }
611
612         return n;
613 }
614
615 bool manager_is_docked_or_external_displays(Manager *m) {
616         int n;
617
618         /* If we are docked don't react to lid closing */
619         if (manager_is_docked(m)) {
620                 log_debug("System is docked.");
621                 return true;
622         }
623
624         /* If we have more than one display connected,
625          * assume that we are docked. */
626         n = manager_count_external_displays(m);
627         if (n < 0)
628                 log_warning_errno(n, "Display counting failed: %m");
629         else if (n >= 1) {
630                 log_debug("External (%i) displays connected.", n);
631                 return true;
632         }
633
634         return false;
635 }
636
637 bool manager_is_on_external_power(void) {
638         int r;
639
640         /* For now we only check for AC power, but 'external power' can apply
641          * to anything that isn't an internal battery */
642         r = on_ac_power();
643         if (r < 0)
644                 log_warning_errno(r, "Failed to read AC power status: %m");
645         else if (r > 0)
646                 return true;
647
648         return false;
649 }
650
651 bool manager_all_buttons_ignored(Manager *m) {
652         assert(m);
653
654         if (m->handle_power_key != HANDLE_IGNORE)
655                 return false;
656         if (m->handle_suspend_key != HANDLE_IGNORE)
657                 return false;
658         if (m->handle_hibernate_key != HANDLE_IGNORE)
659                 return false;
660         if (m->handle_lid_switch != HANDLE_IGNORE)
661                 return false;
662         if (m->handle_lid_switch_ep != _HANDLE_ACTION_INVALID &&
663             m->handle_lid_switch_ep != HANDLE_IGNORE)
664                 return false;
665         if (m->handle_lid_switch_docked != HANDLE_IGNORE)
666                 return false;
667
668         return true;
669 }