No se puede falsificar la entrada del terminal con termios.TIOCSTI

La mayoría de los ejemplos de código que he visto están intentando leer desde stdin sin eco local. Para hacer esto, modifican el indicador de “modos locales” para eliminar la configuración de “Caracteres de entrada de eco” . Pensé que solo podría modificar el indicador de “modos de entrada” a TIOCSTI que es para “Insertar el byte dado en la cola de entrada”. . Sin embargo, aunque ejecute el script como root, no tiene ningún efecto. cualquier cosa que escriba en el fd parece ir a la salida del terminal, en lugar de a la entrada del terminal. Básicamente, lo que quiero hacer es exactamente eso , pero en python puro.

 """ 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() 

TIOCSTI es un ioctl (documentado en tty_ioctl(4) ), no una configuración de terminal, por lo que no puede usar tcsetattr() ; en su lugar, debe ingresar cada carácter de la entrada falsa a ioctl() . Nunca tuve que hacer ioctl desde Python antes, pero lo siguiente parece funcionar para ejecutar un ls en un terminal diferente (especificado como el argumento, por ejemplo, / dev / pts / 13 ) que está ejecutando 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 requiere privilegios de root (o CAP_SYS_ADMIN para ser más específicos, pero eso es generalmente lo mismo en la práctica), por cierto, ver capabilities(7) .

Tomé la respuesta de @Ulfalizer y la amplié un poco para que fuera una aplicación completa y utilizable.

 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') 

Así es como lo usas:

Terminal # 1: hacer …

 $ tty > /tmp/t1 

Terminal # 2: hacer …

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

Terminal # 1: observar …

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