#!/usr/bin/env python3 """console.py -- the visitor's terminal joined to the demo machine's serial console, once the machine is running (issue #112). console.py A resumed machine takes a moment to load. Anything typed meanwhile would reach a serial port whose state is about to be replaced, and be lost half-way through a line ("3 4 + ." arriving as "4 + ."). So: wait until QEMU says the machine is running, throw away what was typed before, say so, and only then pass bytes both ways. Ends when either side closes. """ import json, os, select, socket, sys, termios, time, tty qmp_path, con_path = sys.argv[1], sys.argv[2] def connect(path, limit=30): end = time.time() + limit while True: try: s = socket.socket(socket.AF_UNIX); s.connect(path); return s except OSError: if time.time() > end: raise time.sleep(0.1) qmp = connect(qmp_path).makefile("rw") qmp.readline() qmp.write(json.dumps({"execute": "qmp_capabilities"}) + "\n"); qmp.flush(); qmp.readline() end = time.time() + 60 while True: # until the machine runs qmp.write(json.dumps({"execute": "query-status"}) + "\n"); qmp.flush() while True: r = json.loads(qmp.readline()) if "return" in r or "error" in r: break # skip events if r.get("return", {}).get("status") == "running": break if time.time() > end: sys.exit("The machine did not start.") time.sleep(0.1) con = connect(con_path) stdin, stdout = sys.stdin.fileno(), sys.stdout.fileno() saved = None if os.isatty(stdin): termios.tcflush(stdin, termios.TCIFLUSH) # what was typed while the machine was loading saved = termios.tcgetattr(stdin) tty.setraw(stdin) # the machine echoes and edits the line itself os.write(stdout, b"Ready -- type a line and press Enter.\r\n") try: while True: r, _, _ = select.select([stdin, con], [], []) if stdin in r: data = os.read(stdin, 1024) if not data: break con.sendall(data) if con in r: data = con.recv(4096) if not data: break os.write(stdout, data) except OSError: pass # the visitor's terminal went away finally: if saved: termios.tcsetattr(stdin, termios.TCSADRAIN, saved)