Linux change to tty

Как переключаться между TTY без использования функциональных клавиш в Linux

В этом кратком руководстве описывается, как переключаться между TTY без функциональных клавиш в Unix-подобных операционных системах.

Прежде чем идти дальше, мы посмотрим, что такое TTY.

Как упоминалось в ответе на форуме AskUbuntu, слово TTY появилось из TeleTYpewriter.

Еще в ранние дни Unix пользовательские терминалы, подключенные к компьютерам, были электромеханическими телепринтерами или телетайпами (tty вкратце).

С тех пор имя TTY продолжает использоваться для консолей с текстом. В настоящее время все текстовые консоли представляют собой виртуальные консоли, а не физические консоли. Команда TTY печатает имя файла терминала, подключенного к стандартному входу.

Переключение между TTY в Linux

По умолчанию в Linux есть 7 tty.

Они известны как tty1, tty2 … .. tty7.

От 1 до 6 tty – только командная строка.

7th tty – графический интерфейс (ваш рабочий стол X).

Вы можете переключаться между различными TTY, используя клавиши CTRL + ALT + Fn.

Например, чтобы переключиться на tty1, мы набираем CTRL + ALT + F1.

Вот как выглядит tty1 на сервере Ubuntu 18.04 LTS.

Если ваша система не имеет сеанса X, просто введите Alt + Fn. Вам не нужно использовать CTRL.

В некоторых версиях Linux (например, с Ubuntu 17.10 и далее) на экране входа в систему теперь используется виртуальная консоль 1.

Таким образом, вам нужно нажать CTRL + ALT + F3 до CTRL + ALT + F6 для доступа к виртуальным консолям.

Чтобы вернуться в среду рабочего стола, нажмите CTRL + ALT + F2 или CTRL + ALT + F7 на Ubuntu 17.10 и более поздних версиях.

До сих пор мы видели, что мы можем легко переключаться между TTY, используя CTRL + ALT + Function_Key (F1-F7).

Однако, если вы не хотите использовать клавиши функций по какой-либо причине, в Linux есть простая команда с именем chvt.

chvt описание

Команда «chvt N» позволяет вам переключиться на терминал N переднего плана, так же, как нажать CTRL + ALT + Fn.

Соответствующий экран создается, если он еще не существует.

Посмотрим, напечатаем ли система текущий tty:

Пример вывода с моего сервера Ubuntu 18.04 LTS.

Теперь перейдем к tty2. Для этого введите:

Помните, что вам нужно использовать «sudo» с командой chvt.

Теперь проверьте текущий tty с помощью команды:

Вы увидите, что tty теперь изменился.

Аналогичным образом, вы можете переключиться на tty3, используя «sudo chvt 3», tty4, используя «sudo chvt 4» и так далее.

Команда Chvt может быть полезна, когда какая-либо из ваших функциональных клавиш не работает.

Чтобы просмотреть общее количество активных виртуальных консолей, запустите:

Как вы можете видеть, в моей системе есть два активных VT.

Вы можете увидеть следующий нераспределенный виртуальный терминал, используя команду:

Виртуальная консоль не используется, если она не является консолью переднего плана, и никакой процесс не открывается для чтения или записи, и на ее экране не было выделено текста.

Чтобы избавиться от неиспользуемых VT, просто введите:

Вышеупомянутая команда освобождает память ядра и структуры данных для всех неиспользуемых виртуальных консолей.

Чтобы сказать проще, эта команда освободит все ресурсы, связанные с неиспользуемыми виртуальными консолями.

Для получения дополнительной информации см. Справочные страницы соответствующей команды.

Источник

Linux terminals, tty, pty and shell

This is the first of two articles about Linux terminals. By the end of the two articles, we should be able to:

  • describe the main components in the terminal subsystem
  • know the difference between TTY, PTY and Shell
  • answer what happens when we press a key in a Terminal (like Xterm, etc.)
  • build a simple remote terminal application using golang

Or at least I hope so 🙂

What’s a terminal?

Generally speaking a terminal is a relatively dumb electromechanical device with an input interface (like a keyboard) and an output interface (like a display or sheet of paper).

It is connected to another device (like a computer) via two logical channels, and all it does is:

  • send the keystrokes down the first line
  • read from the second line and print them on a sheet of paper

The commercial name for this type of device is teletypewriter, Teletype or TTY (remember this word as it will come up
again later). The machines would provide a user interface to early mainframe computers and minicomputers, sending typed data to the computer and printing the response.


By ArnoldReinhold — Own work , CC BY-SA 3.0, Link

To understand how a modern Terminal works we need to dwell just a bit on how teletypes used to work.
Each machine is connected via two cables: one to send instructions to the computer and one to receive output from the computer.
These cables are connected to the computer through a serial cable plugged into a Universal Asynchronous Receiver and Transmitter (UART).

The computer has an UART driver to read for the hardware device.
The sequence of characters is passed to TTY driver which applies the line discipline. The line discipline is in charge of converting special characters (like end of line, backspaces), and echoing what has been received back to the teletype, so that the user can see what it has been typed (line disciplines will be discussed in the next post of the series).
It is also responsible to buffer the characters.
When enter is pressed, the buffered data is passed to the foreground process for the session associated with the TTY. As a user, you can execute several processes in parallel, but only interact with one at a time, letting the others working (or waiting) in the background.

The whole stack as defined above is called a TTY device.
The foreground process is a computer program called Shell.

Gotcha: The words terminal and TTY device are basically interchangeable as they mean the same thing

What’s a shell?

Shells are user space applications that use the kernel API in just the same way as it is used by other application programs. A shell manages the user–system interaction by prompting users for input, interpreting their input, and then handling an output from the underlying operating system (much like a read–eval–print loop, REPL).
For example, if the input is ‘cat file | grep hello’, bash will interpret that and figure it needs to run the program cat passing ‘file’ as parameter and pipe the output to grep.

It also controls programs execution (feature called job control): kills them (CTRL + C), suspends them (CTRL + Z), sets them to run in the foreground (fg) or in the background (bg).

They can also run in non interactive mode, via script which contains a sequence of commands.

Bash, Zsh, Fish and sh are all different flavors of shells.

What’s a terminal emulator?

Let’s move to more recent times. Computers started becoming smaller and smaller, with everything packed in one single box.
For the first time the terminal was not a physical device connected via UART to the computer. The terminal became a computer program in the kernel which would send characters directly to the TTY driver, read from it and print to the screen.

That is, the kernel program would emulate the physical terminal device, thus the name terminal emulator.
Note that, although emulated they were and are still called Teletypes.

Don’t get fooled by the word emulator. A terminal emulator is as dumb as the physical terminals used to be, it listens for events coming from the keyboard and sends it down to the driver. The difference is that there is no physical device or cable which is connected to the TTY driver.

How do I see a terminal emulated TTY?

If you run a Linux OS on your machine press Ctrl+Alt+F1. You’ll get a TTY emulated by the kernel! You can get other TTYs by pressing Ctrl+Alt with the function keys from (F2 to F6). By pressing Ctrl+Alt+F7 you’ll get back to the GUI (X session).

Читайте также:  Какие возможности ядра linux использует гипервизор kvm для своей работы

Let’s recap the main concepts so far:

  • Terminal and TTY can be used interchangeably
  • Teletypes (TTY) is physical electromechanical originally designed for telegraphy, then adapted to send input and get output from mainframes
  • A Teletype can be emulated by a computer program running as a module in the kernel

What’s a pseudo terminal (PTY)?

It’s Teletype emulated by a computer program running in the user land.
Compare that with a TTY: the difference is where the program runs; it’s not a kernel program but one that runs in the user land.

I won’t (and probably couldn’t) give a complete description of kernel vs user land, I am just going to say that stuff which runs in the kernel have access to a privileged mode. That allows the kernel to access the hardware of the machine.
Programs in user land instead interact only with the kernel, not directly with the hardware.
If something goes wrong with a kernel module, all the system might be compromised, whereas if something goes wrong with a program in user land, only that program is impacted; in the worst case a reboot will bring the system back to normal.
This is definitively a good argument to move terminal emulation in user land. It is easier for developers to build one.

I guess the main reason why PTY exists is to facilitate moving the terminal emulation into user land, while still keeping the TTY subsystem (session management and line discipline) intact.

How does it work? (High level)

Terminal emulator (or any other program) can ask the kernel for a pair of characters files (called PTY master and PTY slave).
On the master side you have the terminal emulator, while on the slave side you have a Shell.
Between master and slave sits the TTY driver (line discipline, session management, etc.) which copies stuff from/to PTY master and slave.

Let’s see what happens when.

you type something in a terminal emulator in the user land like XTerm or any any other application you use to get a terminal.

Usually we say we open ‘the terminal’ or we open ‘a bash’, but what it actually happens is:

  • a GUI which emulates the terminal starts (like the Terminal or Xterm UI application).
  • it draws the UI to the video and requests a pty from the OS.
  • launches bash as subprocess
  • The std input, output and error of the bash will be set to be the pty slave.
  • XTerm listens for keyboard events and sends the characters to the pty master
  • The line discipline gets the character and buffers them. It copies them to the slave only when you press enter. It also writes back its input to the master (echoing back). Remember the terminal is dumb, it will only show stuff on the screen if it comes from the pty master. Thus, the line discipline echoes back the character so that the terminal can draw it on the video, allowing you to see what you just typed.
  • When you press enter, the TTY driver (it’s ‘just’ a kernel module) takes care of copying the buffered data to the pty slave
  • bash (which was waiting for input on standard input) finally reads the characters (for example ‘ls -la’). Again, remember that bash standard input is set to be the PTY slave.
  • At this points bash interprets the character and figures it needs to run ‘ls’
  • It forks the process and runs ‘ls’ in it. The forked process will have the same stdin, stdout and stderr used by bash, which is the PTY slave.
  • ls runs and prints to standard output (once again, this is the pty slave)
  • the tty driver copies the characters to the master(no, the line discipline does not intervene on the way back)
  • XTerm reads in a loop the bytes from the pty master and redraws the UI

I think we made it! That’s roughly what happens when we run a command in a terminal emulator. The drawing should help consolidate the workflow:

As an experiment, run the ‘ps’ command in new instance of a terminal.
If you did not run any process yet, you will see that the only two programs associated with the terminal are ‘ps’ and ‘bash’.
‘ps’ is the program we just started and ‘bash’ was started by the terminal. ‘pts/0’ which you see in the results is the PTY slave we talked about.

Exit fullscreen mode

Let’s what happens when.

you start a program that reads from the standard input from a terminal emulator. The program can be as simple as reading from standard input and writing it to the standard output, like the following.

Источник

Виртуальные твари и места их обитания: прошлое и настоящее TTY в Linux

Ubuntu интегрирована в Windows 10 Redstone, Visual Studio 2017 обзавелась поддержкой разработки под Linux – даже Microsoft сдает позиции в пользу растущего числа сторонников Торвальдса, а ты всё еще не знаешь тайны виртуального терминала в современных дистрибутивах?

Хочешь исправить этот пробел и открываешь исходный код? TTY, MASTER, SLAVE, N_TTY, VT, PTS, PTMX… Нагромождение понятий, виртуальных устройств и беспорядочная магия? Всё это складывается в довольно логичную картину, если вспомнить, с чего всё началось…

1. START FROM SCRATCH & KEEP CALM

TTY: ПАЛЕОЗОЙ

Мы шагнули прямиком в тридцатые годы XX века и оказались в совсем еще молодой Teletype Corporation. Прямо перед нами перед нами Тот-С-Которого-Всё-Началось – телетайп, представляющий из себя «буквопечатающий телеграф», который передает текстовые сообщения между двумя абонентами.

Абонент А набирает на клавиатуре символы, которые преобразуются в электрические сигналы. По самому обычному кабелю сигналы «бегут» на телетайп абонента Б и уже там печатаются на самой обычной бумаге. Если сигнал дуплексный, то нам крупно повезло, и абонент Б может сразу написать свой ответ; если нет – то ему потребуется сначала подсоединить второй провод для обратной связи.


Здесь, на Teletype Corporation, еще не знают, какое будущее в скором времени ждет их продукт, и уж конечно не подозревают, что аббревиатура TTY намного переживет сам телетайп. Не будем портить для них интригу, пойдем дальше.

TTY: МЕЗОЗОЙ

Прошло сорок лет, мы в лаборатории Digital Equipment Corporation, любуемся первым мини-компьютером (интерактивным!) PDP-1. Для ввода и вывода информации, а также для обеспечения взаимодействия с пользователем к нему подключен уже знакомый нам телетайп.

Дело в том, что ведущие инженерные умы решили велосипед не изобретать и приспособить уже имеющийся дешевый и доступный механизм под новые нужды. Телетайп напрямую подключили к компьютеру (а не к другому телетайпу, как это было раньше) и назвали это дело консолью. Оператор, осуществляющий ввод, видит, как набираемые символы мгновенно печатаются на бумаге, но происходит это без участия ОС – благодаря сохранению в консоли принципа печатающей машинки.

TTY: ПАЛЕОГЕН

Оказываемся в самом начале 80-ых годов, на этот раз в Bell Laboratories. Здесь только что выпущен один из важнейших релизов «раннего» UNIX – Version 7 для PDP-11. Особенности у этого релиза следующие: вводимая пользователем команда теперь отображается по принципу ECHO (набранный на клавиатуре символ сначала попадает в буфер накопления и только потом ОС отправляет инструкцию вывести этот символ на печать), поддерживаются простые возможности редактирования вводимых команд (можно «стирать» символ или целую строку, перемещать каретку), появляется разделение режимов:

  • raw mode (редактирование строки не производится; управляющие последовательности распознаются как обычные символы; введенный символ немедленно передается процессу);
  • cooked mode (происходит распознавание специальных символов и генерирование сигналов остановки и прерывания для процесса; передача готовой строки процессу осуществляется только после нажатия клавиши Return).

Вполне ожидаемый вопрос: как же можно «стереть» то, что уже напечатал телетайп? Для наглядного выполнения операций редактирования Unix Version 7 предусмотрена печать определенных символов: например, @ — стереть всю строку, # — стереть последний символ. То есть, если наш телетайп напечатал ld@lk#s, и оператор нажал Return, то на исполнение пошла команда ls. Это еще не TTY LINE DISCIPLINE (о ней речь пойдет дальше), но уже большой шаг вперед в отношении обработки ввода на уровне ОС.

Кстати говоря, Digital Equipment Corporation за эти 20 лет не только разработала упомянутый PDP-11, но и подумала о том, как усовершенствовать телетайп: появились так называемые умные терминалы.

Смотрим направо: это VT100, один из первых терминалов, умеющих работать в любви и согласии с PDP-11 и поддерживаемый Unix Version 7.

Читайте также:  Ifunbox не видит iphone windows 10

На уровне ОС и консоль, и умный терминал сейчас воспринимаются как символьные устройства, которые подключаются через интерфейс UART, преобразовывающий асинхронный поток данных в последовательность символов. Для ОС они в принципе идентичны, разница лишь в том, стирать ли символы на экране терминала или печатать символ забоя с помощью телетайпа.


Слева показана в общих чертах схема взаимодействия компьютера и консоли (или умного терминала). У этой схемы есть один недостаток, который совсем не радует оператора консоли PDP-11: с одной консолью ассоциируется одна сессия (или сеанс), в котором пользователь может в фоновом режиме запустить несколько процессов, однако активным в один момент времени на одном TTY будет только один.

И наш бедный оператор вынужден в прямом смысле этого слова переходить от одной консоли к другой, если вдруг ему придет в голову поработать с несколькими сессиями.

TTY: НЕОГЕН

Мы очутились в редакции журнала «PC MAGAZINE», рассматриваем свежий выпуск от 13 января 1987 года. Один из разворотов активно убеждает нас не жалеть денег на ПК с UNIX System V. Каковы аргументы? В частности – grep, awk, sort, split, cut, paste, vi, ed – word processing явно шагнул вперед. И самое интересное: к нашим услугам сейчас эмуляторы терминалов! Благодаря виртуальным консолям, уже можно запустить целых четыре сессии без нужды подключать всё новые и новые физические телетайпы.

Кроме того, жизнь монохромных терминалов нынче можно расцветить: поддерживается CGA, Hercules, EGA графика. Бедолага-оператор может вздохнуть спокойно, телетайп (а также умный терминал) в виде железного зверя угрожает ему только в ночных кошмарах.

Посоветуем оператору лишь одно: ни за что не лезть в директорию /dev – ведь его ждут там аж несколько ttyX и напоминают о том, что под капотом виртуальной консоли живет всё тот же старый-добрый телетайп.

TTY: АНТРОПОГЕН

На предыдущем шаге мы убедились: консоль сделали виртуальной (не будет же солидное издание «PC MAGAZINE» лгать). Что это значит – весь механизм ввода/вывода переписан и в корне изменен? Тогда почему виртуальное устройство – всё еще ttyX? Всё просто: виртуальная консоль эмулируется как самая что ни на есть физическая, а место UART-драйвера, вероятно, занимает кто-то другой. Изменившуюся схему подробно обсудим чуть дальше.

До финишной прямой один шаг, но пропустить его мы не можем хотя бы из уважения к Линусу Торвальдсу. Сейчас 1993 год, и мы наконец имеем счастье рассматривать исходный код Linux 0.95. Почему именно этот релиз? Именно в нем уже сформировалась TTY-абстракция, наиболее близкая к тому, что мы имеем в самых последних дистрибутивах: оформились три обособленных слоя (TTYX — TTY_LINE_DISCIPLINE — TTY_DRIVER).

Кроме того, спустя всего год будет выпущен Linux 1.0, где появится оконный интерфейс, предоставленный проектом XFree86. С этого момента к виртуальным консолям добавятся в придачу еще виртуальные терминалы, которые пользователь (в почти не ограниченном количестве) сможет запускать, не покидая графическую оболочку… Однако прежде, чем окунуться в тонкости и детали усовершенствованной io-магии, вернемся в наше настоящее к Ubuntu 16.04.

2. STOP BEAT AROUND THE BUSH & LOOK INSIDE

ВИРТУАЛЬНЫЕ ТВАРИ И МЕСТА ИХ ОБИТАНИЯ

Лишь некоторые устройства директории /dev/ используются повседневно: /dev/sdaX, /dev/mem, /dev/zero, /dev/random… Но есть несколько групп устройств, которые не часто привлекают наше внимание, однако более чем его заслуживают. Это устройства /ttyX, /vcsX, /vcsaX, а также /ptmx и /pts/X. Собственно говоря, о них и пойдет речь дальше.

И первый наш объект – виртуальная консоль. Каждому такому объекту присущи как минимум сакральное число идентификатор и тотемное животное файл виртуального устройства /tty, коих в виртуальном лесу директории /dev встречают аж 64.

Проверим, есть ли у нас возможность пообщаться с ними. Выполняем Ctrl-Alt-FX (или chvt X, где X – номер консоли, например, Ctrl-Alt-F1) и замечаем, что X может быть равно 1, 2 … 6. При этом перед нами открывается виртуальная консоль, при первом запуске нам предлагают ввести имя пользователя и пароль и создают для нас новый сеанс работы. Если X равен 7, то мы возвращаемся в родные графические пенаты и понимаем, что /tty7 связан с XServer’ом. Идем дальше. Восемь, девять, десять и так далее до 63 — признаков жизни не подают.

Дело в том, что в Linux есть макрос MAX_NR_CONSOLES (64), определяющий максимально допустимое число виртуальных консолей, которые и представлены 64-мя файлами виртуальных устройств /dev/ttyX. Однако последнее слово остается за параметром ACTIVE_CONSOLES (/etc/default/console-setup), и параметр этот по умолчанию равен шести.

Инициализация консолей происходит в несколько стадий. Сперва ядро, получив управление от Grub’a, в ходе инициализации подсистем вызывает функцию «console_init», которая создает первичную консоль – «boot console», предназначенную для вывода отладочной информации. Это консоль осуществляет вывод символов самым примитивным образом: через «putchar», которая напрямую обращается к BIOS, инициализируя и заполняя структуру biosregs, и осуществляет вывод символа в консоль, используя прерывание 0x10.

Позже, в ходе выполнения «fs-initcall» и «console-initcall» происходит создание виртуальных устройств и структур под 6 полноценных виртуальных консолей – «real console». Активацию этих консолей выполняет первый запущенный ядром процесс /sbin/init, запускающий программу getty, которая выполняет чтение конфигурационных файлов /etc/init/console.conf и /etc/init/ttyX.conf и впоследствии отображает на консоль содержимое файла-приветствия etc/issue и запускает login. Далее XServer инициирует активацию консоли на dev/tty7, на которой запускается графическая оболочка.

Однако у нас есть еще вопросы. Что за неведомый объект /dev/tty0? И если каждый /dev/ttyX — это виртуальное устройство консоли, то зачем нужны /dev/console и /dev/tty? За ответом переходим на tty1 (нажимая Ctrl-Alt-F1) и в фоновом режиме запускаем такой скрипт:

Затем переходим на, скажем, tty4 и ждем несколько секунд. По истечении видим следующую картину:

Распределение ролей становится понятно: /dev/tty0 = /dev/console = текущая консоль, т.е. оба всегда ассоциированы с той консолью, которую мы в данный момент видим перед собой, а /dev/tty «помнит» консоль, с которой стартовал процесс. Поэтому пока наш процесс выполнялся, /dev/tty0 и /dev/console определялись для него по ходу пьесы в зависимости от текущей активной консоли, а вот /dev/tty оставался неизменным.

Не спешим покидать директорию /dev. Здесь еще чуть больше дюжины любопытных объектов: /dev/vcsX (virtual console screen) и /dev/vcsaX (virtual console screen with attributes). Еще один опыт: перемещаемся на tty5 и оставляем какие-нибудь следы своего пребывания, затем переходим в любую другую консоль (пусть ее номер 3), делаем «cat» на /dev/vcs5 и видим именно то состояние консоли 5, в каком мы оставили ее несколько секунд назад. При этом, соответственно, /dev/vcs3 и /dev/vcs (а также /dev/vcsa) относятся к консоли 3, на которой мы находимся в данный момент.

Понимаем, что /dev/vcsX — не что иное как омут памяти устройство виртуальной памяти консоли, позволяющее нам без потерь перемещаться между экземплярами tty. В паре с ним — /dev/vcsaX, который предоставляет базовые сведения о состоянии экрана: цвета, различные атрибуты (напр. мерцание), текущее положение курсора, конфигурацию экрана (количество строк и столбцов). Подытожим увиденное схемой:

ВИД СВЕРХУ ЛУЧШЕ

Теперь остановимся с изучением зоологии tty на какое-то время и перейдем к самой tty-абстракции, частью которой и являются наши виртуальные устройства. Посмотрим на общую структуру tty-комплекса и выделим три компонента:

  1. /dev/ttyX – виртуальное устройство консоли в файловой системе, которое заняло место UART-драйвера и с которым мы уже знакомы. На этом же уровне располагаются устройства /dev/vcsX и /dev/vcsaX, общение с ними осуществляется непосредственно через /dev/ttyX.
  2. TTY Line Discipline — драйвер, который делает ECHO набираемой команды и дает нам возможности ее редактирования. Также драйвер этого слоя генерирует сигналы при наборе управляющих последовательностей (^C, ^Z и т.д.). По умолчанию здесь царствует N_TTY, однако этот модуль можно заменить, например, своим драйвером – с этим поэкспериментируем немного позже;
  3. TTY driver – драйвер, который предоставляет набор методов инициализации и открытия консоли, а также методы, обрабатывающие операции ввода/вывода, приостановку консоли при переключении и возобновление ее работы и, конечно, обеспечивает «передачу» полученной от пользователя команды активному процессу.

Помните жалобы оператора PDP-11? Ему не нравилось тратить время на переходы от одной физической консоли к другой. Сейчас дело обстоит следующим образом: у нас есть по умолчанию 7 виртуальных консолей, а перед ними — офисное кресло на колесиках (разумеется, тоже виртуальное). Когда мы переключаемся с одной консоли на другую, операционная система перемещает наше кресло к нужному tty, а вместе с креслом «переключаются» на него и комплекс физических io-устройств: на мониторе теперь состояние нашей новой консоли, на нее же поступает ввод с клавиатуры и т.п.

При этом процессы от первого tty продолжают работать: считывают команды с файла своей виртуальной консоли, пишут в этой файл, но – так как они оторваны от «кресла» – не получают никаких событий (те же ^C и ^Z) и – так как физические устройства «уехали» вместе с «креслом» – могут только накапливать свой «вывод» в буфере, чтоб отправить его на монитор, как только «кресло» вернется.

Читайте также:  Via windows wireless utility

ПУТЕШЕСТВИЕ К ЦЕНТРУ ЗЕМЛИ

Да, сверху всё смотрится вполне презентабельно. Но тебе, %username%, вероятно, хочется увидеть, как трехуровневое взаимодействие tty-компонентов реализовано непосредственно в коде? За ответом придется опуститься с небес на землю, даже лучше сказать – под землю, в недра исходного кода Ubuntu (работать будем с ядром версии 4.4).

Сделаем упреждающий ход – разберемся, через какие структуры происходит связывание tty-абстракции в единое целое.

Во-первых, это «tty_struct», у которой есть поле «tty_ldisc» (это структура методов драйвера 2-ого слоя), поле «tty_driver» (это драйвер 3-ого слоя) и тут же «tty_operations» (это структура методов драйвера 3-ого слоя, ради удобства вынесенная прямо в «tty_struct»).

То есть, «tty_struct» обеспечивает доступ к слоям TTY_LINE_DISCIPLINE и TTY_DRIVER. Получили к ней доступ – 2/3 стека tty-абстракции, считай, перед нами. Теперь нам нужно понять, как осуществляется переход от файлов виртуальных устройств к этой самой структуре. Ответ прост: у структуры «tty_file_private» как раз есть поле типа «tty_struct». Следовательно, обращаясь к файлу виртуального устройства на 1-ом уровне, мы с легкостью получаем доступ к уровням повыше.

Пока пазл складывается, но нам этого недостаточно. Продебажим ядро (с помощью qemu и cgdb) и рассмотрим backtrace вывода (эхо) единичного символа, введенного пользователем с клавиатуры:

Итак, мы на I уровне tty-стека. Происходит системный вызов «write», который на нашем tty обрабатывается функцией «tty_write». В нее передаются указатель на структуру файла виртуального устройства и буфер с символом. В функции «tty_write» по файлу происходит получение экземпляра «tty_struct». Принимая игру, «tty_struct» первым делом вызывает драйвер TTY_LINE_DISCIPLINE – «tty_ldisc», место которой по умолчанию занимает N_TTY. Первый уровень пройден!

N_TTY принимает эстафету: в свою очередь вызывает метод «n_tty_write», а затем передает буфер функции «output_process_block», которая, удостоверившись, что мы ввели не символ позиционирования каретки, просит «tty_struct» позвать «tty_driver». Всё верно, мы переходим на III уровень.

«Tty_struct» успешно играет роль посредника, и вот – уже запускается метод «con_write» tty-драйвера по имени «console_driver». Драйвер III-его уровня рад бы выполнить своё дело, но он один, консолей много – с какой надо работать? На помощь опять приходит «tty_struct» и вручает драйверу нужный экземпляр структуры «vc» (она отвечает за состояние своей конкретной консоли и содержит её клавиатурные, экранные установки, а также набор методов графического отображения).

«Сonsole_driver» блокирует консоль и призывает «vc_data» выполнить наконец эхо символа. «Vc_data» с ужасом осознает: к ней обратились не ради вопроса о самочувствии вверенной ей консоли, а ради действия. Это значит лишь одно: пора звать на помощь методы «consw», которые в нашем случае представляет VGA (при другой конфигурации ядра это может быть, например, framebuffer). И точно – VGA споро берется за дело, скрывает курсор, печатает символ, при необходимости прокручивает экран или переходит на новую строку, перемещает и отображает курсор. «Vc» выдыхает: «console_driver» работу принял и консоль разблокировал. Можем выдохнуть и мы, ведь все три уровня успешно пройдены, каждый компонент свою миссию выполнил.

3. KEEP AN EYE ON VIRTUAL TERMINAL

Но это еще не всё: пришло время познакомиться с представителями еще одного класса обитателей /dev – c эмуляторами терминалов. Это те самые xterm или gnome-terminal, которые мы запускаем с консоли, оснащенной графической оболочкой, используя, например, Ctrl-Alt-T или Ctrl-Shift-T.

Живут они в отдельном вольере /dev/pts (=pseudo-terminal slave) и представляют собой файлы под номерами 0, 1, 2 и т.д. Выполняем ps в текущем терминале и видим – мы на /dev/pts/1. Нажимаем Alt+5 – перемещаемся на наш четвертый по порядку открытия терминал, файл виртуального устройства которого /dev/pts/20. На любом терминале нас встречает bash, с каждым терминалом связано своё множество процессов. Пока никаких сюрпризов.

Но заметим: /dev/pts/X создаются динамически, запускаются на одной консоли /dev/tty7, не требуют запуска login и самое интересное – здесь нет правила «кресла»: мы можем открыть несколько виртуальных терминалов и одновременно наблюдать, как происходит работа на каждом из них. В очередной раз у %username% может появиться повод для сомнений: сохраняется ли и здесь принцип tty-абстракции и как в этот принцип вписывается устройство — slave, которым, вероятно, управляет некое устройство — master?

Новый объект не заставляет себя ждать: в единственном экземпляре файл ptmx лежит в той же директории /dev (На самом деле он может быть и не один: если запущено более одной консоли с графической оболочкой). По ману, при открытии /dev/ptmx создается подчиненная часть псевдотерминала /dev/pts/X, связанного со своей ведущей частью «ptm» (обращение происходит через дескриптор файла, но реальный файл не создается). Затем «ptm» передается в функции grantpt и unlockpt, и после всего этого можно открывать непосредственно /dev/pts/X, который будет вести себя точно так же, как виртуальная консоль (за исключением описанных выше особенностей).

Для нас в ключе идеи tty-абстракции это означает следующее: когда пользователь хочет запустить эмулятор терминала, XServer обращается к /dev/ptmx с просьбой создать виртуальное устройство /dev/pts/X. Могущественный «мультиплексер» /dev/ptmx любезно делает это, закрепляет файл устройства за экземпляром терминала и … /dev/pts/X занимает место /dev/ttyX, ему назначается драйвер слоя TTY_LINE_DISCIPLINE, его ласково принимает в свои объятия TTY_DRIVER. Стек над /dev/pts/X принимает уже привычный вид. Задача изучения механизма эмулятора терминала плавно сводится к предыдущей истории с виртуальной консолью, однако его подробное изучение требует отдельной статьи (которая входит в планы на будущее!).

4. LET’S PLAY WITH TTY LINE DISCIPLINE

На секунду вспомним tty-«палеозой»: было время, когда слой TTY_LINE_DISCIPLINE и отдельным слоем-то не был и полноценной современной функциональностью не обладал. Попробуем оценить вес перемен, произошедших с тех пор.

Для начала убедимся, что мы действительно имеем дело с N_TTY:

Всё познается в сравнении, поэтому действуем кардинально и с помощью stty отключаем все полезные фичи N_TTY:

Результат наглядно демонстрирует область ответственности N_TTY, без которой вывод не форматируется, ввод не отображается. Причем, если мы откроем новый терминал, то убедимся в целостности и невредимости его LINE_DISCIPLINE. Полученный эффект наталкивает на мысль: мы точно знаем, какой компонент обрабатывает весь наш ввод, мы можем модифицировать его для каждого виртуального терминала в отдельности и, помнится, мы слышали, что этот компонент можно заменить, загрузив свой модуль.

К сожалению, N_TTY сама по себе является частью ядра. Поэтому за основу возьмем другие драйверы слоя LINE_DISCIPLINE, предусмотренные в Linux и загружаемые в виде модулей. По их образу и подобию модифицируем файл исходного кода n_tty.c:

  1. Добавим функцию отгрузки модуля, в которой вызывается функция tty_register_ldisc, осуществляющая «знакомство» ядра с нашей персональной линией дисциплины. В эту функцию первым параметром передадим ее уникальный идентификатор, а вторым – указатель на структуру с методами драйвера.
  2. Добавим функцию «выгрузки» модуля, в которой вызывается, соответственно, функция tty_unregister_ldisc.
  3. В самой структуре «tty_ldisc_ops» зададим новое имя драйвера.
  4. Позаботимся о том, чтобы наш модуль «узнал» нужные ему функции из файла tty_io.c (он не радует нас макросами «EXPORT SYMBOL», что заставляет либо дописывать все требуемые функции вручную, либо линковать вместе с tty_io.c).

Теперь добавим какой-нибудь функционал, отличающий нашу линию дисциплины от оригинальной. Помним, что именно TTY_LINE_DISCIPLINE обрабатывает служебные последовательности, поэтому грех не поколдовать на этом поприще. Для этого открываем функцию «n_tty_receive_char_special», в которой TTY_LINE_DISCIPLINE проверяет, не является ли введенные символы специальными и при нахождении оных посылает соответствующий сигнал. Для примера поменяем местами сигналы, генерирующиеся для Ctrl+Z и Ctrl+С:

После этого получим из нашего модифицированного файла непосредственно модуль ядра our_ldisc.ko. Загрузим его, убедимся, что загрузка произошла успешно. Проверим, что «our_modyfied_ldisc» действительно зарегистрировалась как TTY_LINE_DISCIPLINE. Откроем терминал и посмотрим номер pts. После этого назначим наш драйвер ответственным за слой TTY_LINE_DISCIPLINE у /dev/pts/X:

Настроим новую линию дисциплины с помощью команды «stty echo cooked» — теперь терминал работает в привычном для нас режиме. Запустим тестовую программу с вечным циклом и сравним эффект Ctrl+Z и Ctrl+С:

Мы добились желаемого: генерация сигналов переопределена на уровне драйвера слоя TTY_LINE_DISCIPLINE в индивидуальном порядке для одного эмулятора терминала! Есть поле для работы фантазии: от фокусов с обработкой служебных последовательностей до кастомизированного фильтра команд.

В ЗАКЛЮЧЕНИЕ

Теперь для тебя, %username%, тайны виртуальных консолей и эмуляторов терминала – больше не тайны, беспорядочная магия – не магия, а технология, прошедшая немалый путь, чтоб создать гибкую подсистему tty, а телетайп – не артефакт древности, а изобретение (кстати говоря, наше, отечественное), без потомков которого современный компьютер представлять как-то не хочется.

Мы любим рассказывать увлекательные истории. Хочешь послушать их вживую? Приходи на «Очную ставку» NeoQUEST-2017, там тебя ждёт множество интересных докладов: от «железа» до криптографии! Вход свободный при регистрации на сайте.

Источник

Оцените статью