60 lines
1.9 KiB
Python
Executable File
60 lines
1.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
"""pty_baud.py – run a shell behind two baud-rate simulators."""
|
||
import os, pty, sys, tty, termios, select, subprocess
|
||
|
||
BAUD = sys.argv[1] if len(sys.argv) > 1 else "baud"
|
||
SHELL = ["bash", "--norc"]
|
||
|
||
master, slave = pty.openpty()
|
||
shell = subprocess.Popen(SHELL, stdin=slave, stdout=slave, stderr=slave,
|
||
preexec_fn=os.setsid, close_fds=True)
|
||
os.close(slave)
|
||
|
||
baud_out = subprocess.Popen([BAUD], stdin=subprocess.PIPE,
|
||
stdout=subprocess.PIPE)
|
||
baud_in = subprocess.Popen([BAUD], stdin=subprocess.PIPE,
|
||
stdout=subprocess.PIPE)
|
||
|
||
# ── flatten every endpoint to an int fd ──────────────────────────
|
||
fd_term = sys.stdin.fileno()
|
||
fd_baud_in_stdin = baud_in.stdin.fileno()
|
||
fd_baud_in_out = baud_in.stdout.fileno()
|
||
fd_baud_out_in = baud_out.stdin.fileno()
|
||
fd_baud_out_out = baud_out.stdout.fileno()
|
||
# master is already an int from openpty()
|
||
|
||
old = termios.tcgetattr(fd_term)
|
||
tty.setraw(fd_term)
|
||
|
||
def pump(r, w):
|
||
try:
|
||
d = os.read(r, 4096) # r is already an int
|
||
except OSError:
|
||
return False
|
||
if not d:
|
||
return False
|
||
try:
|
||
os.write(w, d) # w is already an int
|
||
except OSError:
|
||
return False
|
||
return True
|
||
|
||
try:
|
||
while True:
|
||
r, _, _ = select.select(
|
||
[fd_term, master, fd_baud_in_out, fd_baud_out_out],
|
||
[], [], 0.01)
|
||
|
||
if fd_term in r: pump(fd_term, fd_baud_in_stdin)
|
||
if master in r: pump(master, fd_baud_out_in)
|
||
if fd_baud_in_out in r: pump(fd_baud_in_out, master)
|
||
if fd_baud_out_out in r: pump(fd_baud_out_out, fd_term)
|
||
except KeyboardInterrupt:
|
||
pass
|
||
finally:
|
||
termios.tcsetattr(fd_term, termios.TCSADRAIN, old)
|
||
for p in (shell, baud_in, baud_out):
|
||
try: p.terminate()
|
||
except OSError: pass
|
||
|