2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
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.
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.
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/>.
22 #include <sys/ioctl.h>
23 #include <sys/types.h>
26 #include "alloc-util.h"
27 #include "bus-error.h"
29 #include "cgroup-util.h"
33 #include "terminal-util.h"
34 #include "udev-util.h"
35 #include "user-util.h"
37 int manager_add_device(Manager
*m
, const char *sysfs
, bool master
, Device
**_device
) {
43 d
= hashmap_get(m
->devices
, sysfs
);
45 /* we support adding master-flags, but not removing them */
46 d
->master
= d
->master
|| master
;
48 d
= device_new(m
, sysfs
, master
);
59 int manager_add_seat(Manager
*m
, const char *id
, Seat
**_seat
) {
65 s
= hashmap_get(m
->seats
, id
);
78 int manager_add_session(Manager
*m
, const char *id
, Session
**_session
) {
84 s
= hashmap_get(m
->sessions
, id
);
86 s
= session_new(m
, id
);
97 int manager_add_user(Manager
*m
, uid_t uid
, gid_t gid
, const char *name
, User
**_user
) {
104 u
= hashmap_get(m
->users
, UID_TO_PTR(uid
));
106 r
= user_new(&u
, m
, uid
, gid
, name
);
117 int manager_add_user_by_name(Manager
*m
, const char *name
, User
**_user
) {
125 r
= get_user_creds(&name
, &uid
, &gid
, NULL
, NULL
);
129 return manager_add_user(m
, uid
, gid
, name
, _user
);
132 int manager_add_user_by_uid(Manager
*m
, uid_t uid
, User
**_user
) {
140 return errno
> 0 ? -errno
: -ENOENT
;
142 return manager_add_user(m
, uid
, p
->pw_gid
, p
->pw_name
, _user
);
145 int manager_add_inhibitor(Manager
*m
, const char* id
, Inhibitor
**_inhibitor
) {
151 i
= hashmap_get(m
->inhibitors
, id
);
159 i
= inhibitor_new(m
, id
);
169 int manager_add_button(Manager
*m
, const char *name
, Button
**_button
) {
175 b
= hashmap_get(m
->buttons
, name
);
177 b
= button_new(m
, name
);
188 int manager_process_seat_device(Manager
*m
, struct udev_device
*d
) {
194 if (streq_ptr(udev_device_get_action(d
), "remove")) {
196 device
= hashmap_get(m
->devices
, udev_device_get_syspath(d
));
200 seat_add_to_gc_queue(device
->seat
);
208 sn
= udev_device_get_property_value(d
, "ID_SEAT");
212 if (!seat_name_is_valid(sn
)) {
213 log_warning("Device with invalid seat name %s found, ignoring.", sn
);
217 seat
= hashmap_get(m
->seats
, sn
);
218 master
= udev_device_has_tag(d
, "master-of-seat");
220 /* Ignore non-master devices for unknown seats */
221 if (!master
&& !seat
)
224 r
= manager_add_device(m
, udev_device_get_syspath(d
), master
, &device
);
229 r
= manager_add_seat(m
, sn
, &seat
);
238 device_attach(device
, seat
);
245 int manager_process_button_device(Manager
*m
, struct udev_device
*d
) {
252 if (streq_ptr(udev_device_get_action(d
), "remove")) {
254 b
= hashmap_get(m
->buttons
, udev_device_get_sysname(d
));
263 r
= manager_add_button(m
, udev_device_get_sysname(d
), &b
);
267 sn
= udev_device_get_property_value(d
, "ID_SEAT");
271 button_set_seat(b
, sn
);
278 int manager_get_session_by_pid(Manager
*m
, pid_t pid
, Session
**session
) {
279 _cleanup_free_
char *unit
= NULL
;
288 r
= cg_pid_get_unit(pid
, &unit
);
292 s
= hashmap_get(m
->session_units
, unit
);
301 int manager_get_user_by_pid(Manager
*m
, pid_t pid
, User
**user
) {
302 _cleanup_free_
char *unit
= NULL
;
312 r
= cg_pid_get_slice(pid
, &unit
);
316 u
= hashmap_get(m
->user_units
, unit
);
324 int manager_get_idle_hint(Manager
*m
, dual_timestamp
*t
) {
327 dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
332 idle_hint
= !manager_is_inhibited(m
, INHIBIT_IDLE
, INHIBIT_BLOCK
, t
, false, false, 0, NULL
);
334 HASHMAP_FOREACH(s
, m
->sessions
, i
) {
338 ih
= session_get_idle_hint(s
, &k
);
344 if (k
.monotonic
< ts
.monotonic
)
350 } else if (idle_hint
) {
352 if (k
.monotonic
> ts
.monotonic
)
363 bool manager_shall_kill(Manager
*m
, const char *user
) {
367 if (!m
->kill_user_processes
)
370 if (!m
->kill_exclude_users
&& streq(user
, "root"))
373 if (strv_contains(m
->kill_exclude_users
, user
))
376 if (strv_isempty(m
->kill_only_users
))
379 return strv_contains(m
->kill_only_users
, user
);
382 static int vt_is_busy(unsigned int vtnr
) {
383 struct vt_stat vt_stat
;
385 _cleanup_close_
int fd
;
389 /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
390 * we'd open the latter we'd open the foreground tty which
391 * hence would be unconditionally busy. By opening /dev/tty1
392 * we avoid this. Since tty1 is special and needs to be an
393 * explicitly loaded getty or DM this is safe. */
395 fd
= open_terminal("/dev/tty1", O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
399 if (ioctl(fd
, VT_GETSTATE
, &vt_stat
) < 0)
402 r
= !!(vt_stat
.v_state
& (1 << vtnr
));
407 int manager_spawn_autovt(Manager
*m
, unsigned int vtnr
) {
408 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
409 char name
[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned int)];
415 if (vtnr
> m
->n_autovts
&&
416 vtnr
!= m
->reserve_vt
)
419 if (vtnr
!= m
->reserve_vt
) {
420 /* If this is the reserved TTY, we'll start the getty
421 * on it in any case, but otherwise only if it is not
424 r
= vt_is_busy(vtnr
);
431 snprintf(name
, sizeof(name
), "autovt@tty%u.service", vtnr
);
432 r
= sd_bus_call_method(
434 "org.freedesktop.systemd1",
435 "/org/freedesktop/systemd1",
436 "org.freedesktop.systemd1.Manager",
442 log_error("Failed to start %s: %s", name
, bus_error_message(&error
, r
));
447 static bool manager_is_docked(Manager
*m
) {
451 HASHMAP_FOREACH(b
, m
->buttons
, i
)
458 static int manager_count_external_displays(Manager
*m
) {
459 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
460 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
464 e
= udev_enumerate_new(m
->udev
);
468 r
= udev_enumerate_add_match_subsystem(e
, "drm");
472 r
= udev_enumerate_scan_devices(e
);
476 first
= udev_enumerate_get_list_entry(e
);
477 udev_list_entry_foreach(item
, first
) {
478 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
479 struct udev_device
*p
;
480 const char *status
, *enabled
, *dash
, *nn
, *i
;
481 bool external
= false;
483 d
= udev_device_new_from_syspath(m
->udev
, udev_list_entry_get_name(item
));
487 p
= udev_device_get_parent(d
);
491 /* If the parent shares the same subsystem as the
492 * device we are looking at then it is a connector,
493 * which is what we are interested in. */
494 if (!streq_ptr(udev_device_get_subsystem(p
), "drm"))
497 nn
= udev_device_get_sysname(d
);
501 /* Ignore internal displays: the type is encoded in
502 * the sysfs name, as the second dash seperated item
503 * (the first is the card name, the last the connector
504 * number). We implement a whitelist of external
505 * displays here, rather than a whitelist, to ensure
506 * we don't block suspends too eagerly. */
507 dash
= strchr(nn
, '-');
512 FOREACH_STRING(i
, "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
513 "Composite-", "SVIDEO-", "Component-",
514 "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
516 if (startswith(dash
, i
)) {
524 /* Ignore ports that are not enabled */
525 enabled
= udev_device_get_sysattr_value(d
, "enabled");
528 if (!streq_ptr(enabled
, "enabled"))
531 /* We count any connector which is not explicitly
532 * "disconnected" as connected. */
533 status
= udev_device_get_sysattr_value(d
, "status");
534 if (!streq_ptr(status
, "disconnected"))
541 bool manager_is_docked_or_external_displays(Manager
*m
) {
544 /* If we are docked don't react to lid closing */
545 if (manager_is_docked(m
)) {
546 log_debug("System is docked.");
550 /* If we have more than one display connected,
551 * assume that we are docked. */
552 n
= manager_count_external_displays(m
);
554 log_warning_errno(n
, "Display counting failed: %m");
556 log_debug("External (%i) displays connected.", n
);