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