- Linux-аналог Знаем Linux-аналоги для Windows-приложений
- Выгода использования терминала (консоли)
- Сущность Linux-команд
- Взаимопомощь пользователей Linux
- Linux=Terminal?
- Тестовое окружение
- Создаем рабочий стол
- Вместо заключения
- Покоряй и Властвуй: Укрощение терминала
- Содержание
- Что такое Терминал?
- Зачем нужен Терминал?
- Нужно ли мне использовать Терминал?
- Должен ли я использовать Терминал?
- Hello, World! Глубокое погружение в Терминалы
- Основы
- Terminal
- Console
- Shell
- Terminal Emulator
- Virtual Console (Virtual Terminal)
- TTY устройства
- TTY Line Discipline
- TTY Line Editing
- Terminal Emulator и Pseudoterminal
- Виртуальные устройства
- Устройство псевдотерминала
- 1. tty_set_operations
- 2. ptmx_open
- Регистрация драйвера
- Hello, World!
- Заключение
Linux-аналог Знаем Linux-аналоги для Windows-приложений
Выгода использования терминала (консоли)
Большинство начинающих пользователей побаиваются командной строки в терминале Linux. Необходимость вводить команды в терминале вместо того, чтобы кликнуть мышью в графическом дизайне, многим людям представляется устрашающим и архаичным способом управления системой. (Особенно тем, кто не использовал командную строку MS-DOS в 80-х годах).
Мы не утверждаем, что командную строку необходимо использовать постоянно. Но есть некоторые задачи, выполнять которые через командную строку удобнее, приятнее и быстрее.
Предположим, необходимо установить Thunderbird с использованием графического интерфейса (например, с помощью Центра приложений Ubuntu). В таком случае приходится делать пять щелчков мышью, преодолевая несколько окон с предупреждениями и запросами пароля.
Если же приложение нужно установить с помощью командной строки Linux, достаточно ввести только одну команду
Сущность Linux-команд
Перед тем, как начать управлять системой с помощью команд, важно узнать, какими бывают команды и что они обозначают.
Есть простой способ получить такую информацию: использовать ключ —help (минус минус help). Например, получить подсказку о том, что делает команда rm, можно, если набрать в терминале
Более подробное описание команд Linux-консоли можно получить, вводя в терминале команду man. Например:
Для выхода из режима чтения описания команд man необходимо нажать на клавиатуре q.
Взаимопомощь пользователей Linux
Консольные команды для Linux-пользователей — это самый простой способ оказания помощи друг другу.
Поскольку пользователи Linux живут в разных концах мира, им проще обмениваться друг с другом строчками Linux-команд, нежели описаниями долгих процессов щелканья мышью в графических интерфейсах. Выложенные на форумах пользователей Linux-команды (для установки программ или устранения ошибок) даже не требуется набирать в терминалах. Достаточно просто копировать команды и вставлять в терминал в указанной последовательности.
Терминальные команды намного удобнее и полезнее для объяснения ошибок, поскольку в консоли в случае их возникновения всегда выводятся сообщения.
Когда ошибка возникает в графическом интерфейсе, часто можно увидеть, как какая-то часть интерфейса «изчезла», «зависла» или «замерла». Для объяснения произошедшего приходится делать скриншот и размешать его на форуме или отсылать другу. Такой трудоемкий способ оказывается в конечном итоге менее информативным, нежели простое копирование текстового сообщения об ошибке в консоли Linux.
Терминальные команды Linux также универсальны, по сравнению с видео-инструкциями или статьями, снабженными скриншотами, поскольку интерфейс разных версий и семейств Linux различаются между собой. Например, инструкция со скриншотами (картинками) графического интерфейса в Ubuntu отличается от инструкции со скриншотами интерфейса Kubuntu. А консольные команды для Ubuntu, Xubuntu, Kubuntu, and Edubuntu — одинаковы.
Если после прочтения этой статьи вы все еще думаете, что консоль – это нелепый инструмент; что вы никогда не будете ей пользоваться; что установка и настройка Ubuntu — это не то, что вам нужно, вы можете:
1. Купить ноутбук с предустановленым Linux.
2. Попросить кого-нибудь другого сконфигурировать Linux для вас.
3. Отказаться от использования Linux.
Статьи из рубрики «Первые шаги в Linux» — авторские. Их полная или частичная перепечатка возможна только при условии указания активной ссылки на источник — сайт . Надеемся на ваше понимание.
Источник
Linux=Terminal?
Несколько десятилетий прошло с момента релиза первого рабочего стола пользователя, где с помощью манипулятора-мыши появилась возможность выбирать различные части интерфейса, взаимодействовать с ними, вводить данные. Это был прорыв, определивший, как будет выглядеть пользовательское взаимодействие с современной операционной системой еще долгие годы. Сегодня без этой фичи сложно представить пользовательскую операционную систему. Визуальный рабочий стол стал для большинства пользователей основным способом знакомства с компьютерными технологиями и операционной системой.
Для более продвинутого администрирования системы пользователю так или иначе придется сделать шаг назад и обратиться к специализированному и менее визуализированному интерфейсу — консоли. В разных операционных системах этот интерфейс может называться по разному. В текущей статье обратимся к Terminal-у в ОС Linux. Операционная система Linux до сегодняшнего дня сохраняет особое отношение к Terminal-у, без него не получится установить приложение, настроить часы, осуществить поиск машин в сети и так далее. Начинающему пользователю или администратору может быть сложно ориентироваться в мире Terminal без окон, поэтому цель данной статьи — рассказать, как можно заполучить от операционной системы хотя бы примитивный рабочий стол и даже запустить приложение, которое требует наличия окон, в терминале.
Тестовое окружение
Для демонстрации настроек и работы с системами операционной системы Linux будем использовать Ubuntu 20.04 Server версию. Необходимо установить базовую систему и создать обычного пользователя. В результате должно получиться нечто похожее на снимок ниже:
Для подготовки лабораторной операционной системы также потребуется установить дополнительное ПО на сервер. Это будет Xvfb и Xpra (их описание будет в статье далее). Установить их можно соответствующими командами:
apt-get update && apt-get -y install xvfb imagemagick (последний нужен для корректного преобразования памяти в картинку)
apt-get update && apt-get -y install xpra
Проверка и отчасти демонстрация результатов может производиться на любом хосте в сети с сервером. Для тестов в качестве второй машины использовалась операционная система Kali Linux, включенная в локальную сеть вместе с Ubuntu сервером.
Создаем рабочий стол
Инструменты xpra и xvfb были созданы в первую очередь для тестирования ОС и её окружения. Однако, с появлением целого сообщества этих инструментов, их использование значительно расширилось.
xvfb — приложение, которое создано для работы с графикой на тех системах, где даже на уровне железа может и не быть видеокарты или другого устройства вывода. Все операции инструмент проводит в оперативной памяти. Применение инструмента нашлось в рендеринге, фоновых операциях с графикой. Стоит заметить, что это ПО даёт только лишь возможность взглянуть на экран, но не имеет инструментов для взаимодействия с его интерфейсами. Поэтому, чтобы картинка менялась, придется немного покодить для автоматизации. К примеру, для браузера можно использовать скрипты для Selenium.
Продемонстрируем, как можно выстроить работу с помощью xvfb . Главной единицей взаимодействия для данной тулзы является устройство Screen или просто экран. По умолчанию существует только один экран с разрешением 1280x1024x8 (ШиринаХВысотаХГлубина). Выполним следующие команды на сервере:
1. Установим X11 приложения — apt install x11-apps . Нам понадобится калькулятор для демонстрации интерфейса.
2. Откроем экран для отрисовки калькулятора:
3. Запустим калькулятор на созданном экране — DISPLAY=$DISPLAY /usr/bin/xcalc &
4. Создадим из экрана картинку, которую можно будет просмотреть на клиенте —
Выполним команду на клиенте, чтобы увидеть результат:
Выглядит не слишком современно, но это уже больше, чем просто консоль. На снимке слева — калькулятор, который был захвачен из xvfb буфера, а справа — оригинальный калькулятор, который был запущен в клиентской системе. Вообщем-то ничего важного при визуализации потеряно не было, как будто просто черно-белый экран. Проверим, что можно сделать с помощью других инструментов.
Xpra в противовес инструменту xvfb имеет полный функционал по взаимодействию с системой. Можно сказать, это своеобразный аналог VNC, который может использовать в качестве транспорта протокол ssh, tcp и несколько других, достаточно лишь настроить на целевой системе сервер для приема соединения, а на клиенте использовать верный протокол для взаимодействия. Оставим эту настройку для читателя (тестирование на виртуальных машинах не рекомендуется, так как у ПО есть проблемы с поддержкой, виртуальные машины просто зависают). А в качестве второго эксперимента проведем печать интерфейса приложения прямо из запущенного контейнера Docker.
Для проведения этого теста нам понадобится установить Docker для операционной системы Ubuntu. Инструкции к его установке можно найти вот здесь. В инструкции достаточно подробное описание, потому перейдем сразу к этапу создания Image, который будет использоваться для контейнера целевой машины. Для создания контейнера нам нужно сделать файл “Dockerfile” и наполнить его следующими данными:
Для завершения эксперимента нужно снова запустить команды для создания файла png и скопировать его на клиентскую машину. В результате получаем такой же скриншот:
Вместо заключения
В очередной раз операционная система Linux доказала свою многогранность и возможность применять различные неожиданные решения. Новичкам нужно только найти правильный набор ПО, и с ним можно будет решить любую задачу — даже просмотр пользовательского интерфейса на сервере, в котором нет видеокарты.
Данная статья была написана в преддверии старта курса Administrator Linux. Basic от OTUS. Узнать подробнее о курсе и посетить бесплатный урок можно по этой ссылке.
Источник
Покоряй и Властвуй: Укрощение терминала
Содержание
Автор: Филип Рейер (Philip Reyer)
Ты сидишь в кабинете доктора почти час. Каждая секунда кажется бесконечностью. Беспокойство охватывает тебя изнутри. В коридоре две медсестры обсуждают результаты обследования, и их мрачные лица не выглядят многообещающими. Ты гадаешь, что же такое они нашли, надеясь, что это не опасно для жизни. Ты очень много можешь потерять: семью, работу, хорошую машину. Ты вскакиваешь, как только доктор заходит в кабинет, держа в руке папку с результатами и сосредоточенно рассматривая данные. Он поднимает взгляд и смотрит прямо тебе в глаза. “Простите, но результаты показывают, что ваша болезнь неизлечима”. Твоё сердце останавливается, осознавая, что только смерть вылечит тебя. Всё, для чего ты работал … всё пропало.
Мой первый опыт работы с терминалом компьютера был похожим. Я очень боялся вводить команды вручную. При появлении любой строки на экране я беспокоился, что что-то не так. Что, если я ошибся при вводе команды, и это сломает компьютер? Впрочем, со временем это беспокойство сменилось уверенностью, что я мог бы с этого начать.
Знаете, что я думаю, когда слышу слово “терминал”? Я думаю, что это неприятное слово. И я не удивляюсь этому, когда вижу некоторые способы установок чего-либо в Linux. Я дрожу от страха, когда мне говорят запустить Терминал. Но есть ли причина бояться ввода набора символов и могущественных технических слов? Это разумный страх? Почему многие испытывают страх перед переходом на Linux из-за “возможности использования командной строки”? Позвольте развеять ваши страхи и помочь вам узнать терминал немного лучше.
Что такое Терминал?
Терминал — это приложение, которое позволяет вам общаться с компьютером, используя текстовые команды. Это означает, что для выполнения программ вам не нужно использовать сочетание клавиш или графический интерфейс. Это называется командной строкой. Вместо щелканья по кнопкам и значкам вы вводите текстовые команды. Например, чтобы обновить вашу систему, нужно ввести:
Существует множество других команд, которые используются для запуска различных программ. В первые дни существования Linux большая часть вещей делалась только в командной строке. Это одна из причин, покоторой большинство обычных людей не перешло или не хочет переходить на Linux. Правда в том, что примитивные методы использования только командной строки остались в прошлом. Linux стал удобным средством работы для всех, а не только для профессионалов. Так зачем, если Linux, в частности Ubuntu, стал настолько удобным, по-прежнему пользоваться терминалом?
Зачем нужен Терминал?
Терминал может стать вашим лучшим другом. Он поговорит с вами, когда у вас возникнет проблема. Он расскажет вам, в чем ошибка. Может не так, как это делают люди, но в очень схожей манере. Позвольте немного прояснить. Когда вы щелкаете по значку на рабочем столе или кнопке, компьютер получает некие команды. Вы не видите этого, потому что это происходит в фоне. Например, если я нажму кнопку «обновить», чтобы обновить систему, всё, что я увижу, — это строку текущего состояния, показывающую время, оставшееся до конца обновления. Но, если я введу “sudo apt-get update” (эквивалент в командной строке), я увижу очень длинный и подробный список веб адресов, на которых мой компьютер ищет обновления.
Вы возможно думаете: “Зачем мне нужно это видеть?” Ответ прост: это показывает происходящие за кулисами действия. Всё-таки, зачем это нужно знать? Если возникнет проблема с установкой, и это помешает завершить её, в терминале появятся сообщения об ошибках, которые я не увижу в случае графического интерфейса. Если всё, что я увижу, будет “Простите, установка Gobbledy Plus не может быть завершена”, я не пойму, что пошло не так. Но, если устанавливать программу через терминал, появятся сообщения об ошибках, информируя меня о проблеме. Это даст возможность их исправить или получить помощь. Но использование терминала — это не для всех.
Нужно ли мне использовать Терминал?
Хотя Терминал очень полезен во многих ситуациях, я не рекомендую его каждому. Это может быть слишком сложно для новичков, и они могут случайно испортить свою систему. Но, если у вас проблемы с компьютером: не запускается программа или не удается её установить, — вы можете скопировать вывод команды c терминала на веб сайт, чтобы получить помощь от других людей.
Должен ли я использовать Терминал?
Не нужно постоянно использовать терминал в Ubuntu, он нужен только, когда случаются какие-либо проблемы. Даже являясь продвинутым пользователем, я редко его использую. Просто потому, что, если в вашей машине есть запаска, нет нужды пользоваться ею постоянно. Вы используете её, только если прокололи колесо.
Надеюсь, вы не будете больше боятся терминала. Вместо этого вы будете рассматривать его как инструмент, с которым можно легко обращаться. Терминал очень полезен, но не нужно пользоваться только им. Нам не следует бояться неизвестности. Если мы будем бояться, мы никогда не познаем ничего нового.
Источник
Hello, World! Глубокое погружение в Терминалы
На написание данной статьи меня вдохновила статья об анализе Сишного printf. Однако, там был пропущен момент о том, какой путь проходят данные после того, как они попадают в терминальное устройство. В данной статье я хочу исправить этот недочет и проанализировать путь данных в терминале. Также мы разберемся, чем отличается Terminal от Shell, что такое Pseudoterminal, как работают эмуляторы терминалов и многое другое.
Основы
Давайте для начала разберемся, что такое Terminal, Shell, Console, чем отличается Terminal Emulator от обычного Terminal и почему он так назван. Информации об этом написано уже довольно много, поэтому ничего нового вы здесь не услышите. Почти вся информация здесь была взята из интернета, ссылки приведу в конце статьи. Кто уже знает, что все эти вещи обозначают, может смело пропускать данный раздел.
Terminal
Terminal (терминал) — это комбинация дисплея и клавиатуры, то есть физическое устройство. До того, как терминалы стали именно данной комбинацией, они являлись неким устройством под названием teleprinter (teletype, teletypewriter или TTY сокращенно), то есть комбинацией принтера и клавиатуры. Обычно несколько терминалов подключались к одному и тому же компьютеру. Таким образом возможно было работать нескольким пользователям за одним и тем же компьютером, причем каждому выделялась своя сессия, независимая от других. Терминал был назван так потому, что он находился на конце терминального кабеля (terminal end).
Это Teletype:
А это Terminal:
Console
Console (консоль) — терминал, который подключен напрямую к компьютеру. Дело в том, что большинство терминалов были соединены неявно, но хотя бы один был подключен напрямую к компьютеру. Консоль было разрешено использовать строго определенному кругу лиц, так как она позволяла настраивать компьютер.
Shell
Если предыдущие два представляют собой физические устройства, то данное определение относится исключительно к программному обеспечению.
Shell — это command line interpreter. Главное предназначение — запускать другие программы. Существует большое количество различных Shell’ов. Самым распространенным является Bash (от англ. Bourne Again SHell, что как подсказывает Википедия, является каламбуром для «Born again» Shell, то есть «возрождённый» Shell). Другие примеры: Dash (легковесный Shell, доступен, если запустить бинарник по адресу /bin/sh), Zsh.
Конечно же, и терминалы, и консоли не могли не найти своего отражения в современности. Поэтому далее мы рассмотрим такие вещи, как Terminal Emulator и Virtual Console.
Terminal Emulator
Terminal Emulator — эмулятор старого доброго терминала. Эмулятор терминала требуется для программ, которые не могут напрямую взаимодействовать с X Window System — Bash, Vim и прочие.
Давайте для начала установим обязанности терминала:
- Передача ввода пользователя в компьютер
- Доставка вывода компьютера на дисплей
Так и наш Terminal Emulator выполняет абсолютно то же самое: он доставляет ввод пользователя в запущенную программу, а также отображает вывод программы на дисплей. В любом случае, смысл сохраняется — между пользователем и запущенной программой, существует какой-то слой, отвечающий за ввод/вывод. Примеры Terminal Emulator: gnome-terminal, xterm, konsole.
Прошу не путать Shell и Terminal Emulator!
Terminal Emulator — GUI приложение, то есть окно в X Window System. Shell — это command line interpreter, то есть просто исполнитель команд, он не имеет графической оболочки. Если говорить совсем правильно, вы не запускаете Bash, вы запускаете Terminal Emulator, который запускает внутри себя Bash. Terminal Emulator и Bash — абсолютно 2 различные программы. Первая отвечает исключительно за ввод/вывод, вторая — за обработку команд.
Далее в статье все упоминания терминала будут относиться к эмулятору терминала.
Virtual Console (Virtual Terminal)
Нажмите Ctrl+Alt+FN, где N, обычно, имеет значения от 1 до 6. То, что вы сейчас видели — называется Virtual Console (виртуальная консоль) или Virtual Terminal (виртуальный терминал). Помните, что я говорил ранее о терминалах? Множество терминалов были подсоединены к одному компьютеру и каждый терминал был отдельной сессией, независимой от других. Virtual Console повторяет эту идею: внутри вашего компьютера может быть несколько независимых сессий (однако, ресурсы компьютера все же, очевидно, общие).
Вы можете именовать данную сущность как Virtual Console, так и Virtual Terminal, так как по определению, консоль — это терминал, подключенный напрямую к компьютеру, но ведь все виртуальные терминалы в каком-то смысле подключены напрямую к компьютеру.
TTY устройства
Каждому терминалу назначается свое TTY устройство (терминальное устройство), которое обеспечивает работу консоли. Хотя телетайпы вы вряд ли уже найдете, но сокращение TTY дошло и до наших дней.
TTY устройство состоит из двух фундаментальных компонентов:
- Драйвер устройства. Он отвечает за доставку ввода с клавиатуры в программу и за отображение вывода программы на экран.
- TTY Line Discipline (рус. — дисциплина линии). Дисциплина линии — это интерфейс доступа к драйверу, который, однако, привносит немало логики в TTY устройство. Можно сказать, что дисциплина линии проксирует вызовы к драйверу. Какова зона ответственности данного компонента, мы будем узнавать по ходу статьи.
Строение TTY устройства:
Существует 3 типа TTY устройств:
- Console device — обеспечивает работу Virtual Console. Ввод и вывод данного устройства управляется полностью ядром.
- PTY device (псевдотерминал) — обеспечивают работу терминала в оконном интерфейсе. Ввод и вывод данного устройства управляется эмулятором терминала, который работает в пользовательском пространстве.
- Serial device — общается напрямую с железом. Обычно не используется напрямую, а существует как самый нижний уровень в организации архитектуры терминального устройства.
В данной статье мы будем говорить именно о втором типе TTY устройств — псевдотерминалах.
TTY Line Discipline
Начнем рассматривать дисциплину линии TTY устройств.
Первой важной особенностью дисциплиной линии является то, что она отвечает за процессинг ввода/вывода. Это включает в себя, например, обработку управляющих символов (см. Управляющие символы) и форматирование вывода. Например, вы вводите любой текст, но вдруг понимаете, что ошиблись в написании чего-то и хотите это стереть — именно тут в дело вступает дисциплина линии.
Разберем подробно, что именно происходит, когда мы работаем в Bash, запущенном в терминале. По умолчанию TTY устройство работает в каноничном режиме с включенным эхо (echoing). Эхо — это отображение введенных вами символов на экране.
Когда мы вводим, к примеру, символ a , данный символ посылается в TTY устройство, но перехватывается дисциплиной линии TTY устройства. Она читает символ в свой внутренний буфер, видит, что включен режим echo и выводит символ на экран. В это время еще ничего не доступно для чтения в программе, к которой прикреплено терминальное устройство. Пусть мы нажимаем backspace на клавиатуре. Символ ^? снова перехватывается дисциплиной линии, и последняя, понимая, что пользователь хочет стереть последний введенный символ, удаляет данный символ из своего внутреннего буфера и стирает этот символ также с экрана. Теперь, если мы нажмем Enter, TTY Line Discipline наконец пошлет в буфер чтения терминального устройства все, что было записано раннее в внутренний буфер дисциплины, включая LF. При этом, на экран выводятся символы CR и LF для того, чтобы перевести курсор на новую строку — это форматирование вывода.
Так работает каноничный режим — передает все введенные символы в устройство только после нажатия Enter , производит процессинг управляющих символов и форматирует вывод.
TTY Line Editing
TTY Line Editing — это тот компонент, который отвечает за процессинг ввода в дисциплине линии. Следует сказать, что Line Editing — это общее понятие и относится оно к процессингу ввода. Например, Bash и Vim имеют свой Line Editing.
Мы можем контролировать настройки дисциплины линии текущего TTY устройства с помощью программы stty. Давайте немного поэкспериментируем.
Откройте Bash или любой другой Shell и введите:
Теперь попробуйте что-нибудь ввести — и вы не увидите вашего ввода (не беспокойтесь, вы все еще можете передавать ввод в программу). Вы только что отключили эхо — то есть отображение введенных символов на экране. Теперь введите:
Попробуйте что-нибудь вводить. Вы видите, как нарушается вывод. Но для большего эффекта давайте зайдем в Dash — введите /bin/sh . Теперь попробуйте вводить специальные символы (клавиша Ctrl + любой символ на клавиатуре) или же просто нажать Enter . Вы недоумеваете — что это за странные символы на экране? Дело в том, что мы, зайдя в самый простой Shell, кроме Line Editing самой дисциплины отключили также Line Editing Bash, и теперь можем вовсю наблюдать эффект включения raw режима дисциплины линии. Данный режим совершенно не производит процессинг ввода и не форматирует вывод. Зачем raw режим нужен? Например, для Vim: он открывается во всё окно терминала и производит сам процессинг ввода, хотя бы для того, чтобы специальные символы дисциплины линии не пересекались с специальными символами самого Vim.
Для еще большего понимания давайте рассмотрим кастомизацию управляющих символов. В этом нам поможет команда stty .
Введите в Bash:
Теперь управляющий символ erase будет назначен на символ 0 . Кнопка backspace обычно имеет значение ^? , но теперь данный специальный символ будет передаваться в буфер чтения PTS устройства буквально — попробуйте сами. Стирать символы же теперь вы можете с помощью кнопки 0 на клавиатуре, ведь вы сами попросили tty line discipline распозновать введенный символ как управляющий символ erase . Вернуть обратно настройку вы можете с помощью команды stty erase ^\? или просто закрытием терминала, ведь мы влияли только на текущее tty устройство.
Больше информации вы сможете найти в man stty.
Terminal Emulator и Pseudoterminal
Каждый раз, когда мы открываем новый терминал в X Window System, GNOME Terminal Server порождает новый процесс и запускает в нём выбранную по умолчанию программу. Обычно, это какой-то Shell (например, Bash).
Общение с запущенной программой происходит через так называемый Pseudoterminal (псевдотерминал, PTY). Сам псевдотерминал существует в ядре, однако ввод получает из пользовательского пространства — из эмулятора терминала.
Псевдотерминал состоит из следующих двух виртуальных TTY устройств:
1) PTY master (PTM) — ведущая часть псевдотерминала. Используется GNOME Terminal Server для передачи ввода с клавиатуры в запущенную внутри терминала программу, а также для чтения вывода программы и отображения вывода на дисплей. GNOME Terminal Server в свою очередь общается с X Window System по X протоколу.
2) PTY slave (PTS) — ведомая часть псевдотерминала. Используется программой, запущенной внутри терминала, для чтения ввода с клавиатуры и отображения вывода на экран. По крайней мере, так думает сама программа (объясню, что это значит, чуть далее).
Любые данные, записанные в PTS устройство, являются вводом PTM устройства, то есть становятся доступны для чтения на PTM устройстве. И наоборот: любые данные, записанные в PTM устройство, являются вводом PTS устройства. Именно таким образом и происходит общение GNOME Terminal Server и запущенной внутри терминала программы. Каждому PTM устройству сопоставляется свое PTS устройство.
Процесс запуска нового терминала выглядит примерно следующим образом:
1) GNOME Terminal Server создает master и slave устройства с помощью вызова функции open() на специальном устройстве /dev/ptmx. Вызов open() возвращает файловый дескриптор созданного PTM устройства — master_fd.
2) GNOME Terminal Server создает новый процесс с помощью вызова функции fork() . Данный процесс и будет являться новым терминалом.
3) В терминале PTS устройство открывается на файловых дескрипторах 0, 1, 2 (stdin, stdout и stderr соответственно). Теперь стандартные потоки ввода/вывода терминала ведут на данное устройство.
4) В терминале запускается нужная программа с помощью вызова функции exec() . Обычно запускается какой-то Shell (например, Bash). Любая программа, запущенная впоследствии из Bash, будет иметь те же файловые дескрипторы, что и сам Bash, то есть потоки программы будут направлены на PTS устройство.
Вы можете сами посмотреть, куда направлены стандартные потоки вывода терминала, с помощью команды ls -la /proc/self/fd :
PTS устройство находится по пути /dev/pts/N, а путь к PTM устройству нас абсолютно не интересует. Дело в том, что GNOME Terminal Server уже имеет файловый дескриптор открытого PTM устройства и ему не требуется путь к нему, однако в дочернем процессе мы должны открыть PTS устройство на стандартных потоках вывода с помощью вызова функции open() , которая требует путь к файлу.
Помните, я сказал, что программа, использующая PTS устройство, только думает, что она общается напрямую с терминалом? Дело в том, что PTS также является терминальным устройством (TTY устройством), но разница между PTS устройством и действительным TTY устройством в том, что PTS устройство ввод получает не с клавиатуры, а с master устройства, а вывод идет не на дисплей, а на master устройство. Именно поэтому псевдотерминал назван так — псевдотерминал лишь имитирует (опять??) терминал. Разница между эмулятором терминала и псевдотерминалом в том, что эмулятор терминала — это лишь графическая программа, позволяющая запускать терминал прямо внутри оконного интерфейса, но реализована эта возможность с помощью псевдотерминала.
То, что PTS устройство является TTY устройством — это очень важно. Вот почему:
- Программе, к которой прикреплено терминальное устройство, доступны все возможности обычного терминала. Например: отключение эха, отключение/включение каноничного вида.
- Программа, зная, что к ней прикреплен терминальное устройство (говорится, что программа имеет управляющий терминал), может работать в интерактивном режиме и просить у пользователя ввода. Например, спрашивать логин и пароль.
- Здесь также существует TTY Line Discipline, поэтому мы имеем возможность обрабатывать управляющие символы до того, как они дойдут до программы, а также форматировать вывод программы.
PTM устройство также является TTY устройством, но это не играет никакой роли, так как оно не используется в роли управляющего терминала. Более того, дисциплина линии PTM устройства установлена в raw режим, поэтому процессинг при передаче данных от PTS к PTM устройству не производится. Однако, вызовы read() и write() из пользовательского пространства все равно сперва обслуживаются дисциплиной линии на обоих устройствах. Данный момент сыграет еще большую роль, как мы увидим позднее.
Процесс общения GNOME Terminal Server и запущенной внутри терминала программы выглядит следующим образом:
Следует поподробнее рассмотреть роль, которую играет дисциплина линии при общении между обеими частями псевдотерминала. Здесь дисциплина линии отвечает за процессинг данных, переходящих от PTM к PTS устройству, а также за доставку данных из одной части псевдотерминала в другую. Когда мы находимся в драйвере PTS устройства, мы задействуем дисциплину линии PTM устройства, и наоборот.
Виртуальные устройства
Вы, наверное, могли подумать, что можете открыть файл по пути /dev/pts/N и писать или читать данные из него, как из обычного текстового файла? Да, все устройства в Unix-подобных системах являются файлами благодаря фундаментальному принципу Unix, который гласит, что все является файлом. Однако, никакие специальные файлы устройств (англ. — device file) не являются текстовыми файлами. Такие устройства называются виртуальными устройствами (virtual device) — то есть существуют исключительно в памяти, а не на диске.
Не стоит пытаться открывать данные файлы как обычные текстовые файлы. Однако, вы можете использовать эти устройства через операции write() и read() , вызов которых обслужит драйвер устройства. Давайте попробуем сделать это.
Откройте два окна терминала и введите в каждом команду tty . Данная команда покажет, какое TTY устройство обслуживает текущий активный терминал. Теперь введите echo «Hello, World!» > /dev/pts/N в первом окне терминала, где N — это индекс PTS устройства второго окна, переключитесь на второе окно — и вы увидите ваш ввод с первого окна. Сейчас вы записали данные в PTS устройство второго окна так, как будто бы это сделала программа, работающая в том терминале.
Устройство псевдотерминала
Мы все ближе приближаемся к заключительной части статьи, но перед этим заглянем «под капот» Linux — рассмотрим устройство псевдотерминала на уровне ядра. Будет много кода, но я постараюсь объяснять каждый приведенный блок кода максимально подробно, сокращать неважные детали и идти последовательно.
Перед началом введем так называемую «корзину компонентов». По мере продвижения по ядру, мы будет добавлять в нее всё больше компонентов и находить связь между ними. Надеюсь, это еще лучше поможет понять устройство псевдотерминала. Приступим.
Когда Linux запускается, он загружает необходимые драйверы устройств. Такой драйвер имеется и у нашего псевдотерминала. Его регистрация начинается с вызова данной функции:
Для всех современных систем будет вызвана функция unix98_pty_init() :
Здесь нас интересует 3 вещи:
- Вызовы tty_set_operatons для драйвера pty master и pty slave устройств.
- Функция ptmx_open , которая отвечает за создание обоих частей псевдотерминала при открытии специального устройства /dev/ptmx. Важно: /dev/ptmx — это не PTM устройство, а всего лишь интерфейс для создания нового псевдотерминала.
- Регистрация драйвера PTM и PTS устройств.
Пойдем по порядку:
1. tty_set_operations
Функция tty_set_operations() всего лишь устанавливает таблицу функций для текущего драйвера:
Структура tty_operations — это таблица функций, которая используется для доступа к функциям драйвера TTY устройства.
Выделю самое главное в структурах pty_unix98_ops и ptm_unix98_ops , которые являются таблицей функций для соответствующих частей псевдотерминала:
Здесь можете наблюдать уже знакомую по статье о Сишном printf функцию pty_write — к ней мы вернемся чуть позднее.
Давайте добавим данную структуру в нашу корзину компонентов:
Как видите, основные методы обоих драйверов совсем не отличаются. Кстати, заметьте, что отсутствует функция для read() операции — нет ничего похожего на pty_read() . Дело в том, что чтение будет обслуживаться исключительно дисциплиной линии. Таким образом, мы узнаём о второй важной особенности дисциплины линии — чтение данных с TTY утройства.
2. ptmx_open
Теперь перейдем к ptmx_open():
Нас интересует функция tty_init_dev() , где первым аргументом является драйвер PTM устройства, а вторым — индекс устройства. Здесь мы покидаем зону ответственности PTY драйвера и переходим к файлу, который отвечает только за общие TTY устройства и ничего не знает о нашем псевдотерминале.
Сначала разберем функцию alloc_tty_struct() :
Единственное, что нас здесь интересует, это функция tty_ldisc_init() :
Которая вызывает tty_ldisc_get() :
Итак, мы рассмотрели вызов функции alloc_tty_struct() , которая создает структуру tty_struct вместе с дисциплиной линии — структурой tty_ldisc. Обе структуры имеют ссылки друг на друга. Давайте познакомимся с данными структурами поближе.
- tty_struct — это структура для доступа к драйверу TTY устройства и некоторым другим полям. Выглядит она следующим образом:
- tty_ldisc — это структура для дисциплины линии TTY устройства. Состоит она всего из двух полей и выглядит следующим образом:
Вроде бы ничего сложного? Давайте добавим все рассмотренные до этого момента структуры в нашу корзину и свяжем их таким же образом, как они связаны в коде:
Но мы создали tty_struct всего лишь для PTM устройства. А что же о PTS устройстве? Для этого вернемся к функции tty_init_dev() и вспомним о том, что дальше нас ожидает вызов функции tty_driver_install_tty() :
Комментарий подсказывает нам, что данный метод ответственен за создание различных дополнительных структур. PTS устройство и будет являться нашей дополнительной структурой. Признаюсь, это было для меня крайне удивительно, ибо это, черт возьми, целое устройство, а не просто какая-то дополнительная структура! Но мы то с вами понимаем, что все устройства — это всего лишь какие-то структуры, так что идем дальше. Хорошо, что такое здесь driver->ops->install? Для этого посмотрим на таблицу функций для PTM драйвера ещё раз:
И поймем, что нас интересует функция pty_unix98_install() :
Которая вызывает функцию pty_common_install() :
Мы видим, что для PTS устройства создается абсолютно такая же структура tty_struct за исключением того, что в ней будет находиться драйвер PTS устройства. Обе структуры хранят указатели друг на друга для общения между собой. Добавляем tty_struct для PTS устройства в нашу корзину.
Регистрация драйвера
Мы не будем рассматривать весь процесс регистрации драйвера, так как нас интересует только установка таблицы функций для файла TTY устройства (ведь мы должны как-то получить доступ к самому устройству при работе с файлом?).
Это — таблица функций, которая будет установлена для файла как PTM, так и PTS устройства:
Мы не будем добавлять данную структуру в нашу корзину, ибо она в принципе то и не относится к устройству псевдотерминалов и служит лишь для доступа к TTY устройству.
Готово. Мы рассмотрели процесс создания обоих устройств, который будет произведен при открытии мультиплексора /dev/ptmx. Таким образом, включая второе PTS устройство, которое имеет точно такое же строение, как и PTM устройство, общая картина строения псевдотерминала складывается следующая:
Hello, World!
Ну вот мы и подошли к самому главному. В данной главе мы полностью разберем путь нашей строки «Hello, World!», отправленной из простой Си программы в терминальное устройство.
Итак, наша строка «Hello, World!» отправляется в увлекательное путешествие. На самом деле, программа не знает ничего, кроме того, что она пишет в стандартный поток вывода. Ей больше нет разницы, куда этот вывод пойдет. Направьте stdout в /dev/null — и вывод вообще не будет нигде отображаться. Здесь я не буду рассказывать о вызовах библиотечных Си функций, а начнем сразу с файловой системы Linux.
Так как каждое устройство в Unix является файлом с определенными для него функциями write(), read(), close() и прочими, то при вызове write() на /dev/pts/0 мы попадаем в общую для всех файлов функцию __vfs_write() :
Здесь мы вызываем операцию write() из таблицы функций для текущего файла. Как вы помните, таблица функций была установлена при регистрации драйвера и выглядела она следующим образом:
Данная функция получает структуру tty_struct для текущего файла TTY устройства, а потом достает из нее дисциплину линии и вызывает функцию write() для нее. Таблица функций дисциплины линии выглядела следующим образом:
Переходим к функции n_tty_write() :
Итак, строка «Hello, World!» наконец отправилась в write() функцию драйвера PTS устройства. Найдем эту функцию в таблице функций драйвера:
Давайте здесь остановимся и проследим наш путь до этого места:
Вроде бы ничего не упустили. Итак, буфер передается в очередь ввода на PTM устройство. Разберемся, как именно это происходит.
Для начала, следует познакомить вас с новой структурой данных под названием flip buffer. Flip buffer — это структура данных, состоящая из двух массивов. Когда tty driver получает новые данные, он сохраняет их в первом массиве. Когда массив заполняется, ожидающая данных сторона будет об этом уведомлена и сможет прочитать данные из этого массива. Если в будущем появятся новые данные, они сохранятся уже во второй массив для того, чтобы не перезаписать читающиеся другой стороной данные. Когда и этот массив заполняется, ожидающая данных сторона снова будет уведомлена, а новые данные в следующий раз будут снова записываться в первый массив. Именно из-за такой логики данная структура данных и названа flip buffer — потому что данные перемещаются между массивами (наверное, здесь лучше подойдет какое-то другое слово, но я не знаю хорошего перевода для слова flip).
Не будем долго тянуть и снова идти по цепочке вызовов, так что сразу перейдем к нужной функции. Вызов tty_insert_flip_string() в итоге перетекает в вызов функции под названием tty_insert_flip_string_fixed_flag() , в которой и происходит основная работа по передаче данных в PTM устройство:
На самом деле, flip buffer был замёнен новой имплементацией в новых версиях ядра, однако поведение буфера осталось почти таким же, а все функции остались совместимы с раннее реализованными драйверами. Не стоит сильно вникать в устройство данного буфера, ясно одно — в конце концов данные будут перемещены в PTM устройство, а после окончания записи ожидающая сторона будет уведомлена о готовых для чтения данных.
Итак, наша строка «Hello, World!» оказалась в PTM устройстве. В это время GNOME Terminal Server заблокирован на вызове poll() (техника мультиплексирования I/O) и ожидает новых данных на любом из master устройств. Вы думаете, сейчас он проснется и прочитает новые данные на устройстве? Как бы не так. Когда я говорил об ожидающей стороне, я говорил о дисциплине линии, ведь это именно её задача — принимать ввод и производить его процессинг при необходимости.
Дисциплина линии будет уведомлена о новых данных с помощью вызова функции tty_flip_buffer_push() (в том же pty_write):
Функция tty_schedule_flip() , в свою очередь, планирует задачу по доставке данных в дисциплину линии:
Я не знаю, что здесь подразумевается под work (предположу, что это какая-то внутренняя структура ядра для планировки различных задач) и какой компонент ядра отвечает за планировку, но из комментариев ясно следующее — когда задача начнет выполняться, доставку организует функция flush_to_ldisc() :
Функция receive_buf() через цепочку вызовов в итоге перетекает в вызов функции __receive_buf() , которая диспатчит работу по процессингу ввода:
Все функции, начинающиеся с n_tty_receive_buf (кроме тех, где есть суффикс _raw) производят процессинг данных и записывают данные в буфер под названием read_buf, который и является основным буфером для чтения с TTY устройства. Так как дисциплина линии для PTM устройства установлена в raw режим, то процессинг не будет произведен и данные сразу запишутся в read_buf. Однако, если бы мы разбирали доставку данных от PTM к PTS устройству, то процессинг был бы произведен.
Опишу полную цепочку вызовов до конечного вызова, включая пропущенные вызовы:
Заметьте, никакая функция PTM драйвера при перемещении данных не была использована — вся работа произошла в дисциплине линии и драйвере PTS устройства.
Можете выдохнуть: данные наконец записаны в конечный буфер PTM устройства. Теперь GNOME Terminal Server просыпается и читает нашу строку «Hello, World!», вызывая read() на PTM устройстве. Вызов read() по аналогии с write() перехватывается дисциплиной линии — методом n_tty_read() . В этой функции нет ничего интересного, кроме того, что она просто переместит данные из буфера в ядре — read_buf — в пользовательский буфер. Далее GNOME Terminal Server передает строку в X Server, который отобразит её на дисплей.
Таким образом, наша строчка «Hello, World!» проходит следующий путь:
Заключение
Подведем итог. В данной статье мы узнали:
- Как работают эмуляторы терминалов
- Что такое виртуальные устройства
- Что такое TTY устройства
- Как устроены псевдотерминалы
- Какой путь проходят данные, начиная с обычной Си программы и до дисплея
На этом все, спасибо за внимание! Если у вас возникли какие-нибудь вопросы — смело задавайте их в комментариях, буду рад ответить!
Источник