[28269] in Source-Commits

home help back first fref pref prev next nref lref last post

cluster-login-config commit: Update getty.debathena for logind

daemon@ATHENA.MIT.EDU (Jonathan D Reed)
Wed Jun 18 18:15:57 2014

Date: Wed, 18 Jun 2014 18:15:51 -0400
From: Jonathan D Reed <jdreed@MIT.EDU>
Message-Id: <201406182215.s5IMFp5B032072@drugstore.mit.edu>
To: source-commits@MIT.EDU

https://github.com/mit-athena/cluster-login-config/commit/3d9b8b4ed790edb3da1c01ad8fdd0a3d01adf6a2
commit 3d9b8b4ed790edb3da1c01ad8fdd0a3d01adf6a2
Author: Jonathan Reed <jdreed@mit.edu>
Date:   Wed Jun 11 17:10:53 2014 -0400

    Update getty.debathena for logind
    
    - Add logind support to getty.debathena (Trac: #1482)
    - initialize 'sessions' in the consolekit activation so it's not
      an unbound variable in some corner cases
    - Add logging so that we actuall notice when this fails in the future
    - Add debugging support

 debian/changelog       |    7 ++
 debian/getty.debathena |  149 +++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 135 insertions(+), 21 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index ad820e8..5f61853 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+debathena-cluster-login-config (1.41) UNRELEASED; urgency=low
+
+  * Update getty.debathena to work with logind (which has replaced
+    ConsoleKit in Trusty) (Trac: #1482)
+
+ -- Jonathan Reed <jdreed@mit.edu>  Fri, 13 Jun 2014 16:16:36 -0400
+
 debathena-cluster-login-config (1.40) unstable; urgency=low
 
   * Disable Lens search results (Trac: #1423)
diff --git a/debian/getty.debathena b/debian/getty.debathena
index c946004..5263b18 100644
--- a/debian/getty.debathena
+++ b/debian/getty.debathena
@@ -12,6 +12,8 @@ user back to their session if they press any key.
 
 import curses
 import getopt
+import logging
+import logging.handlers
 import os
 import pwd
 import subprocess
@@ -19,14 +21,32 @@ import sys
 import time
 
 import dbus
+from dbus.exceptions import DBusException
 
 
+# ConsoleKit
 CK_NAME = 'org.freedesktop.ConsoleKit'
 CK_MANAGER_PATH = '/org/freedesktop/ConsoleKit/Manager'
 CK_MANAGER_IFACE = 'org.freedesktop.ConsoleKit.Manager'
 CK_SESSION_IFACE = 'org.freedesktop.ConsoleKit.Session'
+
+# logind
+LD_NAME = 'org.freedesktop.login1'
+LD_MANAGER_PATH = '/org/freedesktop/login1'
+LD_MANAGER_IFACE = 'org.freedesktop.login1.Manager'
+LD_SESSION_IFACE = 'org.freedesktop.login1.Session'
+
 KIOSK_USER = None
 
+logger = logging.getLogger('getty.debathena')
+logger.setLevel(logging.DEBUG)
+sl_handler = logging.handlers.SysLogHandler(
+    address='/dev/log',
+    facility=logging.handlers.SysLogHandler.LOG_AUTH)
+sl_handler.setLevel(logging.INFO)
+sl_handler.setFormatter(
+    logging.Formatter("%(name)s[%(process)d] %(levelname)s: %(message)s"))
+logger.addHandler(sl_handler)
 
 def find_tty(args):
     """Find the tty in a set of getty arguments.
@@ -48,8 +68,7 @@ def find_tty(args):
     else:
         return args[0]
 
-
-def activate_session():
+def activate_session_consolekit():
     """Seek out and activate what should be the current session.
 
     Using ConsoleKit, activate_session first looks to see if there is
@@ -74,6 +93,7 @@ def activate_session():
                              CK_MANAGER_IFACE)
 
     session = None
+    sessions = None
     if KIOSK_USER:
         # We'll prefer kiosk sessions if they exist
         sessions = manager.GetSessionsForUnixUser(KIOSK_USER)
@@ -93,36 +113,121 @@ def activate_session():
     if session:
         session.Activate()
     else:
-        vt = None
+        activate_session_fallback()
+
+def activate_session_logind():
+    """Use logind to activate what should be the current session.
 
-        # Look for a kiosk-mode session that we missed
+    Similar to consolekit_activate_session, except using logind.
+    """
+    global KIOSK_USER
+    if KIOSK_USER is None:
         try:
-            vt = open('/var/run/athena-kiosk-vt').read().strip()
-        except IOError, e:
-            pass
+            KIOSK_USER = pwd.getpwnam('kiosk@mit').pw_uid
+        except KeyError:
+            # There is no kiosk user
+            KIOSK_USER = False
+
+    bus = dbus.SystemBus()
+    manager = dbus.Interface(bus.get_object(LD_NAME, LD_MANAGER_PATH),
+                             LD_MANAGER_IFACE)
 
-        # Look for any X session
-        if not vt:
-            p = subprocess.Popen(['pgrep', '-x', 'Xorg'],
+    # Get all active sessions
+    sessions = manager.ListSessions()
+    target_sessions = {}
+    for s in sessions:
+        # Each session is a dbus.Struct (tuple) of:
+        # (session id, uid, username, seat id, and session object path)
+        session = dbus.Interface(bus.get_object(LD_NAME, s[-1]),
+                                 LD_SESSION_IFACE)
+        obj_properties = dbus.Interface(session,
+                                        'org.freedesktop.DBus.Properties')
+        properties = obj_properties.GetAll(LD_SESSION_IFACE)
+        if properties['Type'] == 'x11' and properties['Remote'] == 0:
+            logger.debug("Found %s on VT %s", properties['Name'],
+                         properties['VTNr'])
+            target_sessions[properties['Name']] = session
+
+    if KIOSK_USER and KIOSK_USER in target_sessions:
+        # Prefer a kiosk mode session
+        target_sessions[KIOSK_USER].Activate()
+    else:
+        if len(target_sessions) < 1:
+            activate_session_fallback()
+        else:
+            if len(target_sessions) > 1:
+                logger.error("Multiple active sessions found: %s",
+                             repr(target_sessions.keys()))
+            target_sessions.values()[0].Activate()
+
+def activate_session_fallback():
+    vt = None
+
+    # Look for a kiosk-mode session that we missed
+    try:
+        vt = open('/var/run/athena-kiosk-vt').read().strip()
+        logger.warn("Found a kiosk session in fallback mode")
+    except IOError, e:
+        pass
+
+    # Look for any X session
+    if not vt:
+        logger.warn("Falling back to pgrep")
+        p = subprocess.Popen(['pgrep', '-x', 'Xorg'],
+                             stdout=subprocess.PIPE)
+        pid, _ = p.communicate()
+        pid = pid.splitlines()[0]
+
+        if pid:
+            p = subprocess.Popen(['ps', '-otty=', pid],
                                  stdout=subprocess.PIPE)
-            pid, _ = p.communicate()
-            pid = pid.splitlines()[0]
+            tty, _ = p.communicate()
+            tty = tty.splitlines()[0]
 
-            if pid:
-                p = subprocess.Popen(['ps', '-otty=', pid],
-                                     stdout=subprocess.PIPE)
-                tty, _ = p.communicate()
-                tty = tty.splitlines()[0]
+            if tty.startswith('tty'):
+                vt = tty[len('tty'):]
 
-                if tty.startswith('tty'):
-                    vt = tty[len('tty'):]
+    if vt:
+        subprocess.call(['chvt', vt])
 
-        if vt:
-            subprocess.call(['chvt', vt])
 
+def activate_session():
+    """
+    Figure out what session manager is in use and use it to find and
+    activate the current session.
+    """
+    have_consolekit = False
+    have_logind = False
+    try:
+        logger.debug("Checking for ConsoleKit")
+        _ = dbus.SystemBus().get_object(CK_NAME, CK_MANAGER_PATH)
+        have_consolekit = True
+    except DBusException as e:
+        if e.get_dbus_name() != "org.freedesktop.DBus.Error.ServiceUnknown":
+            logger.exception(
+                "Unexpected DBus exception while checking for ConsoleKit")
+    try:
+        logger.debug("Checking for logind")
+        _ = dbus.SystemBus().get_object(LD_NAME, LD_MANAGER_PATH)
+        have_logind = True
+    except DBusException as e:
+        if e.get_dbus_name() != "org.freedesktop.DBus.Error.ServiceUnknown":
+            logger.exception(
+                "Unexpected DBus exception while checking for logind")
+    logger.debug("ConsoleKit: %s; logind: %s", have_consolekit, have_logind)
+    if have_consolekit:
+        activate_session_consolekit()
+    elif have_logind:
+        activate_session_logind()
+    else:
+        logger.warn("Neither ConsoleKit nor logind available.")
 
 def main():
     tty_name = find_tty(sys.argv[1:])
+    if os.getenv('DEBATHENA_DEBUG_GETTY', '0') == '1':
+        # Note that when debugging, executing "socat STDIO PTY" in a second
+        # xterm, and then connecting to that PTY, is incredibly helpful.
+        logger.addHandler(logging.StreamHandler())
     tty = open(os.path.join('/dev', tty_name), 'a+')
     # We want to set TERM for a tty, not for whatever TERM was set to
     # on getty's controlling terminal.
@@ -130,6 +235,8 @@ def main():
 
     CLEAR = curses.tigetstr('clear')
 
+    # Why is this in a loop when upstart will just respawn the job
+    # anyway?
     while True:
         tty.write(CLEAR)
         tty.write('Please press Enter to return to your session\n')

home help back first fref pref prev next nref lref last post