无法使用termios.TIOCSTI伪造终端输入

时间:2015-04-13 20:15:55

标签: python linux terminal

我见过的大多数code samples都试图从没有本地回声的stdin读取。为此,他们修改"local modes"标记以删除setting to "Echo input characters"。我以为我可以修改"输入模式"标记为TIOCSTI的{​​{3}}。但是,即使我以root身份运行脚本,它也没有任何效果。我写给fd的任何东西似乎都转到终端输出,而不是终端输入。基本上我想做的是"Insert the given byte in the input queue.",但是在纯python中。

"""
termfake.py

Usage: sudo python termfake.py /dev/ttys002

Get the tty device path of a different local termimal by running `tty`
in that terminal.
"""

import sys
import termios

fd = open(sys.argv[1], 'w')
fdno = fd.fileno()

# Returns [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
tatters = termios.tcgetattr(fdno)
print('original', tatters)
tatters[0] = termios.TIOCSTI
print('TIOCSTI', termios.TIOCSTI)

# Set iflag
termios.tcsetattr(fdno, termios.TCSANOW, tatters)

# Verify setting change
with open('/dev/ttys002', 'w') as fd2:
    print('modified', termios.tcgetattr(fd2.fileno()))

fd.write('This is test\n')
fd.close()

2 个答案:

答案 0 :(得分:6)

TIOCSTI是一个ioctl(记录在tty_ioctl(4)中),而非终端设置,因此您无法使用tcsetattr() - 您需要提供假的每个字符改为输入ioctl()。从来没有必要从Python做过ioctl,但以下似乎适用于在不同的终端中运行ls(指定为参数,例如 / dev / pts / 13 )正在运行Bash:

import fcntl
import sys
import termios

with open(sys.argv[1], 'w') as fd:
    for c in "ls\n":
        fcntl.ioctl(fd, termios.TIOCSTI, c)

TIOCSTI需要root权限(或CAP_SYS_ADMIN更具体,但实际上通常在实践中相同) - 请参阅capabilities(7)

答案 1 :(得分:1)

我从@Ulfalizer那里得到了答案并将其扩展为一个完整且可用的应用程序。

import sys
import fcntl
import termios
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('tty', type=argparse.FileType('w'),
                    help='full tty path as given by the tty command')
group = parser.add_mutually_exclusive_group()
group.add_argument('-n', action='store_true',
                   help='prevent sending a trailing newline character')
group.add_argument('--stdin', action='store_true',
                   help='read input from stdin')
group = parser.add_argument_group()
group.add_argument('cmd', nargs='?',
                    help='command to run (required if not using --stdin)')
group.add_argument('args', nargs='*',
                    help='arguments to command')
args = parser.parse_known_args()

if args.stdin:
    data = sys.stdin.read()
else:
    data = ' '.join([args.cmd] + args.args)

for c in data:
    fcntl.ioctl(args.tty, termios.TIOCSTI, c)
if not args.n and data[-1][-1] != '\n':
    fcntl.ioctl(args.tty, termios.TIOCSTI, '\n')

以下是您使用它的方式:

终端#1:执行...

$ tty > /tmp/t1

终端#2:执行...

$ sudo python termfake.py $(cat /tmp/t1) date +%s

终端#1:观察......

$ tty > /tmp/t1
$ date +%s
1487276400