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