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