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