Files
vt1200/harness/serve.py
T

91 lines
3.1 KiB
Python

#!/usr/bin/env python3
"""Serve VT1200 font files over TFTP.
The terminal's "TFTP Font Path" is ``<host>:<filename>``; it requests that exact
filename over TFTP and (if it parses) loads it as a font. This serves several
plausible names so we catch whatever it asks for.
sudo python3 -u harness/serve.py [host] [port]
"""
import os
import sys
import time
HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(HERE)
sys.path.insert(0, os.path.join(ROOT, "tools"))
import fontgen
FONTS = os.path.join(ROOT, "reference", "fonts")
def load(name):
with open(os.path.join(FONTS, name), "rb") as fh:
return fh.read()
def main():
baseline = load("baseline.pcf")
evil = load("evil-real.pcf")
probe = load("probe-uniq.pcf")
probe_snf = load("probe.snf")
probe_dec = load("probe-dec.snf")
probe_dec2 = load("probe-dec2.snf")
real = load("system-10x20.pcf")
fonts_dir = load("fonts.dir")
files = {}
# The font path value is <host>:<fontdir>. The terminal fetches
# "<fontdir>/fonts.dir" (the directory index), then the font files it names.
for d in ("69", "font", "fonts", "misc", "X11"):
files[f"{d}/fonts.dir"] = fonts_dir
files[f"{d}/baseline.pcf"] = baseline
files[f"{d}/v1200a.pcf"] = baseline
files[f"{d}/evil.pcf"] = evil
# also serve the plain names, in case it asks for those first
for n in ("69", "fonts.dir", "font", "fonts", "ROM", "rom", "real.pcf"):
files[n] = real
files["baseline.pcf"] = baseline
files["evil.pcf"] = evil
if os.path.exists(os.path.join(FONTS, "fonts.dir")):
files["fonts.dir"] = load("fonts.dir")
host = sys.argv[1] if len(sys.argv) > 1 else "100.103.255.254"
port = int(sys.argv[2]) if len(sys.argv) > 2 else 69
def resolve(name):
# The terminal first fetches the bare path, then "<dir>/fonts.dir".
# Accept ANY name: the index for fonts.dir, the payload otherwise.
if name == "fonts.dir" or name.endswith("/fonts.dir"):
return fonts_dir
if name.endswith(".snf"):
if "dec2" in name:
return probe_dec2
return probe_dec if "dec" in name else probe_snf
if name.endswith((".pcf", ".DECW$FONT")):
if "evil" in name:
return evil
if "probe" in name:
return probe
return baseline
return baseline # bare directory name: give it data, not an error
srv = fontgen.TFTPServer((host, port), files, timeout=60.0, retries=10,
resolver=resolve).start()
print(f"serving {len(files)} names on {srv.address}", flush=True)
print(" names: " + ", ".join(sorted(files)), flush=True)
try:
while True:
time.sleep(0.5)
while srv.log:
ts, name, addr = srv.log.pop(0)
stamp = time.strftime("%H:%M:%S", time.localtime(ts))
print(f"{stamp} {addr[0]}:{addr[1]} requested {name!r}", flush=True)
except KeyboardInterrupt:
pass
finally:
srv.stop()
if __name__ == "__main__":
main()