X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flogind.c;h=a0a89c0689a5e97318d24d5c478a016528f37b21;hb=88bb8d215aa0f5576eb3f9c77c30cdc4b17783fe;hp=3100fd25177a010e8d0efaaf25790fa4f7172f13;hpb=a2e5283217b9e1e636ab3272e8d36e724a78cf6a;p=elogind.git diff --git a/src/logind.c b/src/logind.c index 3100fd251..a0a89c068 100644 --- a/src/logind.c +++ b/src/logind.c @@ -42,7 +42,8 @@ Manager *manager_new(void) { m->console_active_fd = -1; m->bus_fd = -1; - m->udev_fd = -1; + m->udev_seat_fd = -1; + m->udev_vcsa_fd = -1; m->epoll_fd = -1; m->n_autovts = 6; @@ -102,8 +103,11 @@ void manager_free(Manager *m) { if (m->console_active_fd >= 0) close_nointr_nofail(m->console_active_fd); - if (m->udev_monitor) - udev_monitor_unref(m->udev_monitor); + if (m->udev_seat_monitor) + udev_monitor_unref(m->udev_seat_monitor); + + if (m->udev_vcsa_monitor) + udev_monitor_unref(m->udev_vcsa_monitor); if (m->udev) udev_unref(m->udev); @@ -247,7 +251,7 @@ int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) { return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user); } -int manager_process_device(Manager *m, struct udev_device *d) { +int manager_process_seat_device(Manager *m, struct udev_device *d) { Device *device; int r; @@ -339,7 +343,7 @@ int manager_enumerate_devices(Manager *m) { goto finish; } - k = manager_process_device(m, d); + k = manager_process_seat_device(m, d); udev_device_unref(d); if (k < 0) @@ -621,17 +625,42 @@ int manager_enumerate_sessions(Manager *m) { return r; } -int manager_dispatch_udev(Manager *m) { +int manager_dispatch_seat_udev(Manager *m) { struct udev_device *d; int r; assert(m); - d = udev_monitor_receive_device(m->udev_monitor); + d = udev_monitor_receive_device(m->udev_seat_monitor); if (!d) return -ENOMEM; - r = manager_process_device(m, d); + r = manager_process_seat_device(m, d); + udev_device_unref(d); + + return r; +} + + +int manager_dispatch_vcsa_udev(Manager *m) { + struct udev_device *d; + int r = 0; + const char *name; + + assert(m); + + d = udev_monitor_receive_device(m->udev_vcsa_monitor); + if (!d) + return -ENOMEM; + + name = udev_device_get_sysname(d); + + /* 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")) + r = seat_preallocate_vts(m->vtconsole); + udev_device_unref(d); return r; @@ -652,7 +681,13 @@ static int vt_is_busy(int vtnr) { assert(vtnr >= 1); - fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); + /* We explicitly open /dev/tty1 here instead of /dev/tty0. If + * we'd open the latter we'd open the foreground tty which + * hence would be unconditionally busy. By opening /dev/tty1 + * we avoid this. Since tty1 is special and needs to be an + * explicitly loaded getty or DM this is safe. */ + + fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC); if (fd < 0) return -errno; @@ -668,16 +703,67 @@ static int vt_is_busy(int vtnr) { int manager_spawn_autovt(Manager *m, int vtnr) { int r; + DBusMessage *message = NULL, *reply = NULL; + char *name = NULL; + const char *mode = "fail"; + DBusError error; assert(m); + assert(vtnr >= 1); + + dbus_error_init(&error); + + if ((unsigned) vtnr > m->n_autovts) + return 0; r = vt_is_busy(vtnr); - if (r != 0) + if (r < 0) return r; + else if (r > 0) + return -EBUSY; - /* ... */ + message = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit"); + if (!message) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } - return 0; + if (asprintf(&name, "autovt@tty%i.service", vtnr) < 0) { + log_error("Could not allocate service name."); + r = -ENOMEM; + goto finish; + } + + if (!dbus_message_append_args(message, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID)) { + log_error("Could not attach target and flag information to message."); + r = -ENOMEM; + goto finish; + } + + reply = dbus_connection_send_with_reply_and_block(m->bus, message, -1, &error); + if (!reply) { + log_error("Failed to start unit: %s", bus_error_message(&error)); + goto finish; + } + + r = 0; + +finish: + free(name); + + if (message) + dbus_message_unref(message); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; } void manager_cgroup_notify_empty(Manager *m, const char *cgroup) { @@ -720,7 +806,7 @@ static void manager_pipe_notify_eof(Manager *m, int fd) { assert(s->pipe_fd == fd); session_unset_pipe_fd(s); - session_add_to_gc_queue(s); + session_stop(s); } static int manager_connect_bus(Manager *m) { @@ -825,31 +911,56 @@ static int manager_connect_udev(Manager *m) { int r; assert(m); - assert(!m->udev_monitor); + assert(!m->udev_seat_monitor); + assert(!m->udev_vcsa_monitor); - m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); - if (!m->udev_monitor) + m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_seat_monitor) return -ENOMEM; - r = udev_monitor_filter_add_match_tag(m->udev_monitor, "seat"); + r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "seat"); if (r < 0) return r; - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "graphics", NULL); + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_seat_monitor, "graphics", NULL); if (r < 0) return r; - r = udev_monitor_enable_receiving(m->udev_monitor); + r = udev_monitor_enable_receiving(m->udev_seat_monitor); if (r < 0) return r; - m->udev_fd = udev_monitor_get_fd(m->udev_monitor); + m->udev_seat_fd = udev_monitor_get_fd(m->udev_seat_monitor); zero(ev); ev.events = EPOLLIN; - ev.data.u32 = FD_UDEV; + ev.data.u32 = FD_SEAT_UDEV; + + if (m->n_autovts <= 0) + return 0; - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_fd, &ev) < 0) + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0) + return -errno; + + m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_vcsa_monitor) + return -ENOMEM; + + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL); + if (r < 0) + return r; + + r = udev_monitor_enable_receiving(m->udev_vcsa_monitor); + if (r < 0) + return r; + + m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor); + + zero(ev); + ev.events = EPOLLIN; + ev.data.u32 = FD_VCSA_UDEV; + + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0) return -errno; return 0; @@ -1011,8 +1122,12 @@ int manager_run(Manager *m) { switch (event.data.u32) { - case FD_UDEV: - manager_dispatch_udev(m); + case FD_SEAT_UDEV: + manager_dispatch_seat_udev(m); + break; + + case FD_VCSA_UDEV: + manager_dispatch_vcsa_udev(m); break; case FD_CONSOLE: