Отправка вывода приложения curses в tty1
Цель
Я хотел бы, чтобы мое Python-приложение curses отображало вывод на первой физической консоли машины Linux (TTY1), добавляя его в /etc/inittab
, перезагружая init с telinit q
и так далее.
Я хотел бы избежать хакерского способа использования перенаправления ввода-вывода при запуске из /etc/inittab
с:
1:2345:respawn:/path/to/app.py > /dev/tty1 < /dev/tty1
То, что я хочу, это делать это прямо из моего приложения, подобно тому, как getty
делает это, то есть вы используете аргумент командной строки, чтобы сообщить ему, какой TTY слушать:
S0:2345:respawn:/sbin/getty -L ttyS1 115200 vt100
Пример кода
Для простоты, скажем, я написал это очень сложное приложение, которое при вызове печатает некоторый контент, используя подпрограммы ncurses.
import curses
class CursesApp(object):
def __init__(self, stdscr):
self.stdscr = stdscr
# Code producing some output, accepting user input, etc.
# ...
curses.wrapper(CursesApp)
У меня уже есть код, который делает все, что мне нужно, за исключением того, что он показывает только свой вывод на терминале, с которого запускается. Когда он вызывается из inittab без хакерского перенаправления, о котором я упоминал выше, это работает, но на TTY1 ничего не выводится.
Я знаю, что init не перенаправляет ввод и вывод сам по себе, так что это ожидаемо.
Как мне нужно изменить существующий код для отправки его вывода в запрошенный TTY вместо STDOUT?
PS. Я не спрашиваю, как добавить поддержку аргументов командной строки, у меня уже есть это, но для краткости удалил ее из примера кода.
1 ответ
Это довольно просто. Просто откройте терминальное устройство один раз для ввода и один раз для вывода; затем дублируйте входной дескриптор в дескриптор файла 0 активного процесса и выходной дескриптор поверх файловых дескрипторов 1 и 2. Затем закройте остальные дескрипторы для TTY:
import os
import sys
with open('/dev/tty6', 'rb') as inf, open('/dev/tty6', 'wb') as outf:
os.dup2(inf.fileno(), 0)
os.dup2(outf.fileno(), 1)
os.dup2(outf.fileno(), 2)
Я проверил это с cmd
Модуль работает на TTY6:
import cmd
cmd.Cmd().cmdloop()
Работает отлично. С проклятиями по их внешности видно, что чего-то не хватает: TERM
переменная окружения:
os.environ['TERM'] = 'linux'
Выполните все эти операторы, прежде чем даже импортировать curses
и это должно работать.