console: Fix handling of high-bit input and escapes
Python's standard file I/O for stdin runs it through numerous translations which
seriously breaks reading high-bit and escape characters. Stop using Python's I/O
routines and use standard syscalls for reading bytes instead.
Change-Id: Ib687388efef7a6897d742d4cd897ad78dd2970f5
diff --git a/mdt/console.py b/mdt/console.py
index 3156597..8dd074c 100644
--- a/mdt/console.py
+++ b/mdt/console.py
@@ -42,22 +42,37 @@
import termios
import tty
- localtty = None
+ from termios import ISTRIP, INLCR, IGNCR, ICRNL, IXON, IXANY, IXOFF
+ from termios import ISIG, ICANON, ECHO, ECHOE, ECHOK, ECHONL
+ from termios import OPOST, VMIN, VTIME
+ from termios import TCSADRAIN
+
+ has_tty = False
+ old_tty_attrs = None
try:
- localtty = termios.tcgetattr(self.inputfile)
+ old_tty_attrs = termios.tcgetattr(self.inputfile)
+
+ (iflag, oflag, cflag, lflag, ispeed, ospeed, cc) = old_tty_attrs
+ iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF)
+ lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL)
+ oflag &= ~OPOST;
+ cc[VMIN] = 1;
+ cc[VTIME] = 0;
+
+ newattrs = [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
+ termios.tcsetattr(self.inputfile, TCSADRAIN, newattrs)
+ has_tty = True
+
except termios.error as e:
- pass
+ has_tty = False
try:
- if localtty:
- tty.setraw(self.inputfile.fileno())
- tty.setcbreak(self.inputfile.fileno())
-
self.channel.settimeout(0)
while True:
read, write, exception = select.select([self.channel, self.inputfile], [], [])
+ # data from device to host
if self.channel in read:
try:
data = self.channel.recv(256)
@@ -71,8 +86,10 @@
except socket.timeout as e:
raise SocketTimeoutError(e)
+ # data from host to device
if self.inputfile in read:
- data = self.inputfile.read(1)
+ fd = self.inputfile.fileno()
+ data = os.read(fd, 1)
if len(data) == 0:
exit_code = None
if self.channel.exit_status_ready():
@@ -80,8 +97,9 @@
raise ConnectionClosedError(exit_code=exit_code)
self.channel.send(data)
finally:
- if localtty:
- termios.tcsetattr(self.inputfile, termios.TCSADRAIN, localtty)
+ if has_tty:
+ localtty_attrs = termios.tcgetattr(self.inputfile)
+ termios.tcsetattr(self.inputfile, TCSADRAIN, old_tty_attrs)
class WindowsConsole: