diff options
author | Michael Biebl <biebl@debian.org> | 2018-12-21 22:06:22 +0100 |
---|---|---|
committer | Michael Biebl <biebl@debian.org> | 2018-12-21 22:06:22 +0100 |
commit | 6e866b331d7cd4a5e0759dd160dea6edabd3678e (patch) | |
tree | 4d24c1ffe4ae946f04d8910956090e8d13aecd9a /src/login/logind.c | |
parent | b012e92123bdc9fa10c2f079ec5bd9313b23e21a (diff) | |
download | systemd-6e866b331d7cd4a5e0759dd160dea6edabd3678e.tar.gz |
New upstream version 240
Diffstat (limited to 'src/login/logind.c')
-rw-r--r-- | src/login/logind.c | 317 |
1 files changed, 150 insertions, 167 deletions
diff --git a/src/login/logind.c b/src/login/logind.c index 52fcee933c..8d85de9b43 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -5,25 +5,27 @@ #include <string.h> #include <unistd.h> -#include "libudev.h" #include "sd-daemon.h" +#include "sd-device.h" #include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "cgroup-util.h" #include "def.h" +#include "device-util.h" #include "dirent-util.h" #include "fd-util.h" #include "format-util.h" #include "fs-util.h" #include "logind.h" +#include "main-func.h" #include "parse-util.h" #include "process-util.h" #include "selinux-util.h" #include "signal-util.h" #include "strv.h" -#include "udev-util.h" +#include "terminal-util.h" static Manager* manager_unref(Manager *m); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref); @@ -34,18 +36,21 @@ static int manager_new(Manager **ret) { assert(ret); - m = new0(Manager, 1); + m = new(Manager, 1); if (!m) return -ENOMEM; - m->console_active_fd = -1; - m->reserve_vt_fd = -1; + *m = (Manager) { + .console_active_fd = -1, + .reserve_vt_fd = -1, + }; m->idle_action_not_before_usec = now(CLOCK_MONOTONIC); m->devices = hashmap_new(&string_hash_ops); m->seats = hashmap_new(&string_hash_ops); m->sessions = hashmap_new(&string_hash_ops); + m->sessions_by_leader = hashmap_new(NULL); m->users = hashmap_new(NULL); m->inhibitors = hashmap_new(&string_hash_ops); m->buttons = hashmap_new(&string_hash_ops); @@ -53,13 +58,9 @@ static int manager_new(Manager **ret) { m->user_units = hashmap_new(&string_hash_ops); m->session_units = hashmap_new(&string_hash_ops); - if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units) + if (!m->devices || !m->seats || !m->sessions || !m->sessions_by_leader || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units) return -ENOMEM; - m->udev = udev_new(); - if (!m->udev) - return -errno; - r = sd_event_default(&m->event); if (r < 0) return r; @@ -112,6 +113,7 @@ static Manager* manager_unref(Manager *m) { hashmap_free(m->devices); hashmap_free(m->seats); hashmap_free(m->sessions); + hashmap_free(m->sessions_by_leader); hashmap_free(m->users); hashmap_free(m->inhibitors); hashmap_free(m->buttons); @@ -126,20 +128,18 @@ static Manager* manager_unref(Manager *m) { sd_event_source_unref(m->wall_message_timeout_source); sd_event_source_unref(m->console_active_event_source); - sd_event_source_unref(m->udev_seat_event_source); - sd_event_source_unref(m->udev_device_event_source); - sd_event_source_unref(m->udev_vcsa_event_source); - sd_event_source_unref(m->udev_button_event_source); sd_event_source_unref(m->lid_switch_ignore_event_source); - safe_close(m->console_active_fd); +#if ENABLE_UTMP + sd_event_source_unref(m->utmp_event_source); +#endif - udev_monitor_unref(m->udev_seat_monitor); - udev_monitor_unref(m->udev_device_monitor); - udev_monitor_unref(m->udev_vcsa_monitor); - udev_monitor_unref(m->udev_button_monitor); + safe_close(m->console_active_fd); - udev_unref(m->udev); + sd_device_monitor_unref(m->device_seat_monitor); + sd_device_monitor_unref(m->device_monitor); + sd_device_monitor_unref(m->device_vcsa_monitor); + sd_device_monitor_unref(m->device_button_monitor); if (m->unlink_nologin) (void) unlink_or_warn("/run/nologin"); @@ -163,8 +163,8 @@ static Manager* manager_unref(Manager *m) { } static int manager_enumerate_devices(Manager *m) { - struct udev_list_entry *item = NULL, *first = NULL; - _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL; + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; + sd_device *d; int r; assert(m); @@ -172,31 +172,17 @@ static int manager_enumerate_devices(Manager *m) { /* Loads devices from udev and creates seats for them as * necessary */ - e = udev_enumerate_new(m->udev); - if (!e) - return -ENOMEM; - - r = udev_enumerate_add_match_tag(e, "master-of-seat"); - if (r < 0) - return r; - - r = udev_enumerate_add_match_is_initialized(e); + r = sd_device_enumerator_new(&e); if (r < 0) return r; - r = udev_enumerate_scan_devices(e); + r = sd_device_enumerator_add_match_tag(e, "master-of-seat"); if (r < 0) return r; - first = udev_enumerate_get_list_entry(e); - udev_list_entry_foreach(item, first) { - _cleanup_(udev_device_unrefp) struct udev_device *d = NULL; + FOREACH_DEVICE(e, d) { int k; - d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item)); - if (!d) - return -ENOMEM; - k = manager_process_seat_device(m, d); if (k < 0) r = k; @@ -206,8 +192,8 @@ static int manager_enumerate_devices(Manager *m) { } static int manager_enumerate_buttons(Manager *m) { - _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL; - struct udev_list_entry *item = NULL, *first = NULL; + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; + sd_device *d; int r; assert(m); @@ -217,35 +203,21 @@ static int manager_enumerate_buttons(Manager *m) { if (manager_all_buttons_ignored(m)) return 0; - e = udev_enumerate_new(m->udev); - if (!e) - return -ENOMEM; - - r = udev_enumerate_add_match_subsystem(e, "input"); + r = sd_device_enumerator_new(&e); if (r < 0) return r; - r = udev_enumerate_add_match_tag(e, "power-switch"); + r = sd_device_enumerator_add_match_subsystem(e, "input", true); if (r < 0) return r; - r = udev_enumerate_add_match_is_initialized(e); + r = sd_device_enumerator_add_match_tag(e, "power-switch"); if (r < 0) return r; - r = udev_enumerate_scan_devices(e); - if (r < 0) - return r; - - first = udev_enumerate_get_list_entry(e); - udev_list_entry_foreach(item, first) { - _cleanup_(udev_device_unrefp) struct udev_device *d = NULL; + FOREACH_DEVICE(e, d) { int k; - d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item)); - if (!d) - return -ENOMEM; - k = manager_process_button_device(m, d); if (k < 0) r = k; @@ -373,7 +345,7 @@ static int manager_enumerate_users(Manager *m) { static int parse_fdname(const char *fdname, char **session_id, dev_t *dev) { _cleanup_strv_free_ char **parts = NULL; _cleanup_free_ char *id = NULL; - unsigned int major, minor; + unsigned major, minor; int r; parts = strv_split(fdname, "-"); @@ -565,67 +537,52 @@ static int manager_enumerate_inhibitors(Manager *m) { return r; } -static int manager_dispatch_seat_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(udev_device_unrefp) struct udev_device *d = NULL; +static int manager_dispatch_seat_udev(sd_device_monitor *monitor, sd_device *device, void *userdata) { Manager *m = userdata; assert(m); + assert(device); - d = udev_monitor_receive_device(m->udev_seat_monitor); - if (!d) - return -ENOMEM; - - manager_process_seat_device(m, d); + manager_process_seat_device(m, device); return 0; } -static int manager_dispatch_device_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(udev_device_unrefp) struct udev_device *d = NULL; +static int manager_dispatch_device_udev(sd_device_monitor *monitor, sd_device *device, void *userdata) { Manager *m = userdata; assert(m); + assert(device); - d = udev_monitor_receive_device(m->udev_device_monitor); - if (!d) - return -ENOMEM; - - manager_process_seat_device(m, d); + manager_process_seat_device(m, device); return 0; } -static int manager_dispatch_vcsa_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(udev_device_unrefp) struct udev_device *d = NULL; +static int manager_dispatch_vcsa_udev(sd_device_monitor *monitor, sd_device *device, void *userdata) { Manager *m = userdata; - const char *name; + const char *name, *action; assert(m); - - d = udev_monitor_receive_device(m->udev_vcsa_monitor); - if (!d) - return -ENOMEM; - - name = udev_device_get_sysname(d); + assert(device); /* Whenever a VCSA device is removed try to reallocate our * VTs, to make sure our auto VTs never go away. */ - if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove")) + if (sd_device_get_sysname(device, &name) >= 0 && + startswith(name, "vcsa") && + sd_device_get_property_value(device, "ACTION", &action) >= 0 && + streq(action, "remove")) seat_preallocate_vts(m->seat0); return 0; } -static int manager_dispatch_button_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(udev_device_unrefp) struct udev_device *d = NULL; +static int manager_dispatch_button_udev(sd_device_monitor *monitor, sd_device *device, void *userdata) { Manager *m = userdata; assert(m); + assert(device); - d = udev_monitor_receive_device(m->udev_button_monitor); - if (!d) - return -ENOMEM; - - manager_process_button_device(m, d); + manager_process_button_device(m, device); return 0; } @@ -791,7 +748,29 @@ static int manager_vt_switch(sd_event_source *src, const struct signalfd_siginfo active = m->seat0->active; if (!active || active->vtnr < 1) { - log_warning("Received VT_PROCESS signal without a registered session on that VT."); + _cleanup_close_ int fd = -1; + int r; + + /* We are requested to acknowledge the VT-switch signal by the kernel but + * there's no registered sessions for the current VT. Normally this + * shouldn't happen but something wrong might have happened when we tried + * to release the VT. Better be safe than sorry, and try to release the VT + * one more time otherwise the user will be locked with the current VT. */ + + log_warning("Received VT_PROCESS signal without a registered session, restoring VT."); + + /* At this point we only have the kernel mapping for referring to the + * current VT. */ + fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); + if (fd < 0) { + log_warning_errno(fd, "Failed to open, ignoring: %m"); + return 0; + } + + r = vt_release(fd, true); + if (r < 0) + log_warning_errno(r, "Failed to release VT, ignoring: %m"); + return 0; } @@ -815,28 +794,28 @@ static int manager_connect_console(Manager *m) { assert(m); assert(m->console_active_fd < 0); - /* On certain architectures (S390 and Xen, and containers), - /dev/tty0 does not exist, so don't fail if we can't open - it. */ + /* On certain systems (such as S390, Xen, and containers) /dev/tty0 does not exist (as there is no VC), so + * don't fail if we can't open it. */ + if (access("/dev/tty0", F_OK) < 0) return 0; m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC); if (m->console_active_fd < 0) { - /* On some systems the device node /dev/tty0 may exist - * even though /sys/class/tty/tty0 does not. */ - if (errno == ENOENT) + /* On some systems /dev/tty0 may exist even though /sys/class/tty/tty0 does not. These are broken, but + * common. Let's complain but continue anyway. */ + if (errno == ENOENT) { + log_warning_errno(errno, "System has /dev/tty0 but not /sys/class/tty/tty0/active which is broken, ignoring: %m"); return 0; + } return log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m"); } r = sd_event_add_io(m->event, &m->console_active_event_source, m->console_active_fd, 0, manager_dispatch_console, m); - if (r < 0) { - log_error("Failed to watch foreground console"); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to watch foreground console: %m"); /* * SIGRTMIN is used as global VT-release signal, SIGRTMIN + 1 is used @@ -845,17 +824,17 @@ static int manager_connect_console(Manager *m) { * release events immediately. */ - if (SIGRTMIN + 1 > SIGRTMAX) { - log_error("Not enough real-time signals available: %u-%u", SIGRTMIN, SIGRTMAX); - return -EINVAL; - } + if (SIGRTMIN + 1 > SIGRTMAX) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Not enough real-time signals available: %u-%u", + SIGRTMIN, SIGRTMAX); assert_se(ignore_signals(SIGRTMIN + 1, -1) >= 0); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN, -1) >= 0); r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m); if (r < 0) - return r; + return log_error_errno(r, "Failed to subscribe to signal: %m"); return 0; } @@ -864,92 +843,100 @@ static int manager_connect_udev(Manager *m) { int r; assert(m); - assert(!m->udev_seat_monitor); - assert(!m->udev_device_monitor); - assert(!m->udev_vcsa_monitor); - assert(!m->udev_button_monitor); + assert(!m->device_seat_monitor); + assert(!m->device_monitor); + assert(!m->device_vcsa_monitor); + assert(!m->device_button_monitor); - m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); - if (!m->udev_seat_monitor) - return -ENOMEM; + r = sd_device_monitor_new(&m->device_seat_monitor); + if (r < 0) + return r; - r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "master-of-seat"); + r = sd_device_monitor_filter_add_match_tag(m->device_seat_monitor, "master-of-seat"); if (r < 0) return r; - r = udev_monitor_enable_receiving(m->udev_seat_monitor); + r = sd_device_monitor_attach_event(m->device_seat_monitor, m->event); if (r < 0) return r; - r = sd_event_add_io(m->event, &m->udev_seat_event_source, udev_monitor_get_fd(m->udev_seat_monitor), EPOLLIN, manager_dispatch_seat_udev, m); + r = sd_device_monitor_start(m->device_seat_monitor, manager_dispatch_seat_udev, m); if (r < 0) return r; - m->udev_device_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); - if (!m->udev_device_monitor) - return -ENOMEM; + (void) sd_event_source_set_description(sd_device_monitor_get_event_source(m->device_seat_monitor), "logind-seat-monitor"); - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "input", NULL); + r = sd_device_monitor_new(&m->device_monitor); if (r < 0) return r; - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "graphics", NULL); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "input", NULL); if (r < 0) return r; - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "drm", NULL); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "graphics", NULL); if (r < 0) return r; - r = udev_monitor_enable_receiving(m->udev_device_monitor); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "drm", NULL); if (r < 0) return r; - r = sd_event_add_io(m->event, &m->udev_device_event_source, udev_monitor_get_fd(m->udev_device_monitor), EPOLLIN, manager_dispatch_device_udev, m); + r = sd_device_monitor_attach_event(m->device_monitor, m->event); if (r < 0) return r; + r = sd_device_monitor_start(m->device_monitor, manager_dispatch_device_udev, m); + if (r < 0) + return r; + + (void) sd_event_source_set_description(sd_device_monitor_get_event_source(m->device_monitor), "logind-device-monitor"); + /* Don't watch keys if nobody cares */ if (!manager_all_buttons_ignored(m)) { - m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); - if (!m->udev_button_monitor) - return -ENOMEM; + r = sd_device_monitor_new(&m->device_button_monitor); + if (r < 0) + return r; - r = udev_monitor_filter_add_match_tag(m->udev_button_monitor, "power-switch"); + r = sd_device_monitor_filter_add_match_tag(m->device_button_monitor, "power-switch"); if (r < 0) return r; - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_button_monitor, "input", NULL); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_button_monitor, "input", NULL); if (r < 0) return r; - r = udev_monitor_enable_receiving(m->udev_button_monitor); + r = sd_device_monitor_attach_event(m->device_button_monitor, m->event); if (r < 0) return r; - r = sd_event_add_io(m->event, &m->udev_button_event_source, udev_monitor_get_fd(m->udev_button_monitor), EPOLLIN, manager_dispatch_button_udev, m); + r = sd_device_monitor_start(m->device_button_monitor, manager_dispatch_button_udev, m); if (r < 0) return r; + + (void) sd_event_source_set_description(sd_device_monitor_get_event_source(m->device_button_monitor), "logind-button-monitor"); } /* Don't bother watching VCSA devices, if nobody cares */ if (m->n_autovts > 0 && m->console_active_fd >= 0) { - m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); - if (!m->udev_vcsa_monitor) - return -ENOMEM; + r = sd_device_monitor_new(&m->device_vcsa_monitor); + if (r < 0) + return r; - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_vcsa_monitor, "vc", NULL); if (r < 0) return r; - r = udev_monitor_enable_receiving(m->udev_vcsa_monitor); + r = sd_device_monitor_attach_event(m->device_vcsa_monitor, m->event); if (r < 0) return r; - r = sd_event_add_io(m->event, &m->udev_vcsa_event_source, udev_monitor_get_fd(m->udev_vcsa_monitor), EPOLLIN, manager_dispatch_vcsa_udev, m); + r = sd_device_monitor_start(m->device_vcsa_monitor, manager_dispatch_vcsa_udev, m); if (r < 0) return r; + + (void) sd_event_source_set_description(sd_device_monitor_get_event_source(m->device_vcsa_monitor), "logind-vcsa-monitor"); } return 0; @@ -979,13 +966,13 @@ static void manager_gc(Manager *m, bool drop_not_started) { /* First, if we are not closing yet, initiate stopping */ if (session_may_gc(session, drop_not_started) && session_get_state(session) != SESSION_CLOSING) - session_stop(session, false); + (void) session_stop(session, false); /* Normally, this should make the session referenced * again, if it doesn't then let's get rid of it * immediately */ if (session_may_gc(session, drop_not_started)) { - session_finalize(session); + (void) session_finalize(session); session_free(session); } } @@ -996,11 +983,11 @@ static void manager_gc(Manager *m, bool drop_not_started) { /* First step: queue stop jobs */ if (user_may_gc(user, drop_not_started)) - user_stop(user, false); + (void) user_stop(user, false); /* Second step: finalize user */ if (user_may_gc(user, drop_not_started)) { - user_finalize(user); + (void) user_finalize(user); user_free(user); } } @@ -1095,6 +1082,9 @@ static int manager_startup(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to register SIGHUP handler: %m"); + /* Connect to utmp */ + manager_connect_utmp(m); + /* Connect to console */ r = manager_connect_console(m); if (r < 0) @@ -1150,15 +1140,18 @@ static int manager_startup(Manager *m) { /* Reserve the special reserved VT */ manager_reserve_vt(m); + /* Read in utmp if it exists */ + manager_read_utmp(m); + /* And start everything */ HASHMAP_FOREACH(seat, m->seats, i) - seat_start(seat); + (void) seat_start(seat); HASHMAP_FOREACH(user, m->users, i) - user_start(user); + (void) user_start(user); HASHMAP_FOREACH(session, m->sessions, i) - session_start(session, NULL); + (void) session_start(session, NULL, NULL); HASHMAP_FOREACH(inhibitor, m->inhibitors, i) inhibitor_start(inhibitor); @@ -1197,28 +1190,23 @@ static int manager_run(Manager *m) { } } -int main(int argc, char *argv[]) { +static int run(int argc, char *argv[]) { _cleanup_(manager_unrefp) Manager *m = NULL; int r; - log_set_target(LOG_TARGET_AUTO); log_set_facility(LOG_AUTH); - log_parse_environment(); - log_open(); + log_setup_service(); umask(0022); if (argc != 1) { log_error("This program takes no arguments."); - r = -EINVAL; - goto finish; + return -EINVAL; } r = mac_selinux_init(); - if (r < 0) { - log_error_errno(r, "Could not initialize labelling: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Could not initialize labelling: %m"); /* Always create the directories people can create inotify watches in. Note that some applications might check * for the existence of /run/systemd/seats/ to determine whether logind is available, so please always make @@ -1230,21 +1218,16 @@ int main(int argc, char *argv[]) { assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGHUP, SIGTERM, SIGINT, -1) >= 0); r = manager_new(&m); - if (r < 0) { - log_error_errno(r, "Failed to allocate manager object: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to allocate manager object: %m"); (void) manager_parse_config_file(m); r = manager_startup(m); - if (r < 0) { - log_error_errno(r, "Failed to fully start up daemon: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to fully start up daemon: %m"); log_debug("systemd-logind running as pid "PID_FMT, getpid_cached()); - (void) sd_notify(false, "READY=1\n" "STATUS=Processing requests..."); @@ -1252,11 +1235,11 @@ int main(int argc, char *argv[]) { r = manager_run(m); log_debug("systemd-logind stopped as pid "PID_FMT, getpid_cached()); - (void) sd_notify(false, "STOPPING=1\n" "STATUS=Shutting down..."); -finish: - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + return r; } + +DEFINE_MAIN_FUNCTION(run); |