[24668] | 1 | #!/usr/bin/python |
---|
| 2 | """getty replacement for Debathena |
---|
| 3 | |
---|
| 4 | Debathena clusters only allow logins through X, in order to avoid a |
---|
| 5 | user logging into a tty, then switching away from that tty, and |
---|
| 6 | walking away from their session. |
---|
| 7 | |
---|
| 8 | This replacement for getty clears the screen, and offers to switch the |
---|
| 9 | user back to their session if they press any key. |
---|
| 10 | """ |
---|
| 11 | |
---|
| 12 | |
---|
| 13 | import curses |
---|
| 14 | import getopt |
---|
| 15 | import os |
---|
| 16 | import pwd |
---|
[24678] | 17 | import subprocess |
---|
[24668] | 18 | import sys |
---|
[24761] | 19 | import time |
---|
[24668] | 20 | |
---|
| 21 | import dbus |
---|
| 22 | |
---|
| 23 | |
---|
| 24 | CK_NAME = 'org.freedesktop.ConsoleKit' |
---|
| 25 | CK_MANAGER_PATH = '/org/freedesktop/ConsoleKit/Manager' |
---|
| 26 | CK_MANAGER_IFACE = 'org.freedesktop.ConsoleKit.Manager' |
---|
| 27 | CK_SESSION_IFACE = 'org.freedesktop.ConsoleKit.Session' |
---|
| 28 | KIOSK_USER = None |
---|
| 29 | |
---|
| 30 | |
---|
| 31 | def find_tty(args): |
---|
| 32 | """Find the tty in a set of getty arguments. |
---|
| 33 | |
---|
| 34 | Given the command line arguments one might pass to getty, find and |
---|
| 35 | return the argument that is the tty to use. |
---|
| 36 | |
---|
| 37 | find_tty uses the getopt option specifier and tty identifying |
---|
| 38 | logic from util-linux 2.13.1.1. |
---|
| 39 | |
---|
| 40 | Note that all other arguments will be ignored, making this getty |
---|
| 41 | useless for gettys that are not on normal ttys. |
---|
| 42 | """ |
---|
| 43 | opts, args = getopt.getopt(args, '8I:LH:f:hil:mt:wUn') |
---|
| 44 | |
---|
| 45 | # Accept both "tty baudrate" and "baudrate tty" |
---|
| 46 | if '0' <= args[0][0] <= '9': |
---|
| 47 | return args[1] |
---|
| 48 | else: |
---|
| 49 | return args[0] |
---|
| 50 | |
---|
| 51 | |
---|
| 52 | def activate_session(): |
---|
| 53 | """Seek out and activate what should be the current session. |
---|
| 54 | |
---|
| 55 | Using ConsoleKit, activate_session first looks to see if there is |
---|
| 56 | an active kiosk-mode browsing session, and if so, switches to |
---|
| 57 | that. Otherwise, it picks the first local session it can find and |
---|
| 58 | assumes that's the user's session. |
---|
| 59 | |
---|
| 60 | With the exception of the kiosk-mode session, it should be |
---|
| 61 | impossible to have more than one session running simultaneously, |
---|
| 62 | so blindly using the first session shouldn't be a problem. |
---|
| 63 | """ |
---|
| 64 | global KIOSK_USER |
---|
| 65 | if KIOSK_USER is None: |
---|
| 66 | try: |
---|
| 67 | KIOSK_USER = pwd.getpwnam('kiosk@mit').pw_uid |
---|
| 68 | except KeyError: |
---|
| 69 | # There is no kiosk user |
---|
| 70 | KIOSK_USER = False |
---|
| 71 | |
---|
| 72 | bus = dbus.SystemBus() |
---|
| 73 | manager = dbus.Interface(bus.get_object(CK_NAME, CK_MANAGER_PATH), |
---|
| 74 | CK_MANAGER_IFACE) |
---|
| 75 | |
---|
| 76 | session = None |
---|
| 77 | if KIOSK_USER: |
---|
[24761] | 78 | # We'll prefer kiosk sessions if they exist |
---|
[24668] | 79 | sessions = manager.GetSessionsForUnixUser(KIOSK_USER) |
---|
[24761] | 80 | if not sessions: |
---|
| 81 | # But if not, we'll take any graphical session that identifies |
---|
| 82 | # as local |
---|
[24668] | 83 | sessions = manager.GetSessions() |
---|
[24761] | 84 | |
---|
| 85 | for s in sessions: |
---|
| 86 | session = dbus.Interface(bus.get_object(CK_NAME, s), |
---|
| 87 | CK_SESSION_IFACE) |
---|
| 88 | if session.IsLocal() and session.GetX11Display(): |
---|
| 89 | break |
---|
[24668] | 90 | else: |
---|
| 91 | session = None |
---|
| 92 | |
---|
| 93 | if session: |
---|
| 94 | session.Activate() |
---|
[24678] | 95 | else: |
---|
[24761] | 96 | vt = None |
---|
[24668] | 97 | |
---|
[24761] | 98 | # Look for a kiosk-mode session that we missed |
---|
| 99 | try: |
---|
| 100 | vt = open('/var/run/athena-kiosk-vt').read().strip() |
---|
| 101 | except IOError, e: |
---|
| 102 | pass |
---|
[24668] | 103 | |
---|
[24761] | 104 | # Look for any X session |
---|
[24762] | 105 | if not vt: |
---|
[24761] | 106 | p = subprocess.Popen(['pgrep', '-x', 'Xorg'], |
---|
| 107 | stdout=subprocess.PIPE) |
---|
| 108 | pid, _ = p.communicate() |
---|
| 109 | pid = pid.splitlines()[0] |
---|
| 110 | |
---|
| 111 | if pid: |
---|
| 112 | p = subprocess.Popen(['ps', '-otty=', pid], |
---|
| 113 | stdout=subprocess.PIPE) |
---|
| 114 | tty, _ = p.communicate() |
---|
| 115 | tty = tty.splitlines()[0] |
---|
| 116 | |
---|
| 117 | if tty.startswith('tty'): |
---|
| 118 | vt = tty[len('tty'):] |
---|
| 119 | |
---|
| 120 | if vt: |
---|
| 121 | subprocess.call(['chvt', vt]) |
---|
| 122 | |
---|
| 123 | |
---|
[24668] | 124 | def main(): |
---|
| 125 | tty_name = find_tty(sys.argv[1:]) |
---|
| 126 | tty = open(os.path.join('/dev', tty_name), 'a+') |
---|
| 127 | # We want to set TERM for a tty, not for whatever TERM was set to |
---|
| 128 | # on getty's controlling terminal. |
---|
| 129 | curses.setupterm("linux", tty.fileno()) |
---|
| 130 | |
---|
| 131 | CLEAR = curses.tigetstr('clear') |
---|
| 132 | |
---|
| 133 | while True: |
---|
| 134 | tty.write(CLEAR) |
---|
| 135 | tty.write('Please press Enter to return to your session\n') |
---|
| 136 | tty.readline() |
---|
| 137 | |
---|
| 138 | activate_session() |
---|
| 139 | |
---|
[24761] | 140 | tty.write("If you are seeing this message, it was not possible to return you to\n") |
---|
| 141 | tty.write("your session automatically, Try pressing Ctrl-Alt-F7, Ctrl-Alt-F8 or\n") |
---|
| 142 | tty.write("Ctrl-Alt-F9. If that does not work, reboot the computer by pressing\n") |
---|
| 143 | tty.write("Ctrl-Alt-Delete.\n") |
---|
[24668] | 144 | |
---|
[24761] | 145 | time.sleep(10) |
---|
| 146 | |
---|
| 147 | |
---|
[24668] | 148 | if __name__ == '__main__': |
---|
| 149 | main() |
---|