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