import errno
import os
import pty
import select
import signal
import sys
import termios
STDIN = 0
STDOUT = 1
STDERR = 2
def pipe(sfd, dfd):
try:
data = os.read(sfd, 256)
except OSError as e:
if e.errno != errno.EIO:
raise
return True
if not data:
return True
if dfd == STDOUT:
filt = lambda c: c >= b' '[0] or c in b'\t\n\r\f'
data = filter(filt, data)
data = bytes(data)
while data:
try:
n = os.write(dfd, data)
except OSError as e:
if e.errno != errno.EIO:
raise
return True
data = data[n:]
if __name__ == '__main__':
argv = sys.argv[1:]
signal.signal(signal.SIGCHLD, lambda nr, _: None)
parent_fd, child_fd = pty.openpty()
assert parent_fd > STDIN
mode = termios.tcgetattr(child_fd)
mode[1] = mode[1] & ~termios.ONLCR
mode[3] = mode[3] & ~termios.ECHOCTL
termios.tcsetattr(child_fd, termios.TCSANOW, mode)
pid = os.fork()
if not pid:
os.setsid()
os.close(parent_fd)
name = os.ttyname(child_fd)
fd = os.open(name, os.O_RDWR)
os.dup2(fd, child_fd)
os.close(fd)
os.dup2(child_fd, STDIN)
os.dup2(child_fd, STDOUT)
os.dup2(child_fd, STDERR)
if child_fd > STDERR:
os.close(child_fd)
os.execve(argv[0], argv, os.environ)
raise Exception('unreachable')
os.close(child_fd)
fds = [STDIN, parent_fd]
while fds:
try:
rfds, _, _ = select.select(fds, [], [])
except select.error as e:
if e[0] != errno.EINTR:
raise
if pid == os.waitpid(pid, os.WNOHANG)[0]:
break
if STDIN in rfds:
if pipe(STDIN, parent_fd):
fds.remove(STDIN)
if parent_fd in rfds:
if pipe(parent_fd, STDOUT):
break