--- cpython/Lib/pty.py 2020-08-15 03:54:52.282519370 -0500 +++ pty.py 2020-08-15 03:55:25.402652373 -0500 @@ -10,6 +10,9 @@ import os import sys import tty +from termios import TIOCGWINSZ, TIOCSWINSZ +from struct import pack +from fcntl import ioctl __all__ = ["openpty","fork","spawn"] @@ -67,7 +70,7 @@ result = os.open(tty_name, os.O_RDWR) try: - from fcntl import ioctl, I_PUSH + from fcntl import I_PUSH except ImportError: return result try: @@ -77,6 +80,26 @@ pass return result +def _login_tty(fd): + """Makes the calling process a session leader, makes fd its + controlling terminal, stdin, stdout, and stderr. Closes fd.""" + # Establish a new session. + os.setsid() + + # Make fd the controlling terminal. + try: + ioctl(fd, termios.TIOCSCTTY) + except: + tmp_fd = os.open(os.ttyname(fd), os.O_RDWR) + os.close(tmp_fd) + + # fd becomes stdin/stdout/stderr. + os.dup2(fd, STDIN_FILENO) + os.dup2(fd, STDOUT_FILENO) + os.dup2(fd, STDERR_FILENO) + if (fd > STDERR_FILENO): + os.close(fd) + def fork(): """fork() -> (pid, master_fd) Fork and make the child a session leader with a controlling terminal.""" @@ -97,20 +120,8 @@ master_fd, slave_fd = openpty() pid = os.fork() if pid == CHILD: - # Establish a new session. - os.setsid() os.close(master_fd) - - # Slave becomes stdin/stdout/stderr of child. - os.dup2(slave_fd, STDIN_FILENO) - os.dup2(slave_fd, STDOUT_FILENO) - os.dup2(slave_fd, STDERR_FILENO) - if (slave_fd > STDERR_FILENO): - os.close (slave_fd) - - # Explicitly open the tty to make it become a controlling tty. - tmp_fd = os.open(os.ttyname(STDOUT_FILENO), os.O_RDWR) - os.close(tmp_fd) + _login_tty(slave_fd) else: os.close(slave_fd) @@ -127,6 +138,12 @@ """Default read function.""" return os.read(fd, 1024) +def _setwinsz(slave_fd): + """Sets window size.""" + w = pack('HHHH', 0, 0, 0, 0) + s = ioctl(STDIN_FILENO, TIOCGWINSZ, w) + ioctl(slave_fd, TIOCSWINSZ, s) + def _copy(master_fd, master_read=_read, stdin_read=_read): """Parent copy loop. Copies @@ -153,10 +170,18 @@ if type(argv) == type(''): argv = (argv,) sys.audit('pty.spawn', argv) - pid, master_fd = fork() + master_fd, slave_fd = openpty() + pid = os.fork() if pid == CHILD: + os.close(master_fd) + _login_tty(slave_fd) os.execlp(argv[0], *argv) try: + _setwinsz(slave_fd) + except: + pass + os.close(slave_fd) + try: mode = tty.tcgetattr(STDIN_FILENO) tty.setraw(STDIN_FILENO) restore = 1