X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogin%2Flogind-session.c;h=65bbb77750b27ffdb1d575b02d3ce3c78c6c7ff8;hp=5a1cb81ccfd7c13f982816e705c843101d577a36;hb=6baa7db00812437bbc87e73faa1a11b6cf631958;hpb=baccf3e40bab6c0b69992ae29c396930de4660c9 diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 5a1cb81cc..65bbb7775 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -44,21 +44,6 @@ static void session_remove_fifo(Session *s); -static unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u = *(const dev_t*)p; - - return uint64_hash_func(&u, hash_key); -} - -static int devt_compare_func(const void *_a, const void *_b) { - dev_t a, b; - - a = *(const dev_t*) _a; - b = *(const dev_t*) _b; - - return a < b ? -1 : (a > b ? 1 : 0); -} - Session* session_new(Manager *m, const char *id) { Session *s; @@ -76,7 +61,7 @@ Session* session_new(Manager *m, const char *id) { return NULL; } - s->devices = hashmap_new(devt_hash_func, devt_compare_func); + s->devices = hashmap_new(&devt_hash_ops); if (!s->devices) { free(s->state_file); free(s); @@ -153,8 +138,6 @@ void session_free(Session *s) { hashmap_remove(s->manager->sessions, s->id); - s->vt_source = sd_event_source_unref(s->vt_source); - free(s->state_file); free(s); } @@ -994,19 +977,9 @@ static int session_open_vt(Session *s) { return s->vtfd; } -static int session_vt_fn(sd_event_source *source, const struct signalfd_siginfo *si, void *data) { - Session *s = data; - - if (s->vtfd >= 0) - ioctl(s->vtfd, VT_RELDISP, 1); - - return 0; -} - int session_prepare_vt(Session *s) { int vt, r; struct vt_mode mode = { 0 }; - sigset_t mask; if (s->vtnr < 1) return 0; @@ -1036,20 +1009,12 @@ int session_prepare_vt(Session *s) { goto error; } - sigemptyset(&mask); - sigaddset(&mask, SIGUSR1); - sigprocmask(SIG_BLOCK, &mask, NULL); - - r = sd_event_add_signal(s->manager->event, &s->vt_source, SIGUSR1, session_vt_fn, s); - if (r < 0) - goto error; - /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS. * So we need a dummy handler here which just acknowledges *all* VT * switch requests. */ mode.mode = VT_PROCESS; - mode.relsig = SIGUSR1; - mode.acqsig = SIGUSR1; + mode.relsig = SIGRTMIN; + mode.acqsig = SIGRTMIN + 1; r = ioctl(vt, VT_SETMODE, &mode); if (r < 0) { r = -errno; @@ -1073,8 +1038,6 @@ void session_restore_vt(Session *s) { if (vt < 0) return; - s->vt_source = sd_event_source_unref(s->vt_source); - ioctl(vt, KDSETMODE, KD_TEXT); if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1') @@ -1090,36 +1053,61 @@ void session_restore_vt(Session *s) { s->vtfd = safe_close(s->vtfd); } +void session_leave_vt(Session *s) { + int r; + + assert(s); + + /* This is called whenever we get a VT-switch signal from the kernel. + * We acknowledge all of them unconditionally. Note that session are + * free to overwrite those handlers and we only register them for + * sessions with controllers. Legacy sessions are not affected. + * However, if we switch from a non-legacy to a legacy session, we must + * make sure to pause all device before acknowledging the switch. We + * process the real switch only after we are notified via sysfs, so the + * legacy session might have already started using the devices. If we + * don't pause the devices before the switch, we might confuse the + * session we switch to. */ + + if (s->vtfd < 0) + return; + + session_device_pause_all(s); + r = ioctl(s->vtfd, VT_RELDISP, 1); + if (r < 0) + log_debug("Cannot release VT of session %s: %m", s->id); +} + bool session_is_controller(Session *s, const char *sender) { assert(s); return streq_ptr(s->controller, sender); } -static void session_swap_controller(Session *s, char *name) { +static void session_release_controller(Session *s, bool notify) { + _cleanup_free_ char *name = NULL; SessionDevice *sd; - if (s->controller) { - manager_drop_busname(s->manager, s->controller); - free(s->controller); - s->controller = NULL; + if (!s->controller) + return; - /* Drop all devices as they're now unused. Do that after the - * controller is released to avoid sending out useles - * dbus signals. */ - while ((sd = hashmap_first(s->devices))) - session_device_free(sd); + name = s->controller; - if (!name) - session_restore_vt(s); - } + /* By resetting the controller before releasing the devices, we won't + * send notification signals. This avoids sending useless notifications + * if the controller is released on disconnects. */ + if (!notify) + s->controller = NULL; - s->controller = name; - session_save(s); + while ((sd = hashmap_first(s->devices))) + session_device_free(sd); + + s->controller = NULL; + manager_drop_busname(s->manager, name); } int session_set_controller(Session *s, const char *sender, bool force) { - char *t; + _cleanup_free_ char *name = NULL; int r; assert(s); @@ -1130,15 +1118,13 @@ int session_set_controller(Session *s, const char *sender, bool force) { if (s->controller && !force) return -EBUSY; - t = strdup(sender); - if (!t) + name = strdup(sender); + if (!name) return -ENOMEM; - r = manager_watch_busname(s->manager, sender); - if (r) { - free(t); + r = manager_watch_busname(s->manager, name); + if (r) return r; - } /* When setting a session controller, we forcibly mute the VT and set * it into graphics-mode. Applications can override that by changing @@ -1149,10 +1135,15 @@ int session_set_controller(Session *s, const char *sender, bool force) { * If logind crashes/restarts, we restore the controller during restart * or reset the VT in case it crashed/exited, too. */ r = session_prepare_vt(s); - if (r < 0) + if (r < 0) { + manager_drop_busname(s->manager, name); return r; + } - session_swap_controller(s, t); + session_release_controller(s, true); + s->controller = name; + name = NULL; + session_save(s); return 0; } @@ -1163,7 +1154,9 @@ void session_drop_controller(Session *s) { if (!s->controller) return; - session_swap_controller(s, NULL); + session_release_controller(s, false); + session_save(s); + session_restore_vt(s); } static const char* const session_state_table[_SESSION_STATE_MAX] = { @@ -1181,6 +1174,7 @@ static const char* const session_type_table[_SESSION_TYPE_MAX] = { [SESSION_X11] = "x11", [SESSION_WAYLAND] = "wayland", [SESSION_MIR] = "mir", + [SESSION_WEB] = "web", }; DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);