Line data Source code
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 0 : int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
37 : Device *d;
38 :
39 0 : assert(m);
40 0 : assert(sysfs);
41 :
42 0 : d = hashmap_get(m->devices, sysfs);
43 0 : if (d)
44 : /* we support adding master-flags, but not removing them */
45 0 : d->master = d->master || master;
46 : else {
47 0 : d = device_new(m, sysfs, master);
48 0 : if (!d)
49 0 : return -ENOMEM;
50 : }
51 :
52 0 : if (_device)
53 0 : *_device = d;
54 :
55 0 : return 0;
56 : }
57 :
58 0 : int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
59 : Seat *s;
60 :
61 0 : assert(m);
62 0 : assert(id);
63 :
64 0 : s = hashmap_get(m->seats, id);
65 0 : if (!s) {
66 0 : s = seat_new(m, id);
67 0 : if (!s)
68 0 : return -ENOMEM;
69 : }
70 :
71 0 : if (_seat)
72 0 : *_seat = s;
73 :
74 0 : return 0;
75 : }
76 :
77 0 : int manager_add_session(Manager *m, const char *id, Session **_session) {
78 : Session *s;
79 :
80 0 : assert(m);
81 0 : assert(id);
82 :
83 0 : s = hashmap_get(m->sessions, id);
84 0 : if (!s) {
85 0 : s = session_new(m, id);
86 0 : if (!s)
87 0 : return -ENOMEM;
88 : }
89 :
90 0 : if (_session)
91 0 : *_session = s;
92 :
93 0 : return 0;
94 : }
95 :
96 0 : int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
97 : User *u;
98 :
99 0 : assert(m);
100 0 : assert(name);
101 :
102 0 : u = hashmap_get(m->users, UID_TO_PTR(uid));
103 0 : if (!u) {
104 0 : u = user_new(m, uid, gid, name);
105 0 : if (!u)
106 0 : return -ENOMEM;
107 : }
108 :
109 0 : if (_user)
110 0 : *_user = u;
111 :
112 0 : return 0;
113 : }
114 :
115 0 : 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 0 : assert(m);
121 0 : assert(name);
122 :
123 0 : r = get_user_creds(&name, &uid, &gid, NULL, NULL);
124 0 : if (r < 0)
125 0 : return r;
126 :
127 0 : return manager_add_user(m, uid, gid, name, _user);
128 : }
129 :
130 0 : int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
131 : struct passwd *p;
132 :
133 0 : assert(m);
134 :
135 0 : errno = 0;
136 0 : p = getpwuid(uid);
137 0 : if (!p)
138 0 : return errno ? -errno : -ENOENT;
139 :
140 0 : return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
141 : }
142 :
143 0 : int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) {
144 : Inhibitor *i;
145 :
146 0 : assert(m);
147 0 : assert(id);
148 :
149 0 : i = hashmap_get(m->inhibitors, id);
150 0 : if (i) {
151 0 : if (_inhibitor)
152 0 : *_inhibitor = i;
153 :
154 0 : return 0;
155 : }
156 :
157 0 : i = inhibitor_new(m, id);
158 0 : if (!i)
159 0 : return -ENOMEM;
160 :
161 0 : if (_inhibitor)
162 0 : *_inhibitor = i;
163 :
164 0 : return 0;
165 : }
166 :
167 0 : int manager_add_button(Manager *m, const char *name, Button **_button) {
168 : Button *b;
169 :
170 0 : assert(m);
171 0 : assert(name);
172 :
173 0 : b = hashmap_get(m->buttons, name);
174 0 : if (!b) {
175 0 : b = button_new(m, name);
176 0 : if (!b)
177 0 : return -ENOMEM;
178 : }
179 :
180 0 : if (_button)
181 0 : *_button = b;
182 :
183 0 : return 0;
184 : }
185 :
186 0 : int manager_watch_busname(Manager *m, const char *name) {
187 : char *n;
188 : int r;
189 :
190 0 : assert(m);
191 0 : assert(name);
192 :
193 0 : if (set_get(m->busnames, (char*) name))
194 0 : return 0;
195 :
196 0 : n = strdup(name);
197 0 : if (!n)
198 0 : return -ENOMEM;
199 :
200 0 : r = set_put(m->busnames, n);
201 0 : if (r < 0) {
202 0 : free(n);
203 0 : return r;
204 : }
205 :
206 0 : return 0;
207 : }
208 :
209 0 : void manager_drop_busname(Manager *m, const char *name) {
210 : Session *session;
211 : Iterator i;
212 :
213 0 : assert(m);
214 0 : assert(name);
215 :
216 : /* keep it if the name still owns a controller */
217 0 : HASHMAP_FOREACH(session, m->sessions, i)
218 0 : if (session_is_controller(session, name))
219 0 : return;
220 :
221 0 : free(set_remove(m->busnames, (char*) name));
222 : }
223 :
224 0 : int manager_process_seat_device(Manager *m, struct udev_device *d) {
225 : Device *device;
226 : int r;
227 :
228 0 : assert(m);
229 :
230 0 : if (streq_ptr(udev_device_get_action(d), "remove")) {
231 :
232 0 : device = hashmap_get(m->devices, udev_device_get_syspath(d));
233 0 : if (!device)
234 0 : return 0;
235 :
236 0 : seat_add_to_gc_queue(device->seat);
237 0 : device_free(device);
238 :
239 : } else {
240 : const char *sn;
241 0 : Seat *seat = NULL;
242 : bool master;
243 :
244 0 : sn = udev_device_get_property_value(d, "ID_SEAT");
245 0 : if (isempty(sn))
246 0 : sn = "seat0";
247 :
248 0 : if (!seat_name_is_valid(sn)) {
249 0 : log_warning("Device with invalid seat name %s found, ignoring.", sn);
250 0 : return 0;
251 : }
252 :
253 0 : seat = hashmap_get(m->seats, sn);
254 0 : master = udev_device_has_tag(d, "master-of-seat");
255 :
256 : /* Ignore non-master devices for unknown seats */
257 0 : if (!master && !seat)
258 0 : return 0;
259 :
260 0 : r = manager_add_device(m, udev_device_get_syspath(d), master, &device);
261 0 : if (r < 0)
262 0 : return r;
263 :
264 0 : if (!seat) {
265 0 : r = manager_add_seat(m, sn, &seat);
266 0 : if (r < 0) {
267 0 : if (!device->seat)
268 0 : device_free(device);
269 :
270 0 : return r;
271 : }
272 : }
273 :
274 0 : device_attach(device, seat);
275 0 : seat_start(seat);
276 : }
277 :
278 0 : return 0;
279 : }
280 :
281 0 : int manager_process_button_device(Manager *m, struct udev_device *d) {
282 : Button *b;
283 :
284 : int r;
285 :
286 0 : assert(m);
287 :
288 0 : if (streq_ptr(udev_device_get_action(d), "remove")) {
289 :
290 0 : b = hashmap_get(m->buttons, udev_device_get_sysname(d));
291 0 : if (!b)
292 0 : return 0;
293 :
294 0 : button_free(b);
295 :
296 : } else {
297 : const char *sn;
298 :
299 0 : r = manager_add_button(m, udev_device_get_sysname(d), &b);
300 0 : if (r < 0)
301 0 : return r;
302 :
303 0 : sn = udev_device_get_property_value(d, "ID_SEAT");
304 0 : if (isempty(sn))
305 0 : sn = "seat0";
306 :
307 0 : button_set_seat(b, sn);
308 0 : button_open(b);
309 : }
310 :
311 0 : return 0;
312 : }
313 :
314 0 : int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
315 0 : _cleanup_free_ char *unit = NULL;
316 : Session *s;
317 : int r;
318 :
319 0 : assert(m);
320 :
321 0 : if (pid < 1)
322 0 : return -EINVAL;
323 :
324 0 : r = cg_pid_get_unit(pid, &unit);
325 0 : if (r < 0)
326 0 : return 0;
327 :
328 0 : s = hashmap_get(m->session_units, unit);
329 0 : if (!s)
330 0 : return 0;
331 :
332 0 : if (session)
333 0 : *session = s;
334 0 : return 1;
335 : }
336 :
337 0 : int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) {
338 0 : _cleanup_free_ char *unit = NULL;
339 : User *u;
340 : int r;
341 :
342 0 : assert(m);
343 0 : assert(user);
344 :
345 0 : if (pid < 1)
346 0 : return -EINVAL;
347 :
348 0 : r = cg_pid_get_slice(pid, &unit);
349 0 : if (r < 0)
350 0 : return 0;
351 :
352 0 : u = hashmap_get(m->user_units, unit);
353 0 : if (!u)
354 0 : return 0;
355 :
356 0 : *user = u;
357 0 : return 1;
358 : }
359 :
360 0 : int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
361 : Session *s;
362 : bool idle_hint;
363 0 : dual_timestamp ts = DUAL_TIMESTAMP_NULL;
364 : Iterator i;
365 :
366 0 : assert(m);
367 :
368 0 : idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
369 :
370 0 : HASHMAP_FOREACH(s, m->sessions, i) {
371 : dual_timestamp k;
372 : int ih;
373 :
374 0 : ih = session_get_idle_hint(s, &k);
375 0 : if (ih < 0)
376 0 : return ih;
377 :
378 0 : if (!ih) {
379 0 : if (!idle_hint) {
380 0 : if (k.monotonic < ts.monotonic)
381 0 : ts = k;
382 : } else {
383 0 : idle_hint = false;
384 0 : ts = k;
385 : }
386 0 : } else if (idle_hint) {
387 :
388 0 : if (k.monotonic > ts.monotonic)
389 0 : ts = k;
390 : }
391 : }
392 :
393 0 : if (t)
394 0 : *t = ts;
395 :
396 0 : return idle_hint;
397 : }
398 :
399 0 : bool manager_shall_kill(Manager *m, const char *user) {
400 0 : assert(m);
401 0 : assert(user);
402 :
403 0 : if (!m->kill_user_processes)
404 0 : return false;
405 :
406 0 : if (strv_contains(m->kill_exclude_users, user))
407 0 : return false;
408 :
409 0 : if (strv_isempty(m->kill_only_users))
410 0 : return true;
411 :
412 0 : return strv_contains(m->kill_only_users, user);
413 : }
414 :
415 0 : static int vt_is_busy(unsigned int vtnr) {
416 : struct vt_stat vt_stat;
417 0 : int r = 0;
418 0 : _cleanup_close_ int fd;
419 :
420 0 : 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 0 : fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
429 0 : if (fd < 0)
430 0 : return -errno;
431 :
432 0 : if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
433 0 : r = -errno;
434 : else
435 0 : r = !!(vt_stat.v_state & (1 << vtnr));
436 :
437 0 : return r;
438 : }
439 :
440 0 : int manager_spawn_autovt(Manager *m, unsigned int vtnr) {
441 0 : _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 0 : assert(m);
446 0 : assert(vtnr >= 1);
447 :
448 0 : if (vtnr > m->n_autovts &&
449 0 : vtnr != m->reserve_vt)
450 0 : return 0;
451 :
452 0 : 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 0 : r = vt_is_busy(vtnr);
458 0 : if (r < 0)
459 0 : return r;
460 0 : else if (r > 0)
461 0 : return -EBUSY;
462 : }
463 :
464 0 : snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
465 0 : 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 0 : if (r < 0)
475 0 : log_error("Failed to start %s: %s", name, bus_error_message(&error, r));
476 :
477 0 : return r;
478 : }
479 :
480 0 : static bool manager_is_docked(Manager *m) {
481 : Iterator i;
482 : Button *b;
483 :
484 0 : HASHMAP_FOREACH(b, m->buttons, i)
485 0 : if (b->docked)
486 0 : return true;
487 :
488 0 : return false;
489 : }
490 :
491 0 : static int manager_count_external_displays(Manager *m) {
492 0 : _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
493 0 : struct udev_list_entry *item = NULL, *first = NULL;
494 : int r;
495 0 : int n = 0;
496 :
497 0 : e = udev_enumerate_new(m->udev);
498 0 : if (!e)
499 0 : return -ENOMEM;
500 :
501 0 : r = udev_enumerate_add_match_subsystem(e, "drm");
502 0 : if (r < 0)
503 0 : return r;
504 :
505 0 : r = udev_enumerate_scan_devices(e);
506 0 : if (r < 0)
507 0 : return r;
508 :
509 0 : first = udev_enumerate_get_list_entry(e);
510 0 : udev_list_entry_foreach(item, first) {
511 0 : _cleanup_udev_device_unref_ struct udev_device *d = NULL;
512 : struct udev_device *p;
513 : const char *status, *enabled, *dash, *nn, *i;
514 0 : bool external = false;
515 :
516 0 : d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
517 0 : if (!d)
518 0 : return -ENOMEM;
519 :
520 0 : p = udev_device_get_parent(d);
521 0 : if (!p)
522 0 : 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 0 : if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
528 0 : continue;
529 :
530 0 : nn = udev_device_get_sysname(d);
531 0 : if (!nn)
532 0 : 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 0 : dash = strchr(nn, '-');
541 0 : if (!dash)
542 0 : continue;
543 :
544 0 : dash++;
545 0 : FOREACH_STRING(i, "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
546 : "Composite-", "SVIDEO-", "Component-",
547 : "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
548 :
549 0 : if (startswith(dash, i)) {
550 0 : external = true;
551 0 : break;
552 : }
553 : }
554 0 : if (!external)
555 0 : continue;
556 :
557 : /* Ignore ports that are not enabled */
558 0 : enabled = udev_device_get_sysattr_value(d, "enabled");
559 0 : if (!enabled)
560 0 : continue;
561 0 : if (!streq_ptr(enabled, "enabled"))
562 0 : continue;
563 :
564 : /* We count any connector which is not explicitly
565 : * "disconnected" as connected. */
566 0 : status = udev_device_get_sysattr_value(d, "status");
567 0 : if (!streq_ptr(status, "disconnected"))
568 0 : n++;
569 : }
570 :
571 0 : return n;
572 : }
573 :
574 0 : 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 0 : if (manager_is_docked(m)) {
579 0 : log_debug("System is docked.");
580 0 : return true;
581 : }
582 :
583 : /* If we have more than one display connected,
584 : * assume that we are docked. */
585 0 : n = manager_count_external_displays(m);
586 0 : if (n < 0)
587 0 : log_warning_errno(n, "Display counting failed: %m");
588 0 : else if (n >= 1) {
589 0 : log_debug("External (%i) displays connected.", n);
590 0 : return true;
591 : }
592 :
593 0 : return false;
594 : }
|