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