Отправка вывода приложения 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 и это должно работать.

Другие вопросы по тегам