X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogin%2Flogind.c;h=f1b6a86298bd5b1237469c8c6f60292da094172b;hp=686506cc6511543275cb48802d080e757dfeb3cc;hb=d5099efc47d4e6ac60816b5381a5f607ab03f06e;hpb=19befb2d5fc087f96e40ddc432b2cc9385666209 diff --git a/src/login/logind.c b/src/login/logind.c index 686506cc6..f1b6a8629 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -55,6 +55,7 @@ Manager *manager_new(void) { m->handle_suspend_key = HANDLE_SUSPEND; m->handle_hibernate_key = HANDLE_HIBERNATE; m->handle_lid_switch = HANDLE_SUSPEND; + m->handle_lid_switch_docked = HANDLE_IGNORE; m->lid_switch_ignore_inhibited = true; m->idle_action_usec = 30 * USEC_PER_MINUTE; @@ -63,17 +64,17 @@ Manager *manager_new(void) { m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ - m->devices = hashmap_new(string_hash_func, string_compare_func); - m->seats = hashmap_new(string_hash_func, string_compare_func); - m->sessions = hashmap_new(string_hash_func, string_compare_func); - m->users = hashmap_new(trivial_hash_func, trivial_compare_func); - m->inhibitors = hashmap_new(string_hash_func, string_compare_func); - m->buttons = hashmap_new(string_hash_func, string_compare_func); + m->devices = hashmap_new(&string_hash_ops); + m->seats = hashmap_new(&string_hash_ops); + m->sessions = hashmap_new(&string_hash_ops); + m->users = hashmap_new(NULL); + m->inhibitors = hashmap_new(&string_hash_ops); + m->buttons = hashmap_new(&string_hash_ops); - m->user_units = hashmap_new(string_hash_func, string_compare_func); - m->session_units = hashmap_new(string_hash_func, string_compare_func); + m->user_units = hashmap_new(&string_hash_ops); + m->session_units = hashmap_new(&string_hash_ops); - m->busnames = set_new(string_hash_func, string_compare_func); + m->busnames = set_new(&string_hash_ops); if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->busnames || !m->user_units || !m->session_units) @@ -163,7 +164,7 @@ void manager_free(Manager *m) { if (m->udev) udev_unref(m->udev); - bus_verify_polkit_async_registry_free(m->bus, m->polkit_registry); + bus_verify_polkit_async_registry_free(m->polkit_registry); sd_bus_unref(m->bus); sd_event_unref(m->event); @@ -232,7 +233,8 @@ static int manager_enumerate_buttons(Manager *m) { if (m->handle_power_key == HANDLE_IGNORE && m->handle_suspend_key == HANDLE_IGNORE && m->handle_hibernate_key == HANDLE_IGNORE && - m->handle_lid_switch == HANDLE_IGNORE) + m->handle_lid_switch == HANDLE_IGNORE && + m->handle_lid_switch_docked == HANDLE_IGNORE) return 0; e = udev_enumerate_new(m->udev); @@ -720,6 +722,47 @@ static int manager_connect_bus(Manager *m) { return 0; } +static int manager_vt_switch(sd_event_source *src, const struct signalfd_siginfo *si, void *data) { + Manager *m = data; + Session *active, *iter; + + /* + * We got a VT-switch signal and we have to acknowledge it immediately. + * Preferably, we'd just use m->seat0->active->vtfd, but unfortunately, + * old user-space might run multiple sessions on a single VT, *sigh*. + * Therefore, we have to iterate all sessions and find one with a vtfd + * on the requested VT. + * As only VTs with active controllers have VT_PROCESS set, our current + * notion of the active VT might be wrong (for instance if the switch + * happens while we setup VT_PROCESS). Therefore, read the current VT + * first and then use s->active->vtnr as reference. Note that this is + * not racy, as no further VT-switch can happen as long as we're in + * synchronous VT_PROCESS mode. + */ + + assert(m->seat0); + seat_read_active_vt(m->seat0); + + active = m->seat0->active; + if (!active || active->vtnr < 1) { + log_warning("Received VT_PROCESS signal without a registered session on that VT."); + return 0; + } + + if (active->vtfd >= 0) { + ioctl(active->vtfd, VT_RELDISP, 1); + } else { + LIST_FOREACH(sessions_by_seat, iter, m->seat0->sessions) { + if (iter->vtnr == active->vtnr && iter->vtfd >= 0) { + ioctl(iter->vtfd, VT_RELDISP, 1); + break; + } + } + } + + return 0; +} + static int manager_connect_console(Manager *m) { int r; @@ -750,6 +793,34 @@ static int manager_connect_console(Manager *m) { return r; } + /* + * SIGRTMIN is used as global VT-release signal, SIGRTMIN + 1 is used + * as VT-acquire signal. We ignore any acquire-events (yes, we still + * have to provide a valid signal-number for it!) and acknowledge all + * release events immediately. + */ + + if (SIGRTMIN + 1 > SIGRTMAX) { + log_error("Not enough real-time signals available: %u-%u", SIGRTMIN, SIGRTMAX); + return -EINVAL; + } + + r = ignore_signals(SIGRTMIN + 1, -1); + if (r < 0) { + log_error("Cannot ignore SIGRTMIN + 1: %s", strerror(-r)); + return r; + } + + r = sigprocmask_many(SIG_BLOCK, SIGRTMIN, -1); + if (r < 0) { + log_error("Cannot block SIGRTMIN: %s", strerror(-r)); + return r; + } + + r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m); + if (r < 0) + return r; + return 0; } @@ -806,7 +877,8 @@ static int manager_connect_udev(Manager *m) { if (m->handle_power_key != HANDLE_IGNORE || m->handle_suspend_key != HANDLE_IGNORE || m->handle_hibernate_key != HANDLE_IGNORE || - m->handle_lid_switch != HANDLE_IGNORE) { + m->handle_lid_switch != HANDLE_IGNORE || + m->handle_lid_switch_docked != HANDLE_IGNORE) { m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); if (!m->udev_button_monitor) @@ -1097,27 +1169,12 @@ int manager_run(Manager *m) { } static int manager_parse_config_file(Manager *m) { - static const char fn[] = "/etc/systemd/logind.conf"; - _cleanup_fclose_ FILE *f = NULL; - int r; - assert(m); - f = fopen(fn, "re"); - if (!f) { - if (errno == ENOENT) - return 0; - - log_warning("Failed to open configuration file %s: %m", fn); - return -errno; - } - - r = config_parse(NULL, fn, f, "Login\0", config_item_perf_lookup, - (void*) logind_gperf_lookup, false, false, m); - if (r < 0) - log_warning("Failed to parse configuration file: %s", strerror(-r)); - - return r; + return config_parse(NULL, "/etc/systemd/logind.conf", NULL, + "Login\0", + config_item_perf_lookup, logind_gperf_lookup, + false, false, true, m); } int main(int argc, char *argv[]) { @@ -1160,7 +1217,7 @@ int main(int argc, char *argv[]) { goto finish; } - log_debug("systemd-logind running as pid %lu", (unsigned long) getpid()); + log_debug("systemd-logind running as pid "PID_FMT, getpid()); sd_notify(false, "READY=1\n" @@ -1168,10 +1225,11 @@ int main(int argc, char *argv[]) { r = manager_run(m); - log_debug("systemd-logind stopped as pid %lu", (unsigned long) getpid()); + log_debug("systemd-logind stopped as pid "PID_FMT, getpid()); finish: sd_notify(false, + "STOPPING=1\n" "STATUS=Shutting down..."); if (m)