chiark / gitweb /
mac: also rename use_{smack,selinux,apparmor}() calls so that they share the new...
[elogind.git] / src / login / logind-session.c
index 58453b516f24392a64016a657fb16754b5609e7c..65bbb77750b27ffdb1d575b02d3ce3c78c6c7ff8 100644 (file)
@@ -61,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);
@@ -1053,38 +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;
-        char *c;
 
-        if (s->controller) {
-                c = s->controller;
-                s->controller = NULL;
-                manager_drop_busname(s->manager, c);
-                free(c);
+        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);
@@ -1095,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
@@ -1115,11 +1136,14 @@ int session_set_controller(Session *s, const char *sender, bool force) {
          * or reset the VT in case it crashed/exited, too. */
         r = session_prepare_vt(s);
         if (r < 0) {
-                free(t);
+                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;
 }
@@ -1130,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] = {