def copy_winsize(target_fd, source_fd=STDIN_FILENO):
"""
Propagate terminal size from `source_fd` to `target_fd`.
"""
# Create a buffer to store terminal size attributes. Refer to tty_ioctl(4)
# for more information.
winsize = array.array("h", [
0, # unsigned short ws_row
0, # unsigned short ws_col
0, # unsigned short ws_xpixel (unused)
0, # unsigned short ws_ypixel (unused)
])
# Write window size into winsize variable.
fcntl.ioctl(source_fd, termios.TIOCGWINSZ, winsize, True)
# Send winsize to target terminal.
fcntl.ioctl(target_fd, termios.TIOCSWINSZ, winsize)
python类TIOCSWINSZ的实例源码
def resize_pty(pty):
try:
winsize = struct.pack('HHHH', 0, 0, 0, 0)
winsize = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, winsize)
fcntl.ioctl(pty, termios.TIOCSWINSZ, winsize)
except IOError:
# Nice to have, but not necessary
pass
# logger =
# output = [1|0]
# chrootPath
#
# The "Not-as-complicated" version
#
def setwinsize(self, rows, cols):
'''This sets the terminal window size of the child tty. This will cause
a SIGWINCH signal to be sent to the child. This does not change the
physical window size. It changes the size reported to TTY-aware
applications like vi or curses -- applications that respond to the
SIGWINCH signal. '''
# Some very old platforms have a bug that causes the value for
# termios.TIOCSWINSZ to be truncated. There was a hack here to work
# around this, but it caused problems with newer platforms so has been
# removed. For details see https://github.com/pexpect/pexpect/issues/39
TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
# Note, assume ws_xpixel and ws_ypixel are zero.
s = struct.pack('HHHH', rows, cols, 0, 0)
fcntl.ioctl(self.fileno(), TIOCSWINSZ, s)
def setwinsize(self, rows, cols):
'''This sets the terminal window size of the child tty. This will cause
a SIGWINCH signal to be sent to the child. This does not change the
physical window size. It changes the size reported to TTY-aware
applications like vi or curses -- applications that respond to the
SIGWINCH signal. '''
# Some very old platforms have a bug that causes the value for
# termios.TIOCSWINSZ to be truncated. There was a hack here to work
# around this, but it caused problems with newer platforms so has been
# removed. For details see https://github.com/pexpect/pexpect/issues/39
TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
# Note, assume ws_xpixel and ws_ypixel are zero.
s = struct.pack('HHHH', rows, cols, 0, 0)
fcntl.ioctl(self.fileno(), TIOCSWINSZ, s)
def set_terminal_size(stdout_fileno, rows, cols):
"""
Set terminal size.
(This is also mainly for internal use. Setting the terminal size
automatically happens when the window resizes. However, sometimes the
process that created a pseudo terminal, and the process that's attached to
the output window are not the same, e.g. in case of a telnet connection, or
unix domain socket, and then we have to sync the sizes by hand.)
"""
# Buffer for the C call
# (The first parameter of 'array.array' needs to be 'str' on both Python 2
# and Python 3.)
buf = array.array(str('h'), [rows, cols, 0, 0])
# Do: TIOCSWINSZ (Set)
fcntl.ioctl(stdout_fileno, termios.TIOCSWINSZ, buf)
def setwinsize(self, rows, cols):
'''This sets the terminal window size of the child tty. This will cause
a SIGWINCH signal to be sent to the child. This does not change the
physical window size. It changes the size reported to TTY-aware
applications like vi or curses -- applications that respond to the
SIGWINCH signal. '''
# Some very old platforms have a bug that causes the value for
# termios.TIOCSWINSZ to be truncated. There was a hack here to work
# around this, but it caused problems with newer platforms so has been
# removed. For details see https://github.com/pexpect/pexpect/issues/39
TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
# Note, assume ws_xpixel and ws_ypixel are zero.
s = struct.pack('HHHH', rows, cols, 0, 0)
fcntl.ioctl(self.fileno(), TIOCSWINSZ, s)
def set_size(self, w, h, pw, ph):
s = struct.pack('HHHH', h, w, ph, pw)
log_debug("SIZE TO BE SENT", struct.unpack('HHHH', s))
self.input_queue.put((1, (termios.TIOCSWINSZ, s)))
# self.input_queue.put((2, signal.SIGWINCH))
def set_pty_size(self, p1, p2, p3, p4):
buf = array.array('h', [p1, p2, p3, p4])
#fcntl.ioctl(pty.STDOUT_FILENO, termios.TIOCSWINSZ, buf)
fcntl.ioctl(self.master, termios.TIOCSWINSZ, buf)
def resize(self, rows, cols):
if (self.rows == rows) and (self.cols == cols):
return
self.rows = rows
self.cols = cols
self.term.resize(self.rows, self.cols)
if not self.completed:
fcntl.ioctl(self.data_pipe, termios.TIOCSWINSZ, struct.pack("hhhh", self.rows, self.cols, 0, 0))
def restart(self, cmd):
if not self.completed:
self.process_input("\n\033[01;31mProcess killed.\033[00m\r\n")
os.kill(self.pid, signal.SIGHUP)
thread = self.thread
thread.stop()
while thread.alive:
QCoreApplication.processEvents()
self.exit_pipe, child_pipe = os.pipe()
pid, fd = pty.fork()
if pid == 0:
try:
os.environ["TERM"] = "xterm-256color"
retval = subprocess.call(cmd, close_fds=True)
os.write(2, "\033[01;34mProcess has completed.\033[00m\n")
os.write(child_pipe, "t")
os._exit(retval)
except:
pass
os.write(2, "\033[01;31mCommand '" + cmd[0] + "' failed to execute.\033[00m\n")
os.write(child_pipe, "f")
os._exit(1)
os.close(child_pipe)
self.process_input("\033[01;34mStarted process with PID %d.\033[00m\r\n" % pid)
self.pid = pid
self.data_pipe = fd
self.completed = False
# Initialize terminal settings
fcntl.ioctl(self.data_pipe, termios.TIOCSWINSZ, struct.pack("hhhh", self.rows, self.cols, 0, 0))
attribute = termios.tcgetattr(self.data_pipe)
termios.tcsetattr(self.data_pipe, termios.TCSAFLUSH, attribute)
self.thread = TerminalUpdateThread(self, self.data_pipe, self.exit_pipe)
self.thread.start()
def _setwinsize(fd, rows, cols):
# Some very old platforms have a bug that causes the value for
# termios.TIOCSWINSZ to be truncated. There was a hack here to work
# around this, but it caused problems with newer platforms so has been
# removed. For details see https://github.com/pexpect/pexpect/issues/39
TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
# Note, assume ws_xpixel and ws_ypixel are zero.
s = struct.pack('HHHH', rows, cols, 0, 0)
fcntl.ioctl(fd, TIOCSWINSZ, s)
def set_pty_size(self, p1, p2, p3, p4):
buf = array.array('h', [p1, p2, p3, p4])
#fcntl.ioctl(pty.STDOUT_FILENO, termios.TIOCSWINSZ, buf)
fcntl.ioctl(self.master, termios.TIOCSWINSZ, buf)
def _setwinsize(fd, rows, cols):
# Some very old platforms have a bug that causes the value for
# termios.TIOCSWINSZ to be truncated. There was a hack here to work
# around this, but it caused problems with newer platforms so has been
# removed. For details see https://github.com/pexpect/pexpect/issues/39
TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
# Note, assume ws_xpixel and ws_ypixel are zero.
s = struct.pack('HHHH', rows, cols, 0, 0)
fcntl.ioctl(fd, TIOCSWINSZ, s)
def resize(self, rows, cols, em_dimensions=None, ctrl_l=True):
"""
Resizes the child process's terminal window to *rows* and *cols* by
first sending it a TIOCSWINSZ event and then sending ctrl-l.
If *em_dimensions* are provided they will be updated along with the
rows and cols.
The sending of ctrl-l can be disabled by setting *ctrl_l* to False.
"""
logging.debug(
"Resizing term %s to rows: %s, cols: %s, em_dimensions=%s"
% (self.term_id, rows, cols, em_dimensions))
if rows < 2:
rows = 24
if cols < 2:
cols = 80
self.rows = rows
self.cols = cols
self.term.resize(rows, cols, em_dimensions)
# Sometimes the resize doesn't actually apply (for whatever reason)
# so to get around this we have to send a different value than the
# actual value we want then send our actual value. It's a bug outside
# of Gate One that I have no idea how to isolate but this has proven to
# be an effective workaround.
import fcntl, termios
s = struct.pack("HHHH", rows, cols, 0, 0)
try:
fcntl.ioctl(self.fd, termios.TIOCSWINSZ, s)
except IOError:
# Process already ended--no big deal
return
try:
os.kill(self.pid, signal.SIGWINCH) # Send the resize signal
except OSError:
return # Process is dead. Can happen when things go quickly
if ctrl_l:
self.write(u'\x0c') # ctrl-l
def _set_pty_size(self):
'''
Sets the window size of the child pty based on the window size of our own controlling terminal.
'''
assert self.master_fd is not None
# Get the terminal size of the real terminal, set it on the pseudoterminal.
buf = array.array('h', [0, 0, 0, 0])
fcntl.ioctl(pty.STDOUT_FILENO, termios.TIOCGWINSZ, buf, True)
fcntl.ioctl(self.master_fd, termios.TIOCSWINSZ, buf)
def _set_pty_size(self):
'''
Sets the window size of the child pty based on the window size of our own controlling terminal.
'''
assert self.master_fd is not None
# Get the terminal size of the real terminal, set it on the pseudoterminal.
rows, cols = self.size
buf = array.array('h', [cols, rows, 0, 0])
#fcntl.ioctl(pty.STDOUT_FILENO, termios.TIOCGWINSZ, buf, True)
fcntl.ioctl(self.master_fd, termios.TIOCSWINSZ, buf)
def setwinsize(r,c):
# Assume ws_xpixel and ws_ypixel are zero.
s = struct.pack("HHHH", r,c,0,0)
x = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCSWINSZ, s)
def set_terminal_size(lines, columns):
"""Set current terminal size
"""
winsize = struct.pack("HHHH", lines, columns, 0, 0)
fcntl.ioctl(1, termios.TIOCSWINSZ, winsize)
sys.stdout.write("\x1b[8;{lines};{columns}t".format(lines=lines, columns=columns))
def _on_wakeup(self):
"""Our main thread woke us up
"""
os.read(self.wakeup_r, 1)
if self.resize_event.is_set():
self.resize_event.clear()
data = fcntl.ioctl(STDIN, termios.TIOCGWINSZ, '0123')
lines, columns = struct.unpack('hh', data)
self.recorder.record_window_resize(lines, columns)
fcntl.ioctl(self.slave, termios.TIOCSWINSZ, data)
def _open_pty(self):
"""Create a PTY
"""
# get our terminal params
self.tcattr = termios.tcgetattr(STDIN)
winsize = fcntl.ioctl(STDIN, termios.TIOCGWINSZ, '0123')
# open a pty
self.master, self.slave = os.openpty()
# set the slave's terminal params
termios.tcsetattr(self.slave, termios.TCSANOW, self.tcattr)
fcntl.ioctl(self.slave, termios.TIOCSWINSZ, winsize)
def _setwinsize(fd, rows, cols):
# Some very old platforms have a bug that causes the value for
# termios.TIOCSWINSZ to be truncated. There was a hack here to work
# around this, but it caused problems with newer platforms so has been
# removed. For details see https://github.com/pexpect/pexpect/issues/39
TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
# Note, assume ws_xpixel and ws_ypixel are zero.
s = struct.pack('HHHH', rows, cols, 0, 0)
fcntl.ioctl(fd, TIOCSWINSZ, s)
def _setwinsize(fd, rows, cols):
# Some very old platforms have a bug that causes the value for
# termios.TIOCSWINSZ to be truncated. There was a hack here to work
# around this, but it caused problems with newer platforms so has been
# removed. For details see https://github.com/pexpect/pexpect/issues/39
TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
# Note, assume ws_xpixel and ws_ypixel are zero.
s = struct.pack('HHHH', rows, cols, 0, 0)
fcntl.ioctl(fd, TIOCSWINSZ, s)
def window_resize(self, lines, columns):
""" update window size in kernel, then send SIGWINCH to fg process """
try:
fcntl.ioctl(self.fd, termios.TIOCSWINSZ, struct.pack("HHHH", lines, columns, 0, 0))
os.kill(self.pid, signal.SIGWINCH)
except:
pass
# vim:foldmethod=marker
def _set_pty_size(self):
"""Sets the window size of the child pty based on the window size of
our own controlling terminal.
"""
assert self.master_fd is not None
# Get the terminal size of the real terminal, set it on the
# pseudoterminal.
buf = array.array('h', [0, 0, 0, 0])
fcntl.ioctl(pty.STDOUT_FILENO, termios.TIOCGWINSZ, buf, True)
fcntl.ioctl(self.master_fd, termios.TIOCSWINSZ, buf)
def set_termsize(self, width, height):
winsize = struct.pack("HHHH", height, width, 0, 0)
fcntl.ioctl(self.master, termios.TIOCSWINSZ, winsize)
def _create(self, rows=24, cols=80):
pid, fd = pty.fork()
if pid == 0:
if os.getuid() == 0:
cmd = ['/bin/login']
else:
# The prompt has to end with a newline character.
sys.stdout.write(socket.gethostname() + ' login: \n')
login = sys.stdin.readline().strip()
cmd = [
'ssh',
'-oPreferredAuthentications=keyboard-interactive,password',
'-oNoHostAuthenticationForLocalhost=yes',
'-oLogLevel=FATAL',
'-F/dev/null',
'-l', login, 'localhost',
]
env = {
'COLUMNS': str(cols),
'LINES': str(rows),
'PATH': os.environ['PATH'],
'TERM': 'linux',
}
os.execvpe(cmd[0], cmd, env)
else:
fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK)
fcntl.ioctl(fd, termios.TIOCSWINSZ,
struct.pack('HHHH', rows, cols, 0, 0))
TermSocketHandler.clients[fd] = {
'client': self,
'pid': pid,
'terminal': Terminal(rows, cols)
}
return fd
def _setwinsize(fd, rows, cols):
# Some very old platforms have a bug that causes the value for
# termios.TIOCSWINSZ to be truncated. There was a hack here to work
# around this, but it caused problems with newer platforms so has been
# removed. For details see https://github.com/pexpect/pexpect/issues/39
TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
# Note, assume ws_xpixel and ws_ypixel are zero.
s = struct.pack('HHHH', rows, cols, 0, 0)
fcntl.ioctl(fd, TIOCSWINSZ, s)
def setwinsize(r,c):
# Assume ws_xpixel and ws_ypixel are zero.
s = struct.pack("HHHH", r,c,0,0)
x = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCSWINSZ, s)
def __init__(self, cmd, raw_debug = None):
if os.name == "nt":
raise RuntimeError, "Windows does not support pseudo-terminal devices"
if cmd:
# Spawn the new process in a new PTY
self.exit_pipe, child_pipe = os.pipe()
self.exit_callback = None
pid, fd = pty.fork()
if pid == 0:
try:
os.environ["TERM"] = "xterm-256color"
if "PYTHONPATH" in os.environ:
del(os.environ["PYTHONPATH"])
if "LD_LIBRARY_PATH" in os.environ:
del(os.environ["LD_LIBRARY_PATH"])
if sys.platform == "darwin":
if "DYLD_LIBRARY_PATH" in os.environ:
del(os.environ["DYLD_LIBRARY_PATH"])
retval = subprocess.call(cmd, close_fds=True)
os.write(2, "\033[01;34mProcess has completed.\033[00m\n")
os.write(child_pipe, "t")
os._exit(retval)
except:
pass
os.write(2, "\033[01;31mCommand '" + cmd[0] + "' failed to execute.\033[00m\n")
os.write(child_pipe, "f")
os._exit(1)
os.close(child_pipe)
self.pid = pid
self.data_pipe = fd
else:
self.exit_pipe = -1
self.pid = -1
self.data_pipe = -1
self.rows = 25
self.cols = 80
self.term = TerminalEmulator(self.rows, self.cols)
self.raw_debug = raw_debug
self.completed = False
self.term.response_callback = self.send_input
if cmd:
# Initialize terminal settings
fcntl.ioctl(self.data_pipe, termios.TIOCSWINSZ, struct.pack("hhhh", self.rows, self.cols, 0, 0))
attribute = termios.tcgetattr(self.data_pipe)
termios.tcsetattr(self.data_pipe, termios.TCSAFLUSH, attribute)
else:
self.process_input("\033[01;33mEnter desired command arguments, then run again.\033[00m\r\n")
self.completed = True