97 lines
3.1 KiB
Python
97 lines
3.1 KiB
Python
import sys
|
||
import os
|
||
import pty
|
||
import tty
|
||
import termios
|
||
import select
|
||
import re
|
||
import getpass
|
||
import datetime
|
||
import itertools
|
||
|
||
|
||
def get_log_filename():
|
||
"""Ermittelt einen Dateinamen basierend auf Username und TTY-Nummer."""
|
||
try:
|
||
username = getpass.getuser()
|
||
except Exception:
|
||
username = "user"
|
||
|
||
try:
|
||
tty_path = os.ttyname(sys.stdout.fileno())
|
||
tty_number = os.path.basename(tty_path)
|
||
filename = f"{username}-tty{tty_number}.log"
|
||
except OSError:
|
||
for i in itertools.count():
|
||
filename = f"{username}-tty{i}.log"
|
||
if not os.path.exists(filename):
|
||
break
|
||
return filename
|
||
|
||
|
||
def sanitize_output(data: bytes) -> bytes:
|
||
"""Entfernt Steuerzeichen und -sequenzen, um die Log-Datei lesbarer zu machen."""
|
||
data = re.sub(
|
||
rb'\x1b(\[[0-?]*[ -/]*[@-~]|\][^]*(\x07|\x1b\\))', b'', data)
|
||
data = data.replace(b'\r', b'')
|
||
data = data.replace(b'\b', b'')
|
||
data = data.replace(b'\a', b'')
|
||
return data
|
||
|
||
|
||
def run_interactive_shell():
|
||
log_filename = get_log_filename()
|
||
print(f"Sitzung wird in '{log_filename}' aufgezeichnet.")
|
||
|
||
file_existed = os.path.exists(log_filename)
|
||
original_termios = termios.tcgetattr(sys.stdin.fileno())
|
||
|
||
try:
|
||
# Öffne die Datei im 'append binary'-Modus ('ab')
|
||
with open(log_filename, 'ab') as log_file:
|
||
if file_existed:
|
||
# Füge einen Trenner für die neue Sitzung hinzu
|
||
timestamp = datetime.datetime.now().isoformat()
|
||
separator = f"\n\n--- NEUE SITZUNG GESTARTET AM {
|
||
timestamp} ---\n\n".encode('utf-8')
|
||
log_file.write(separator)
|
||
|
||
pid, master_fd = pty.fork()
|
||
|
||
if pid == 0:
|
||
os.execv("/bin/zsh", ["/bin/zsh"])
|
||
else:
|
||
tty.setraw(sys.stdin.fileno())
|
||
|
||
while True:
|
||
try:
|
||
readable, _, _ = select.select(
|
||
[sys.stdin, master_fd], [], [])
|
||
|
||
if sys.stdin in readable:
|
||
user_input = os.read(sys.stdin.fileno(), 1024)
|
||
if not user_input:
|
||
break
|
||
log_file.write(sanitize_output(user_input))
|
||
os.write(master_fd, user_input)
|
||
|
||
if master_fd in readable:
|
||
shell_output = os.read(master_fd, 1024)
|
||
if not shell_output:
|
||
break
|
||
log_file.write(sanitize_output(shell_output))
|
||
os.write(sys.stdout.fileno(), shell_output)
|
||
sys.stdout.flush()
|
||
|
||
except OSError:
|
||
break
|
||
finally:
|
||
termios.tcsetattr(sys.stdin.fileno(),
|
||
termios.TCSADRAIN, original_termios)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
print("Starte PTY-Monitor. Gib 'exit' ein, um die Sitzung zu beenden.")
|
||
run_interactive_shell()
|
||
print(f"\nPTY-Monitor beendet.")
|