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 |
---|
17 | import subprocess |
---|
18 | import sys |
---|
19 | import time |
---|
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: |
---|
78 | # We'll prefer kiosk sessions if they exist |
---|
79 | sessions = manager.GetSessionsForUnixUser(KIOSK_USER) |
---|
80 | if not sessions: |
---|
81 | # But if not, we'll take any graphical session that identifies |
---|
82 | # as local |
---|
83 | sessions = manager.GetSessions() |
---|
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 |
---|
90 | else: |
---|
91 | session = None |
---|
92 | |
---|
93 | if session: |
---|
94 | session.Activate() |
---|
95 | else: |
---|
96 | vt = None |
---|
97 | |
---|
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 |
---|
103 | |
---|
104 | # Look for any X session |
---|
105 | if not vt: |
---|
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 | |
---|
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 | |
---|
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") |
---|
144 | |
---|
145 | time.sleep(10) |
---|
146 | |
---|
147 | |
---|
148 | if __name__ == '__main__': |
---|
149 | main() |
---|