summaryrefslogtreecommitdiff
path: root/src/login/logind-session.c
AgeCommit message (Collapse)Author
2014-09-23Silence some "unchecked return-value" warningsDavid Herrmann
This adds some log-messages to ioctl() calls where we don't really care for the return value. It isn't strictly necessary to look for those, but lets be sure and print warnings. This silences gcc and coverity, and also makes sure we get reports in case something goes wrong and we didn't expect it to fail that way.
2014-09-19login: pause devices before acknowledging VT switchesDavid Herrmann
If a session controller does not need synchronous VT switches, we allow them to pass VT control to logind, which acknowledges all VT switches unconditionally. This works fine with all sessions using the dbus API, but causes out-of-sync device use if we switch to legacy sessions that are notified via VT signals. Those are processed before logind notices the session-switch via sysfs. Therefore, leaving the old session still active for a short amount of time. This, in fact, may cause the legacy session to prepare graphics devices before the old session was deactivated, and thus, maybe causing the old session to interfer with graphics device usage. Fix this by releasing devices immediately before acknowledging VT switches. This way, sessions without VT handlers are required to support async session switching (which they do in that case, anyway).
2014-09-15hashmap: introduce hash_ops to make struct Hashmap smallerMichal Schmidt
It is redundant to store 'hash' and 'compare' function pointers in struct Hashmap separately. The functions always comprise a pair. Store a single pointer to struct hash_ops instead. systemd keeps hundreds of hashmaps, so this saves a little bit of memory.
2014-09-01login: simplify controller handlingDavid Herrmann
Simplify the way we handler session-controllers and fix several shortcomings: * send ReleaseDevice() signals on forced session takeover * fix mem-leaks for busnames in case VT preparation fails (non-critical) * avoid passing pre-allocated names to helpers
2014-08-31login: fix mem leakThomas Hindoe Paaboel Andersen
2014-08-27login: fix memory-leak on DropController()David Herrmann
Our bus-name watch helpers only remove a bus-name if it's not a controller, anymore. If we call manager_drop_busname() before unregistering the controller, the busname will not be dropped. Therefore, first drop the controller, then drop the bus-name.
2014-08-19hashmap: try to use the existing 64bit hash functions for dev_t if it is 64bitLennart Poettering
2014-08-14logind: add new session type "web" for PAM web clients, such as cockpitLennart Poettering
On request of Stef Walter.
2014-08-13login: share VT-signal handler between sessionsDavid Herrmann
sd-event does not allow multiple handlers for a single signal. However, logind sets up signal handlers for each session with VT_PROCESS set (that is, it has an active controller). Therefore, registering multiple such controllers will fail. Lets make the VT-handler global, as it's mostly trivial, anyway. This way, the sessions don't have to take care of that and we can simply acknowledge all VT-switch requests as we always did.
2014-08-11login: set_controller should fail if prepare_vt failsOlivier Brunel
If controllers can expect logind to have "prepared" the VT (e.g. set it to graphics mode, etc) then TakeControl() should fail if said preparation failed (and session_restore_vt() was called). (David: fixed up !CONFIG_VT case and errno-numbers)
2014-05-22logind: also escape external data when saving to /runLennart Poettering
Better be safe than sorry...
2014-05-19logind: fix Display property of user objectsLennart Poettering
When we dropped support for creating a per-user to the "main" X11 display we stopped returning useful data in the "Display" user property. With this change this is fixed and we again expose an appropriate (graphical session) in the property that is useful as the "main" one, if one is needed.
2014-05-15Remove unnecessary casts in printfsZbigniew Jędrzejewski-Szmek
No functional change expected :)
2014-04-23login: rename session_mute_vt() to session_prepare_vt()David Herrmann
This function is no longer just about muteing the VT. We do all kinds of VT setup for sessions using the controller-API. Rename the function to something more appropriate.
2014-04-23login: give session ownership of VTRay Strode
The tty associated with a VT should be owned by the owner of the session running on the VT. This is important for supporting a socket activated X server, since the X server will open the tty itself. This commit makes sure to chown the tty any time a session is created and and chown it back to root any time the session is removed. This behavior is copied from /bin/login.
2014-04-09login: add 'mir' to the list of session typesDavid Herrmann
Add Mir to the list of session types. This is implemented for LightDM in lp:~robert-ancell/lightdm/xdg-session-desktop [1]. [1] https://code.launchpad.net/~robert-ancell/lightdm/xdg-session-desktop/+merge/214108 (david: adjusted commit-header and fixed whitespace issues)
2014-03-24sd-event: rework API to support CLOCK_REALTIME_ALARM and ↵Lennart Poettering
CLOCK_BOOTTIME_ALARM, too
2014-03-18util: replace close_nointr_nofail() by a more useful safe_close()Lennart Poettering
safe_close() automatically becomes a NOP when a negative fd is passed, and returns -1 unconditionally. This makes it easy to write lines like this: fd = safe_close(fd); Which will close an fd if it is open, and reset the fd variable correctly. By making use of this new scheme we can drop a > 200 lines of code that was required to test for non-negative fds or to reset the closed fd variable afterwards.
2014-03-07Make tables for DEFINE_STRING_TABLE_LOOKUP consistentDaniel Mack
Bring some arrays that are used for DEFINE_STRING_TABLE_LOOKUP() in the same order than the enums they reference. Also, pass the corresponding _MAX value to the array initalizer where appropriate.
2014-03-06logind: fix reference to systemd-user-sessions.serviceLennart Poettering
2014-02-21logind-session: Fix invalid free in the error caseJasper St. Pierre
utf8 needs to be initialized to NULL for the free for the early return, otherwise we try to free invalid data.
2014-02-20api: in constructor function calls, always put the returned object pointer ↵Lennart Poettering
first (or second) Previously the returned object of constructor functions where sometimes returned as last, sometimes as first and sometimes as second parameter. Let's clean this up a bit. Here are the new rules: 1. The object the new object is derived from is put first, if there is any 2. The object we are creating will be returned in the next arguments 3. This is followed by any additional arguments Rationale: For functions that operate on an object we always put that object first. Constructors should probably not be too different in this regard. Also, if the additional parameters might want to use varargs which suggests to put them last. Note that this new scheme only applies to constructor functions, not to all other functions. We do give a lot of freedom for those. Note that this commit only changes the order of the new functions we added, for old ones we accept the wrong order and leave it like that.
2014-02-19make gcc shut upLennart Poettering
If -flto is used then gcc will generate a lot more warnings than before, among them a number of use-without-initialization warnings. Most of them without are false positives, but let's make them go away, because it doesn't really matter.
2014-02-17logind: close race on session state during loginsDjalal Harouni
At login there is a small race window where session_get_state() will return SESSION_ACTIVE instead of SESSION_OPENING. This must be fixed since during that time there are calls to session_save() to save session states and we want to write the correct state. When we queue the start scope and service jobs, we wait for both of them to finish before calling and continue processing in: "session_jobs_reply() => session_send_create_reply()" to create the session fifo and notify clients. However, in the match_job_removed() D-Bus signal, we may hit situations where the scope job has successfully finished and we are still waiting for the user service job to finish. During that time the "session->scope_job" will be freed and set to NULL, this makes session_get_state() return SESSION_ACTIVE before it is really active, it should return SESSION_OPENING since we are still waiting for the service job to finish in order to create the session fifo. To fix this, we also check if the session fifo fd was created, if so then the session has entered the SESSION_ACTIVE state, if not then it is still in the SESSION_OPENING state and it is waiting for the scope and service jobs to finish.
2014-02-11logind: always kill session when termination is requestedZbigniew Jędrzejewski-Szmek
KillUserProcesses=yes/no should be ignored when termination is explicitly requested.
2014-02-07logind: order all scopes after both systemd-logind.service andLennart Poettering
systemd-user-sessions.service This way at shutdown we can be sure that the sessions go away before the network.
2014-02-07logind: rework session shutdown logicLennart Poettering
Simplify the shutdown logic a bit: - Keep the session FIFO around in the PAM module, even after the session shutdown hook has been finished. This allows logind to track precisely when the PAM handler goes away. - In the ReleaseSession() call start a timer, that will stop terminate the session when elapsed. - Never fiddle with the KillMode of scopes to configure whether user processes should be killed or not. Instead, simply leave the scope units around when we terminate a session whose processes should not be killed. - When killing is enabled, stop the session scope on FIFO EOF or after the ReleaseSession() timeout. When killing is disabled, simply tell PID 1 to abandon the scope. Because the scopes stay around and hence all processes are always member of a scope, the system shutdown logic should be more robust, as the scopes can be shutdown as part of the usual shutdown logic.
2014-02-05Update some message formatsZbigniew Jędrzejewski-Szmek
Use PID_FMT/USEC_FMT/... in more places. Also update logind error messages to print the full path to a file that failed. This should make debugging easier for people who do not know off the top of their head where logind stores it state.
2014-02-05man: introduce new "Desktop" property for sessionsLennart Poettering
This is initialized from XDG_SESSION_DESKTOP and is useful for GNOME to recognize its own sessions. It's supposed to be set to a short string identifying the session, such as "kde" or "gnome".
2014-02-05logind: add new "wayland" session typeLennart Poettering
2014-01-20logind: introduce session "positions"David Herrmann
logind has no concept of session ordering. Sessions have a unique name, some attributes about the capabilities and that's already it. There is currently no stable+total order on sessions. If we use the logind API to switch between sessions, we are faced with an unordered list of sessions we have no clue of. This used to be no problem on seats with VTs or on seats with only a single active session. However, with the introduction of multi-session capability for seats without VTs, we need to find a way to order sessions in a stable way. This patch introduces session "positions". A position is a simple integer assigned to a session which is never changed implicitly (currently, we also don't change it explicitly, but that may be changed someday). For seats with VTs, we force the position to be the same as the VTnr. Without VTs, we simply find the lowest unassigned number and use it as position. If position-assignment fails or if, for any reason, we decide to not assign a position to a session, the position is set to 0 (which is treated as invalid position). During session_load() or if two sessions have the same VTnr, we may end up with two sessions with the same position (this shouldn't happen, but lets be fail-safe in case some other part of the stack fails). This case is dealt with gracefully by ignoring any session but the first session assigned to the position. Thus, session->pos is a hint, seat->positions[i] is the definite position-assignment. Always verify both match in case you need to modify them! Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API. You can call it with any integer value != 0 and logind will try to switch to the request position. If you implement a compositor or any other session-controller, you simply watch for ctrl+alt+F1 to F12 and call SwitchTo(Fx). logind will figure a way out deal with this number. For convenience, we also introduce SwitchToNext/Previous(). It should be called on ctrl+alt+Left/Right (like the kernel-console used to support). Note that the public API (SwitchTo*()) is *not* bound to the underlying logic that is implemented now. We don't export "session-positions" on the dbus/C API! They are an implementation detail. Instead, the SwitchTo*() API is supposed to be a hint to let logind choose the session-switching logic. Any foreground session-controller is free to enumerate/order existing sessions according to their needs and call Session.Activate() manually. But the SwitchTo*() API provides a uniform behavior across session-controllers. Background: Session-switching keys depend on the active keymap. The XKB specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which have to be mapped by all keymaps to allow session-switching. It is usually bound to ctrl+alt+Fx but may be set differently. A compositor passes any keyboard input to XKB before passing it to clients. In case a key-press invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not* forwarded to clients, but instead a session-switch is scheduled. This actually prevents us from handling these keys outside of the session. If an active compositor has a keymap with a different mapping of these keys, and logind itself tries to catch these combinations, we end up with the key-press sent to the compositor's clients *and* handled by logind. This is *bad* and we must avoid this. The only situation where a background process is allowed to handle key-presses is debugging and emergency-keys. In these cases, we don't care for keymap mismatches and accept the double-event. Another exception is unmapped keys like PowerOff/Suspend (even though this one is controversial).
2014-01-15logind: get rid of X11 display socket symlinkLennart Poettering
X11 never made use of it anyway and it's probably better to just push $DISPLAY into the systemd daemon from gnome-session (or equivalent program) than to change libX11 to look for this socket. In particular since we won't need this for Wayland anyway and we shouldn't add infrastructure for stuff that's on its way out anyway.
2013-12-22shared: switch our hash table implementation over to SipHashLennart Poettering
SipHash appears to be the new gold standard for hashing smaller strings for hashtables these days, so let's make use of it.
2013-12-06Get rid of our reimplementation of basenameZbigniew Jędrzejewski-Szmek
The only problem is that libgen.h #defines basename to point to it's own broken implementation instead of the GNU one. This can be fixed by #undefining basename.
2013-11-28logind: remove unused session->closing fieldDavid Herrmann
This field is always false, drop it. If you want a reliable way to get session state, call session_get_state(). Testing for any flags directly doesn't work currently so don't pretend it would.
2013-11-28logind: require VTs on seat0 and forbid elsewhereDavid Herrmann
Sessions on seat0 must pass us a vtnr, otherwise, you shouldn't try attaching it to seat0. For seats without VTs, we do the exact opposite: we forbid VTs. There can be odd situations if the session-files contain invalid combinations. However, we try to keep sessions alive and restore state as good as possible.
2013-11-28logind: make VT numbers unsignedDavid Herrmann
Fix the whole code to use "unsigned int" for vtnr. 0 is an invalid vtnr so we don't need negative numbers at all. Note that most code already assumes it's unsigned so in case there's a negative vtnr, our code may, under special circumstances, silently break. So this patch makes sure all sources of vtnrs verify the validity. Also note that the dbus api already uses unsigned ints.
2013-11-28logind: mute/restore VT on behalf of session controllersDavid Herrmann
If a session process calls TakeControl(), we now put the VT into KD_GRAPHICS+K_OFF mode. This way, the new session controller can solely rely on the logind-dbus API to manage the session. Once the controller exits or calls ReleaseControl(), we restore the VT. We also restore it, if we lost a controller during crash/restart (but only if there really *was* a controller previously). Note that we also must put the VT into VT_PROCESS mode. We want VT_AUTO semantics, but VT_AUTO+KD_GRAPHICS actually disables *all* VT switches (who came up with that great idea?). Hence, we set VT_PROCESS for logind but acknowledge *all* requests immediately. If a compositor wants custom VT setups, they can still get this by *first* calling TakeControl() and afterwards setting up the VT. logind doesn't touch the VT during controller runtime, only during setup/teardown. This is actually what weston already does.
2013-11-28logind: restore session-controller after crashDavid Herrmann
We now save the unique bus-name of a session-controller as CONTROLLER=%s in the session files. This allows us to restore the controller after a crash or restart. Note that we test whether the name is still valid (dbus guarantees that the name is unique as long as the machine is up and running). If it is, we know that the controller still exists and can safely restore it. Our dbus-name-tracking guarantees that we're notified once it exits. Also note that session-devices are *not* restored. We have no way to know which devices where used before the crash. We could store all these on disk, too, or mark them via udev. However, this seems to be rather cumbersome. Instead, we expect controllers to listen for NewSession signals for their own session. This is sent on session_load() and they can then re-request all devices. The only race I could find is if logind crashes, then the session controller tries calling ReleaseControl() (which will fail as logind is down) but keeps the bus-connection valid for other independent requests. If logind is restarted, it will restore the old controller and thus block the session. However, this seems unlikely for several reasons: - The ReleaseControl() call must occur exactly in the timespan where logind is dead. - A process which calls ReleaseControl() usually closes the bus-connection afterwards. Especially if ReleaseControl() fails, the process should notice that something is wrong and close the bus. - A process calling ReleaseControl() usually exits afterwards. There may be any cleanup pending, but other than that, usual compositors exit. - If a session-controller calls ReleaseControl(), a session is usually considered closing. There is no known use-case where we hand-over session-control in a single session. So we don't care whether the controller is locked afterwards. So this seems negligible.
2013-11-20core: convert PID 1 to libsystemd-busLennart Poettering
This patch converts PID 1 to libsystemd-bus and thus drops the dependency on libdbus. The only remaining code using libdbus is a test case that validates our bus marshalling against libdbus' marshalling, and this dependency can be turned off. This patch also adds a couple of things to libsystem-bus, that are necessary to make the port work: - Synthesizing of "Disconnected" messages when bus connections are severed. - Support for attaching multiple vtables for the same interface on the same path. This patch also fixes the SetDefaultTarget() and GetDefaultTarget() bus calls which used an inappropriate signature. As a side effect we will now generate PropertiesChanged messages which carry property contents, rather than just invalidation information.
2013-11-05logind: port logind to libsystemd-busLennart Poettering
2013-10-14list: make our list macros a bit easier to use by not requring type spec on ↵Lennart Poettering
each invocation We can determine the list entry type via the typeof() gcc construct, and so we should to make the macros much shorter to use.
2013-09-17Remove six unused variables and add annotationZbigniew Jędrzejewski-Szmek
clang FTW!
2013-09-17logind: fix build for ARM with sizeof(dev_t) > sizeof(void*)David Herrmann
Unfortunately on ARM-32 systems dev_t can be 64bit and thus we cannot store it easily in void* keys for hashtables. Fix that by passing a pointer to the dev_t variable instead.
2013-09-17logind: implement generic multi-sessionDavid Herrmann
This enables the multi-session capability for seats that don't have VTs. For legacy seats with VTs, everything stays the same. However, all other seats now also get the multi-session capability. The only feature that was missing was session-switching. As logind can force a session-switch and signal that via the "Active" property, we only need a way to allow synchronized/delayed session switches. Compositors need to cleanup some devices before acknowledging the session switch. Therefore, we use the session-devices to give compositors a chance to block a session-switch until they cleaned everything up. If you activate a session on a seat without VTs, we send a PauseDevice signal to the active session for every active device. Only once the session acknowledged all these with a PauseDeviceComplete() call, we perform the final session switch. One important note is that delayed session-switching is meant for backwards compatibility. New compositors or other sessions should really try to deal correctly with forced session switches! They only need to handle EACCES/EPERM from syscalls and treat them as "PauseDevice" signal. Following logind patches will add a timeout to session-switches which forces the switch if the active session does not react in a timely fashion. Moreover, explicit ForceActivate() calls might also be supported. Hence, sessions must not crash if their devices get paused.
2013-09-17logind: introduce session-devicesDavid Herrmann
A session-device is a device that is bound to a seat and used by a session-controller to run the session. This currently includes DRM, fbdev and evdev devices. A session-device can be created via RequestDevice() on the dbus API of the session. You can drop it via ReleaseDevice() again. Once the session is destroyed or you drop control of the session, all session-devices are automatically destroyed. Session devices follow the session "active" state. A device can be active/running or inactive/paused. Whenever a session is not the active session, no session-device of it can be active. That is, if a session is not in foreground, all session-devices are paused. Whenever a session becomes active, all devices are resumed/activated by logind. If it fails, a device may stay paused. With every session-device you request, you also get a file-descriptor back. logind keeps a copy of this fd and uses kernel specific calls to pause/resume the file-descriptors. For example, a DRM fd is muted by logind as long as a given session is not active. Hence, the fd of the application is also muted. Once the session gets active, logind unmutes the fd and the application will get DRM access again. This, however, requires kernel support. DRM devices provide DRM-Master for synchronization, evdev devices have EVIOCREVOKE (pending on linux-input-ML). fbdev devices do not provide such synchronization methods (and never will). Note that for evdev devices, we call EVIOCREVOKE once a session gets inactive. However, this cannot be undone (the fd is still valid but mostly unusable). So we reopen a new fd once the session is activated and send it together with the ResumeDevice() signal. With this infrastructure in place, compositors can now run without CAP_SYS_ADMIN (that is, without being root). They use RequestControl() to acquire a session and listen for devices via udev_monitor. For every device they want to open, they call RequestDevice() on logind. This returns a fd which they can use now. They no longer have to open the devices themselves or call any privileged ioctls. This is all done by logind. Session-switches are still bound to VTs. Hence, compositors will get notified via the usual VT mechanisms and can cleanup their state. Once the VT switch is acknowledged as usual, logind will get notified via sysfs and pause the old-session's devices and resume the devices of the new session. To allow using this infrastructure with systems without VTs, we provide notification signals. logind sends PauseDevice("force") dbus signals to the current session controller for every device that it pauses. And it sends ResumeDevice signals for every device that it resumes. For seats with VTs this is sent _after_ the VT switch is acknowledged. Because the compositor already acknowledged that it cleaned-up all devices. However, for seats without VTs, this is used to notify the active compositor that the session is about to be deactivated. That is, logind sends PauseDevice("force") for each active device and then performs the session-switch. The session-switch changes the "Active" property of the session which can be monitored by the compositor. The new session is activated and the ResumeDevice events are sent. For seats without VTs, this is a forced session-switch. As this is not backwards-compatible (xserver actually crashes, weston drops the related devices, ..) we also provide an acknowledged session-switch. Note that this is never used for sessions with VTs. You use the acknowledged VT-switch on these seats. An acknowledged session switch sends PauseDevice("pause") instead of PauseDevice("force") to the active session. It schedules a short timeout and waits for the session to acknowledge each of them with PauseDeviceComplete(). Once all are acknowledged, or the session ran out of time, a PauseDevice("force") is sent for all remaining active devices and the session switch is performed. Note that this is only partially implemented, yet, as we don't allow multi-session without VTs, yet. A follow up commit will hook it up and implemented the acknowledgements+timeout. The implementation is quite simple. We use major/minor exclusively to identify devices on the bus. On RequestDevice() we retrieve the udev_device from the major/minor and search for an existing "Device" object. If no exists, we create it. This guarantees us that we are notified whenever the device changes seats or is removed. We create a new SessionDevice object and link it to the related Session and Device. Session->devices is a hashtable to lookup SessionDevice objects via major/minor. Device->session_devices is a linked list so we can release all linked session-devices once a device vanishes. Now we only have to hook this up in seat_set_active() so we correctly change device states during session-switches. As mentioned earlier, these are forced state-changes as VTs are currently used exclusively for multi-session implementations. Everything else are hooks to release all session-devices once the controller changes or a session is closed or removed.
2013-09-17logind: extract has_vts() from can_multi_session()David Herrmann
We currently use seat_can_multi_session() to test for two things: * whether the seat can handle session-switching * whether the seat has VTs As both are currently logically equivalent, we didn't care. However, we want to allow session-switching on seats without VTs, so split this helper into: * seat_can_multi_session(): whether session-switching is supported * seat_has_vts(): whether the seat has VTs Note that only one seat on a system can have VTs. There is only one set of them. We automatically assign them to seat0 as usual. With this patch in place, we can easily add new session-switching/tracking methods without breaking any VT code as it is now protected by has_vts(), no longer by can_multi_session().
2013-09-17logind: fix session_activate(vtnr = 0)David Herrmann
VT numbers start with 1. If a session has vtnr == 0, we must not assume it is running on a VT. Note that this could trigger the assert() below as CreateSession() sets vtnr to 0, not <0.
2013-09-17logind: rename vtconsole to seat0David Herrmann
The seat->vtconsole member always points to the default seat seat0. Even if VTs are disabled, it's used as default seat. Therefore, rename it to seat0 to correctly state what it is. This also changes the seat files in /run from IS_VTCONSOLE to IS_SEAT0. It wasn't used by any code, yet, so this seems fine. While we are at it, we also remove every "if (s->vtconsole)" as this pointer is always valid!
2013-09-17logind: make Session.Activate() lazyDavid Herrmann
Currently, Activate() calls chvt(), which does an ioctl(VT_ACTIVATE) and immediately calls seat_set_active(). However, VTs are allowed to prevent being deactivated. Therefore, logind cannot be sure the VT_ACTIVATE call was actually successful. Furthermore, compositors often need to clean up their devices before they acknowledge the VT switch. The immediate call to seat_set_active() may modify underlying ACLs, though. Thus, some compositors may fail cleaning up their stuff. Moreover, the compositor being switched to (if listening to logind instead of VTs) will not be able to activate its devices if the old VT still has them active. We could simply add an VT_WAITACTIVE call, which blocks until the given VT is active. However, this can block forever if the compositor hangs. So to fix this, we make Activate() lazy. That is, it only schedules a session-switch but does not wait for it to complete. The caller can no longer rely on it being immediate. Instead, a caller is required to wait for the PropertiesChanged signal and read the "Active" field. We could make Activate() wait asynchronously for the session-switch to complete and then send the return-message afterwards. However, this would add a lot of state-tracking with no real gain: 1) Sessions normally don't care whether Activate() was actually successful as they currently _must_ wait for the VT activation to do anything for real. 2) Error messages for failed session switches can be printed by logind instead of the session issuing Activate(). 3) Sessions that require synchronous Activate() calls can simply issue the call and then wait for "Active" properties to change. This also allows them to implement their own timeout. This change prepares for multi-session on seats without VTs. Forced VT switches are always bad as compositors cannot perform any cleanup. This isn't strictly required, but may lead to loss of information and ambiguous error messages. So for multi-session on seats without VTs, we must wait for the current session to clean-up before finalizing the session-switch. This requires Activate() to be lazy as we cannot block here. Note that we can always implement a timeout which allows us to guarantee the session switch to happen. Nevertheless, this calls for a lazy Activate().