2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek This file is part of systemd.
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek Copyright 2011 Lennart Poettering
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek (at your option) any later version.
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek d = hashmap_get(m->devices, sysfs);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek /* we support adding master-flags, but not removing them */
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek d->master = d->master || master;
61376f96a98291b5421bfd79a15ca4db50c2a3feZbigniew Jędrzejewski-Szmek d = device_new(m, sysfs, master);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_add_seat(Manager *m, const char *id, Seat **_seat) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_add_session(Manager *m, const char *id, Session **_session) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek s = hashmap_get(m->sessions, id);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
8cb4ab0058e51f1fba93683d145ef95f97c2fa86Lennart Poettering u = hashmap_get(m->users, UID_TO_PTR(uid));
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_add_user_by_name(Manager *m, const char *name, User **_user) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek r = get_user_creds(&name, &uid, &gid, NULL, NULL);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek return manager_add_user(m, uid, gid, name, _user);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
f5e5c28f42a2f6d006785ec8b5e98c11a71bb039Zbigniew Jędrzejewski-Szmek return errno > 0 ? -errno : -ENOENT;
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek i = hashmap_get(m->inhibitors, id);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_add_button(Manager *m, const char *name, Button **_button) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek b = hashmap_get(m->buttons, name);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_process_seat_device(Manager *m, struct udev_device *d) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek if (streq_ptr(udev_device_get_action(d), "remove")) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek device = hashmap_get(m->devices, udev_device_get_syspath(d));
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek seat_add_to_gc_queue(device->seat);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek sn = udev_device_get_property_value(d, "ID_SEAT");
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek log_warning("Device with invalid seat name %s found, ignoring.", sn);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek master = udev_device_has_tag(d, "master-of-seat");
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering /* Ignore non-master devices for unknown seats */
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek r = manager_add_device(m, udev_device_get_syspath(d), master, &device);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek r = manager_add_seat(m, sn, &seat);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_process_button_device(Manager *m, struct udev_device *d) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek if (streq_ptr(udev_device_get_action(d), "remove")) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek b = hashmap_get(m->buttons, udev_device_get_sysname(d));
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek r = manager_add_button(m, udev_device_get_sysname(d), &b);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek sn = udev_device_get_property_value(d, "ID_SEAT");
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek _cleanup_free_ char *unit = NULL;
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek r = cg_pid_get_unit(pid, &unit);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek s = hashmap_get(m->session_units, unit);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_get_user_by_pid(Manager *m, pid_t pid, User **user) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek _cleanup_free_ char *unit = NULL;
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek r = cg_pid_get_slice(pid, &unit);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek u = hashmap_get(m->user_units, unit);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekint manager_get_idle_hint(Manager *m, dual_timestamp *t) {
85a428c69465b047731b6abb5005f01824f1444eLennart Poettering idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek HASHMAP_FOREACH(s, m->sessions, i) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek ih = session_get_idle_hint(s, &k);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmekbool manager_shall_kill(Manager *m, const char *user) {
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek if (strv_contains(m->kill_exclude_users, user))
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek if (strv_isempty(m->kill_only_users))
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek return strv_contains(m->kill_only_users, user);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek * we'd open the latter we'd open the foreground tty which
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek * hence would be unconditionally busy. By opening /dev/tty1
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek * we avoid this. Since tty1 is special and needs to be an
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek * explicitly loaded getty or DM this is safe. */
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek r = !!(vt_stat.v_state & (1 << vtnr));
92bd5ff3a062c3f9475b9d9d39b9335bfeb7705eDavid Herrmannint manager_spawn_autovt(Manager *m, unsigned int vtnr) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
61376f96a98291b5421bfd79a15ca4db50c2a3feZbigniew Jędrzejewski-Szmek char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned int)];
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek /* If this is the reserved TTY, we'll start the getty
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek * on it in any case, but otherwise only if it is not
61376f96a98291b5421bfd79a15ca4db50c2a3feZbigniew Jędrzejewski-Szmek snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
2b3ab29de466ae6bd7c3243a5a48c7291cc2af0aZbigniew Jędrzejewski-Szmek "org.freedesktop.systemd1.Manager",
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering log_error("Failed to start %s: %s", name, bus_error_message(&error, r));
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poetteringstatic bool manager_is_docked(Manager *m) {
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poetteringstatic int manager_count_external_displays(Manager *m) {
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering struct udev_list_entry *item = NULL, *first = NULL;
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering r = udev_enumerate_add_match_subsystem(e, "drm");
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering first = udev_enumerate_get_list_entry(e);
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering _cleanup_udev_device_unref_ struct udev_device *d = NULL;
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering const char *status, *enabled, *dash, *nn, *i;
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering /* If the parent shares the same subsystem as the
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering * device we are looking at then it is a connector,
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering * which is what we are interested in. */
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering /* Ignore internal displays: the type is encoded in
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering * the sysfs name, as the second dash seperated item
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering * (the first is the card name, the last the connector
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering * number). We implement a whitelist of external
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering * displays here, rather than a whitelist, to ensure
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering * we don't block suspends too eagerly. */
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering FOREACH_STRING(i, "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering /* Ignore ports that are not enabled */
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering enabled = udev_device_get_sysattr_value(d, "enabled");
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering /* We count any connector which is not explicitly
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering * "disconnected" as connected. */
6a79c58603ea816a1b4fa1520397b4e138bc1ca0Lennart Poettering status = udev_device_get_sysattr_value(d, "status");
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poetteringbool manager_is_docked_or_external_displays(Manager *m) {
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer /* If we are docked don't react to lid closing */
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer /* If we have more than one display connected,
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer * assume that we are docked. */
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_warning_errno(n, "Display counting failed: %m");
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering else if (n >= 1) {
602a41c22ac2df33b4b5e5083719c1cfaf58acf9Lennart Poettering log_debug("External (%i) displays connected.", n);
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer return false;