- Вопрос или проблема
- Эмуляторы терминала
- Дисциплина линии tty
- Приложение
- Ответ или решение
- Ответственности компонентов псевдотерминала (PTY): всесторонний анализ
- Введение в PTY
- Функции мастера PTY
- Роли и функции подчиненной части PTY (PTS)
- Взаимодействие с программным обеспечением терминала (например, xterm)
- Заключение
Вопрос или проблема
Я пытаюсь разобраться, как работает tty1 (рабочий процесс и ответственность каждого элемента). Я прочитал несколько интересных статей на эту тему, но все еще остаются некоторые неясности.
Вот что я понял на данный момент:
- Эмулятор терминала выполняет различные системные вызовы к
/dev/ptmx
, мастер-части псевдотерминала. - Мастер-часть псевдотерминала выделяет файл в
/dev/pts/[0-N]
, соответствующий устаревшему последовательному порту, и “подключает” к нему подчиненный псевдотерминал. - Подчиненный псевдотерминал хранит информацию, такую как идентификатор сеанса, фоновое задание, размер экрана.
Вот мои вопросы:
- Есть ли у ptmx какая-либо другая цель, кроме выделения подчиненной части? Обеспечивает ли он какую-то “интеллектуальность” или эмулированный терминал
(например, xterm) обладает всей необходимой интеллектуальностью для работы как терминал? - Почему xterm должен взаимодействовать с мастер-частью, если он только перенаправляет stdout и stdin подчиненной части? Почему он не может
напрямую писать и читать из файла pts? - Является ли идентификатор сеанса всегда привязанным к одному файлу pts и наоборот?
Могу ли я выполнитьps
и найти два идентификатора сеанса для одного
/dev/pts/X? - Какую другую информацию хранит
pts
? Обновляет ли xterm все
поля сам илиptm
добавляет ей какую-то “интеллектуальность”?
1. Я основываю свое понимание на статье TTY demystified by Linus Åkesson, посте Linux Kernel by Andries Brouwer, а также на некоторых других вопросах на этих сайтах
Эмуляторы терминала
Мастер-сторона заменяет линию (пару проводов TX/RX), которая идет к терминалу.
Терминал отображает символы, которые он получает по одному из проводов (некоторые из них являются управляющими символами и заставляют его выполнять действия, такие как перемещение курсора или изменение цвета…) и отправляет по другому проводу символы, соответствующие нажатым клавишам.
Эмуляторы терминала, такие как xterm, не отличаются, за исключением того, что вместо отправки и получения символов по проводам, они читают и записывают символы на их файловый дескриптор к мастер-стороне. После того как они создали подчиненный терминал и запустили ваш shell на нем, они больше не трогают это. Помимо эмуляции пары проводов, xterm также может изменять некоторые из свойств дисциплины линии через этот файловый дескриптор на мастер-стороне. Например, они могут обновить атрибуты размера, чтобы приложение, взаимодействующее с подчиненным pty, получило SIGWINCH-уведомление об изменении размера.
Помимо этого, в терминале/эмуляторе терминала мало интеллекта.
То, что вы пишете в файл устройства терминала (например, подчиненного pty), — это то, что вы хотите, чтобы отображалось там, то, что вы читаете оттуда, — это то, что вы ввели, поэтому не имеет смысла для эмулятора терминала читать или писать туда. Они находятся на другом конце.
Дисциплина линии tty
Много интеллекта находится в дисциплине линии tty. Дисциплина линии — это программный модуль (находящийся в драйвере, в ядре), помещенный поверх файла устройства serial/pty (например, через TIOCSETD ioctl() на Linux или через буквальную команду “push” водителя на системах, до сих пор использующих STREAMS), который находится между тем файлом устройства, с которым процессы взаимодействуют, и линией/проводом (мастер-стороной для pty).
Последовательная линия может иметь терминал на другом конце, но также мышь или другой компьютер для сети. Вы можете, например, подключить дисциплину линии SLIP, чтобы получить сетевой интерфейс поверх последовательного устройства (или устройства pty), или вы можете иметь дисциплину линии tty. Дисциплина линии tty — это дисциплина линии по умолчанию, по крайней мере, на Linux для последовательных и pty-устройств. На Linux вы можете изменить дисциплину линии с помощью ldattach
.
Вы можете увидеть эффект отключения дисциплины линии tty, выполнив stty raw -echo
(учтите, что приглашение bash или другие интерактивные приложения, такие как vi
, устанавливают терминал в режиме, который им необходим, поэтому вы захотите использовать такое простое приложение, как cat
, чтобы поэкспериментировать с этим).
Затем все, что записано в файл устройства подчиненного терминала, сразу же попадает на мастер-сторону для чтения xterm, и каждый символ, записанный xterm на мастер-сторону, сразу же доступен для чтения с устройства slave.
Дисциплина линии — это место, где реализуется внутренняя редакторская линия устройства терминала. Например, с stty icanon echo
(по умолчанию), когда вы вводите a
, xterm записывает a
на мастер, затем дисциплина линии эмулирует его обратно (делает a
доступным для чтения xterm для отображения), но ничего не делает доступным для чтения на подчиненной стороне. Затем, если вы вводите backspace, xterm отправляет символ ^?
или ^H
, дисциплина линии (поскольку этот ^?
или ^H
соответствует настройке erase
дисциплины линии) отправляет обратно на мастер ^H
, пробел
и ^H
для xterm, чтобы стереть a
, которую вы только что ввели на его экране, и по-прежнему не отправляет ничего на приложение, читающее с подчиненной стороны, оно просто обновляет свой внутренний буфер редактора строки, чтобы удалить эту a
, которую вы ввели ранее.
Затем, когда вы нажимаете Enter, xterm отправляет ^M
(CR), который дисциплина линии преобразует во входящий ^J (LF) и отправляет то, что вы ввели до сих пор, для чтения на подчиненной стороне (приложение, читающее на /dev/pts/x
, получит то, что вы ввели, включая LF, но не a
, так как вы удалили ее), в то время как на мастер-стороне это отправляет CR и LF, чтобы переместить курсор на следующую строку и в начало экрана.
Дисциплина линии также отвечает за отправку сигнала SIGINT
на передний план группы процессов терминала, когда она получает символ ^C
на мастер-стороне и т.д.
Многие интерактивные терминальные приложения отключают большинство функций этой дисциплины линии, чтобы реализовать их самостоятельно. Но в любом случае, будьте осторожны, что терминал (xterm
) имеет мало вовлеченности в это (кроме отображения того, что ему говорят отображать).
И может быть только один сеанс на процесс и на устройство терминала. Сессия может иметь подключенный терминал управления, но не обязательно. (Все сессии начинаются без терминала, пока они не откроют один.) xterm
, в процессе, который он форкает для выполнения вашей оболочки, обычно создает новую сессию (и, следовательно, отключается от терминала, с которого вы запустили xterm
, если таковой имеется), открывает новый /dev/pts/x
, который он создал, присоединяя это устройство терминала к новой сессии. Затем он выполнит вашу оболочку в этом процессе, чтобы ваша оболочка стала лидером сеанса. Ваша оболочка или любая интерактивная оболочка в этой сессии обычно будет жонглировать группами процессов и tcsetpgrp()
, чтобы установить переднюю и фоновую работы для этого терминала.
Что касается какая информация хранится устройством терминала с дисциплиной линии tty (serial или pty), это обычно то, что команда stty
показывает и изменяет. Вся конфигурация дисциплины: размер экрана терминала, локальные, входные и выходные флаги, настройки для специальных символов (например, ^C, ^Z …), скорость ввода и вывода (нерелевантно для ptys). Это соответствует функциям tcgetattr()
/tcsetattr()
, которые на Linux отображаются в TCGETS
/TCSETS
ioctl и TIOCGWINSZ
/TIOCSWINSZ
для размера экрана. Вы можете утверждать, что текущая группа процессов переднего плана — это другая информация, хранимая в устройстве терминала (tcsetpgrp()
/tcgetpgrp()
, TIOC{G,S}PGRP
ioctl), или текущий буфер ввода и вывода.
Замечу, что информация о размере экрана, хранится в устройстве терминала, может не отражать реальность. Эмулятор терминала обычно устанавливает его (через тот же ioctl на размере master), когда его окно изменяется в размере, но это может выйти из синхронизации, если приложение вызывает ioctl на стороне slave или когда изменение размера не передается (в случае ssh-соединения, которое подразумевает другой pty, созданный sshd
, если ssh
игнорирует SIGWINCH
, например). Некоторые терминалы также могут быть запрошены на их размер через последовательности escape, чтобы приложение могло запросить это таким образом и обновить дисциплину линии с этой информацией.
Для более подробной информации вы можете взглянуть на руководство termios
и tty_ioctl
на Debian, например.
Чтобы поиграть с другими дисциплинами линий:
-
Имитация мыши с помощью псевдотерминала:
socat pty,link=mouse fifo:fifo sudo inputattach -msc mouse # устанавливает дисциплину линии MOUSE и указывает протокол xinput list # смотрите новую мышь там exec 3<> fifo printf '\207\12\0' >&3 # перемещает курсор на 10 пикселей вправо
Выше, мастер-сторона pty заканчивается socat на именованный канал (
fifo
). Мы соединяем этот fifo с процессом (shell), который пишет 0x87 0x0a 0x00, что в протоколе систем мыши означаетни одна кнопка не нажата, дельта(x,y) = (10,0)
. Здесь мы (shell) не эмулируем терминал, а мышь, 3 байта, которые мы отправляем, не предназначены для чтения (возможно, преобразования) приложением с файла устройства терминала (mouse
вышеуказанное, который является символической ссылкой, сделаннойsocat
для некоторого устройства/dev/pts/x
), а для интерпретации как событие ввода мыши. -
Создание интерфейса SLIP:
# на хостA socat tcp-listen:12345,reuseaddr pty,link=interface # после подключения с хостB: sudo ldattach SLIP interface ifconfig -a # смотрите новый интерфейс там sudo ifconfig sl0 192.168.123.1/24 # на хостB socat -v -x pty,link=interface tcp:hostA:12345 sudo ldattach SLIP interface sudo ifconfig sl0 192.168.123.2/24 ping 192.168.123.1 # смотрите пакеты на выводе socat
Выше, последовательный провод эмулируется
socat
как TCP-сокет между хостомA и хостомB. Дисциплина линии SLIP интерпретирует эти байты, обмененные через эту виртуальную линию как пакеты IP, инкапсулированные в SLIP для доставки на интерфейсsl0
.
Редактировать: С тех пор как я ответил на это, я написал посвященную статью на своем блоге для тех, кто заинтересован в более подробной информации.
После долгого чтения, вот что я понял.
-
Есть ли у ptmx какая-либо другая цель, кроме выделения подчиненной части? Обеспечивает ли он какую-то “интеллектуальность” или эмулированный терминал (например, xterm) обладает всей необходимой интеллектуальностью для работы как терминал?
/dev/ptmx
не выделяет подчиненную часть: он выделяет “мастер-часть псевдотерминала”. /dev/ptmx не является мастером псевдотерминала: это мультиплексор мастер-псевдотерминала. Он был создан с стандартом Unix98 PTY для избежания условий гонки при выделении мастер-псевдотерминала (Источник).Мастер-часть (ptm) псевдотерминала не представлена в файловой системе. Она представлена файловым дескриптором.
Подчиненная часть (pts) представлена файлом в
/dev/pts/N
, гдеN
— это число.pts получается из ptm через последовательные вызовы
grandpt
,unlockpt
иptsname
(Источник).ptm заменяет драйвер AUR, посвященный взаимодействию с устройством и редактированию строки. Таким образом, он не эмулирует каким-либо образом терминал, а предоставляет функцию редактирования строки и предоставляет способ визуализации и взаимодействия с pts.
Вот график того, что было tty, подключенное к аппаратному устройству
Вот график того, что является tty, подключенного к ptm
Файл ptm обрабатывает другие аргументы Ioctl (ISPTM, UNLKPT, TIOCREMOTE, TIOCSIGNAL), чем pts.
-
Почему xterm должен взаимодействовать с мастер-частью, если он только перенаправляет stdout и stdin подчиненной части? Почему он не может напрямую писать и читать из файла pts?
Процессы взаимодействуют с устройствами через действия, выполняемые над виртуальным файлом (чтение, запись, ioctl и т.д.). Сам файл не существует, и драйвер использует файл для запуска действий при вызовах методов чтения или записи. (См. приложение для информации о драйверах)
TTY определяет точный способ взаимодействия с ним. Процессы записывают и читают данные с устройства и ожидают одинаковое поведение независимо от типа реализованного TTY.
- функция чтения используется процессами для чтения вводимых данных с терминала
- функция записи используется процессами для отправки выводной информации на терминал
pts ведет себя как драйвер TTY. Его методы чтения и записи используются для реализации поведения драйвера TTY.
Поскольку нет реального устройства для передачи данных, создается пара потоков, и ptm реализует функцию чтения для чтения данных, которые отправляет pts в поток, и функцию записи, чтобы отправить данные в поток, которые будут доступны, когда pts будет читать их.Помните, что файл, представляющий устройство, не является обычным файлом, и если
xterm
хочет увидеть, что было записано в файл, он не может просто вызватьopen
и прочитать его, поскольку эти функции в этом случае имеют совершенно другое поведение. -
Всегда ли идентификатор сессии прикреплен к одному и тому же файлу pts и наоборот? Могу ли я ввести команду ps и найти 2 идентификатора сессии для одного /dev/pts/X?
Я так не думаю, идентификатор сеанса определяется первым процессом, который подключает pts (обычно bash), и я не вижу способа создать другую сессию и подключить ее к тому же pts. Возможно, такой инструмент, как
socat
, мог бы это сделать? -
Какую другую информацию хранит pts? Обновляет ли xterm все поля сам, или ptm добавляет какую-то “интеллектуальность” в это?
pts хранит две категории информации, касающиеся терминала, с которым он общается:
Terminfo
иTermcap
.
Обычно многие терминальные эмуляторы основываются на библиотеке, которая управляет информацией termcap за них (это будет предоставлять все значения возможностей для эмуляции, например, VTX100). Примером такой библиотеки является libvte. Редактировать (см. комментарий Стефана Чазеласа): Терминальные возможности не сохраняются pts.
Приложение
- Полная книга о драйверах символов, последняя глава посвящена TTY:
Linux Device Driver 3rd edition - Подробное объяснение реализации драйвера символов: The Linux kernel, Character device
- Краткая реализация драйвера символов: Краткое руководство от журнала FreeSoftware
- Отличная статья, объясняющая терминалы: The TTY демистификация
- Ман страница ptm и pts от Oracle
Вот схема, которую я сделал некоторое время назад, о том, как работает sshd
. Она не касается работы дисциплины линии и прочего, но добавляет реалистичную иллюстрацию того, кто взаимодействует с чем:
man pts
говорит:
Файл /dev/ptmx — это символьный файл с основным номером 5 и минорным
номером 2, обычно с режимом 0666 и владельцем/группой root.root. Он используется
для создания пары псевдотерминал-мастер и подчиненного псевдотерминала.Когда процесс открывает /dev/ptmx, он получает файловый дескриптор для псевдо-
терминального мастера (PTM), и устройство псевдо-терминального
подчиненного (PTS) создается в каталоге /dev/pts. Каждый файловый дескриптор, полученный
путем открытия /dev/ptmx, является независимым PTM со своей
собственным связанным PTS, путь которого можно найти, передав дескриптор в ptsname(3).Перед открытием подчиненного псевдотерминала вы должны пройти
файловый дескриптор мастера к grantpt(3) и unlockpt(3).Как только псевдотерминальные мастер и
подчиненный открыты, подчиненный предоставляет процессам интерфейс, идентичный тому, который у
настоящего терминала.Данные, записанные в подчиненного, представлены
на мастере как
ввод. Данные, записанные в мастера, представлены на подчиненном как
ввод.На практике,
псевдотерминалы используются для
реализации эмуляторов терминалов, таких как xterm(1), в которых данные, читаемые из псевдотерминального
мастера, интерпретируются приложением таким же образом, как
реальные терминалы интерпретировали бы данные, и для реализации программ удаленного входа, таких как sshd(8), в которых данные, читаемые из псевдотерминального
мастера, отправляются через сеть клиентской программе, которая подключена
к терминалу или эмулятору терминала.Псевдотерминалы также могут использоваться для отправки
ввода программам,
которые обычно отказываются читать ввод из каналов, таким как su(8) и passwd(8)).
О /dev/pts/X индексация
:
каждый X — это сессия, которую вы открываете. Поэтому подчиненные нуждаются в индексации.
О TeteType (/dev/ttyN
):
Это реальная консоль, созданная вашей системой загрузки, например sysV
.
О том, почему slave вместо master:
http://commons.wikimedia.org/wiki/File:Termios-script-diagram.png
Ответ или решение
Ответственности компонентов псевдотерминала (PTY): всесторонний анализ
Введение в PTY
Псевдотерминалы (PTY) предоставляют интерфейс, который эмулирует работу физического терминала. Этот механизм разделен на две части: мастер и подчиненный. Мы рассмотрим роли каждой из этих частей и, используя методологию FOREST (Fact, Original, Review, Emphasize, Simplify, Tell), дадим подробное объяснение их функций, избегая шаблонных фраз и используя профессиональный подход.
Функции мастера PTY
-
Факты:
- Мастер (PTM) создается через файл
/dev/ptmx
. При открытии этого файла процесс получает дескриптор файла, который представляет мастерский псевдотерминал. - PTM действует как мост между потоком данных, поступающих от подчиненного, и приложением, которое считывает эти данные.
- Мастер (PTM) создается через файл
-
Оригинальность:
- PTM не просто ретранслятор. Он предоставляет интерфейс, идентичный реальному терминалу для взаимодействия с пользователем или эмуляции данного взаимодействия приложениями, такими как xterm.
-
Обзор:
- PTM играет ключевую роль в обеспечении того, чтобы данные, отправленные на подчиненный терминал, могли быть прочитаны с мастерской стороны, и наоборот.
-
Подчеркнуть:
- Данные, записанные в PTM, читаются подчиненной стороной как ввод. Это позволяет приложениям, таким как терминальные эмуляторы, правильно интерпретировать и отображать эту информацию.
-
Упрощение:
- PTM, по сути, является виртуальным "проводом" для передачи данных между реальными приложениями и их эмуляцией на терминалах.
-
Рассказать:
- Основная функция мастера — позволять взаимодействие с приложениями, требующими функциональности терминала, но без физического оборудования.
Роли и функции подчиненной части PTY (PTS)
-
Факты:
- Подчиненная часть (PTS) представлена файлами в
/dev/pts/N
, где N — это идентификатор терминала. - PTS действует как интерфейс API для взаимодействия с терминалом внутри системы без непосредственного физического подключения.
- Подчиненная часть (PTS) представлена файлами в
-
Оригинальность:
- PTS не только обрабатывает специфичные для терминала команды (например, управление курсором и изменением цвета), но и хранит параметры сессии, такие как идентификатор сеанса и размер экрана.
-
Обзор:
- Через PTS передается ввод с клавиатуры пользователя в мастера. Это происходит таким образом, чтобы конечный пользователь не замечал разницы между виртуальным и реальным терминалом.
-
Подчеркнуть:
- PTS фокусируется на сохранении чувствительности к пользователю, имитируя натуральное поведение терминала как на уровне ОС, так и на уровне пользователя.
-
Упрощение:
- Подчиненный терминал обеспечивает знакомый интерфейс взаимодействия с компьютерными системами.
-
Рассказать:
- PTS служит "лицевой стороной" виртуального терминала, аналогично тому, как физическая клавиатура является интерфейсом для пользователей.
Взаимодействие с программным обеспечением терминала (например, xterm)
- Программное обеспечение, такое как xterm, работает с мастером PTY для управления сеансами данных, поступающих и отправляемых пользователю.
Заключение
Псевдотерминалы играют важную роль в современной ИТ-инфраструктуре, обеспечивая необходимую платформу для взаимодействий между пользователями и системами, которые требуют терминального доступа. Понимание этих компонентов и их ролей обеспечивает более эффективное использование виртуальных терминалов и улучшает интеграцию приложений с системными интерфейсами.
Для более глубокого погружения в тему рекомендуется обратиться к таким ресурсам, как man
страницы pts
и ptmx
, а также материалы о разработке драйверов в Linux.