Comments 42
Это я еще тут многое пропустил) Но на самом деле, если разобраться, нет совершенно ничего сложного :)
Так то да, но лично я бы эту статью разбил на 2 части для более простого восприятия )
Было интересно! Спасибо!
Понравилось про вывод из одного терминала на другой
UFO landed and left these words here

Про интересные реализации вряд ли скажу, пользуюсь обычным Gnome и не жалуюсь. А что вы имеете в виду под терминалом для телеграм бота? Эмулятор терминала — это графическая программа для возможности запуска терминалов внутри оконного интерфейса, так что не очень понимаю как тут связаны бот и терминал :) Возможно, вы хотите производить процессинг ввода и имеете в виду общение с ботом прямо в терминале, а не из отдельного графического приложения (то есть просто stdin/stdout)? Тогда ответ да — в этом вам помогут псевдотерминалы. Так, например, поступают ssh и screen.

UFO landed and left these words here

Итак, вы запустили терминал и в нем работает Bash. Вы хотите из Bash запустить бота и общаться с ним? Извините, до сих пор не понимаю какова ваша цель)

UFO landed and left these words here

Понял вас) Да, так можно. Например, для gnome-terminal: gnome-terminal -e 'telegram-bot'. Просто передавайте параметром любую программу, которую необходимо запустить при создании процесса нового терминала. Думайте об этом параметре как о аргументе, передающемся в Си вызов exec().

Но вы всегда можете написать свой эмулятор терминала, который будет запускать только ваш бот :)

UFO landed and left these words here
Знакомое тело :) РАФОС, потом уже. Ну или правда, в школе читать учили.
А теперь нужна третья часть про «Далее GNOME Terminal Server передает строку в X Server, который отобразит её на дисплей». Если уж лезть в эту нору, то до самого ̶к̶р̶о̶л̶и̶к̶а̶ железа!
является каламбуром для «Born again» Shell, то есть «возрождённый» Shell

Здесь надо уточнить, что оригинальная оболочка sh называется еще "оболочкой Борна" (в честь ее автора — Стивена Борна). Соответственно bash — это Bourne again shell, в этом и каламбур. Без контекста не очень понятно (конечно, не для тех, кто уже знает).

Шикарно! Сам хотел что-то подобное написать, но работа съела все время :(
Когда читал похожую статью про устройство виндовой командной строки, только подумал, что неплохо было бы почитать что-то столь же подробное и про линуксовый терминал. blinky-z большое спасибо за столь подробную и информативную статью по данной теме!

Рад стараться! А можно ссылку на ту статью? Мне бы и самому было бы интересно почитать про терминалы в винде

Это всё очень круто, но когда и кому (задача/специальность), это может понадобиться постоянно держать в голове?
Некоторые основы нужны каждому, кто работает в терминале, чтобы понять, например, что происходит, если нештатный выход из полноэкранной программы привёл обстановку в нерабочее состояние.
Вот оставила она в raw-режиме, теперь как из него вернуться в нормальный? Предположим, что закрывать окно (если окно) — нельзя. Надо отдать команду (reset или stty sane), но сделать это не получается — нас не слышат, потому что icrnl выключено. Надо жать в этом случае не reset, а reset<Ctrl+J>. Потому что клавиша Enter генерирует не Ctrl+J (LF, код 10), а Ctrl+M (CR, код 13), и только уже в модуле дисциплины присутствие icrnl переводит его в тот код, что ожидает обычный ввод строки. «И сырость капает на клавишу ВК».

У сетевых админов маршрутизаторы ряда классических производителей типа Cisco, Juniper управляются, по крайней мере при начальном конфигурировании, через последовательный порт. Тоже надо понимать хотя бы основы, что оно такое и как может работать.

У эмбедщиков или у тех админов, что управляют машинками по IPMI, очень типичный вариант — serial console поверх IPMI, которую нужно ещё уметь настраивать и понимать её глюки (и там проблемы сильно выше описанной — я у, кажется, Dell видел реализацию, у которой внутри конвертировались даже не битовые потоки, а эмуляции напряжения на порту, между разными скоростями).

Или вот ещё — на моей прошлой работе была одна жутко специализированная и дорогущая проприетарная программа, которая работала по капризу автора как терминальная (были и другие варианты доступа, но считались не основными). Предполагалось, что ею будет управлять человек непосредственно с терминала, некоторые вещи можно было делать только через него. А надо было автоматизировать управление (запуск/останов, отдачу команд). Пришлось запускать под screenʼом через самопальный переходник, что запускал целевую программу под отдельным PTY, гонял данные туда-обратно, настраивал штатную дисциплину, слушал команды по управлению, мог вставлять от имени пользователя какие-то последовательности символов или рассказывать, что последнее она вывела…

Действительно глубокое погружение.
И на удивление качественно подготовленный материал, хороший стиль, в сравнении с большинством современных публикаций на Хабре.
Автор, пиши ещё!

Хорошее изложение, мне понравилось.

Кроме беды с этим термином:
TTY Line Discipline (рус. — дисциплина линии)

«Дисциплина линии» — на редкость неудачный перевод для «line discipline».

Да, я в курсе, что именно такая калька применяется повсеместно. Но, к сожалению, она затрудняет понимание на русском языке.
Из-за такого перевода line discipline постоянно ассоциируют с линией связи терминала (т.к. tty действительно подразумевает наличие таковой), но никакого отношения ни к каким линиям line discipline не имеет.
Английское «line» в этом контексте на русский переводится исключительно как «строка», т.к. подразумевает последовательность символов до символа LF («line feed» — «перевод строки»).

Почему-то нигде переводчикам не приходит в голову называть строки линиями — ни в текстовых редакторах, ни в табличных процессорах, ни в тех же эмуляторах терминалов.
Поэтому «line discipline» — это строковый буфер, строковая политика, обработчик строки, на худой конец — дисциплина строки, но никак не дисциплина линии.
Из-за такого перевода line discipline постоянно ассоциируют с линией связи терминала (т.к. tty действительно подразумевает наличие таковой), но никакого отношения ни к каким линиям line discipline не имеет.

Да, объяснение про строку и правда звучит логично, но разве не по этой самой линии связи передавался ввод? Тогда и название было бы вполне оправдано.

но разве не по этой самой линии связи передавался ввод?

line discipline находится между приложением и драйвером терминала.

Ее задача — обеспечение построчного ввода/вывода (т.е. в первую очередь — задачи буферизации) с возможностью обработки метаинформации (в виде служебных символом в том же потоке). Для пользователей это, в частности, позволяет редактировать набираемую команду.

А «эта самая линия» находится «за» драйвером и в общем случае ее может вообще не быть — может быть ее эмуляция, до чего line discipline нет абсолютно никакого дела. Аналогом «этой самой линии» для псевдотерминала является связь PTS<-->PTM.

Да, в конкретных имплементациях обрабатываемая метаинформация может включать в том числе управление «той самой линией» и тогде некоторые служебные символы могут транслироваться, например, в ioctl драйвера, но обычно задачи line discipline сводятся к простому форматированию текста.

Замечу одну неточность в вашем ответе:


Вы сказали, что связь между pty master и pty slave это аналог линии связи. Однако, ведь это не правда. Линия связи лежала перед UART устройством. Байты с UART устройства принимал UART драйвер и передавал их после обработки драйверу консоли. Сейчас заместо uart драйвера и драйвера консоли выступают PTM и PTS устройства. Дисциплина линии же все также лежит между этими двумя устройствами, но здесь нет никакой линии связи больше. Конечно, это не отдельная дисциплина линии, а экспортируется дисциплина одного из устройств. Линия связи ушла, но дисциплина линии осталась. Точно также, как и название TTY — очень много концепций сохранилось с тех времен, поэтому не забывайте, что, может быть, хоть и сейчас "дисциплина линии" это что-то непонятное, но если мы окунемся в прошлое, то название будет иметь смысл.

> Ее задача — обеспечение построчного ввода/вывода (т.е. в первую очередь — задачи буферизации)

Это задача одного конкретного варианта дисциплины — которая называется «нормальной» или тоже «терминальной». В Linux это константа N_TTY среди констант вариантов дисциплины.

Могут быть выбраны другие line discipline. Вот отдельная программа установки дисциплины на TTY — заметьте, сколько разных дисциплин она знает, и все кроме одной — никаких «строк» не знают, в основном это сетевые стеки с пакетами. На программном уровне это ставится через TIOCSETD.
> Поэтому «line discipline» — это строковый буфер, строковая политика, обработчик строки, на худой конец — дисциплина строки, но никак не дисциплина линии.

Нет, именно линии. Потому что такие дисциплины бывают:
  • обычная терминальная — только тогда «строка» имеет хоть какое-то смысл в обработке;
  • SLIP или PPP — тогда никаких строк нет, работа на уровне байтов; задача дисциплины — вылавливать пакеты, отправлять их в IP стек, в случае PPP — также отрабатывать управляющие пакеты протокола (или хотя бы передавать их в управляющий процесс);
  • изредка — другие (вот большой список), в которых тоже нет строк.
Нет, именно линии.

Да, похоже вы правы.

Мне не приходилось работать с сетью через терминал.
И я всегда считал, что в этом случае, как часто бывает, существующий механизм line discipline был расширен на несвойственные ему изначально задачи.
Но вот предполагалась ли изначально, что дисциплина будет работать с бинарными пакетами, сейчас сказать не так просто — все это было в pre-git истории.
> Мне не приходилось работать с сетью через терминал.

Ясно. Мне приходилось с обеих сторон — строить доступ по PPP и SLIP по модемному дозвону.

> Но вот предполагалась ли изначально, что дисциплина будет работать с бинарными пакетами, сейчас сказать не так просто — все это было в pre-git истории.

«Pre-git» история немного доступна. В Lionsʼ Book (подробная структура Bell Unix V6) описаны функции процессинга ввода-вывода как для терминала, но хардкодом, а не выбираемым модулем.
Расширение на сменные модули (с обычным терминальным процессингом как умолчательным) появилось, скорее всего, в 4.2BSD-4.3BSD, со введением dial-up и связей по постоянным линиям поверх последовательных портов. Но тут самая тёмная часть истории из-за закрытости исходников; 4.4BSD-Lite-based BSD системы — открытые — уже содержали line discipline как устоявшееся и почти идентичным кодом, что нас приводит таки во времена не позже общей 4.4.
Реквестирую комментарий Иртегова.
Очень уж он любит вопрос «что такое терминал?».
В терминале запускается нужная программа с помощью вызова функции exec(). Обычно запускается какой-то Shell (например, Bash).
Разрешите наивный вопрос. Разве exec не подразумевает замену вызывающей программы на вызываемую? И получается, что Shell у нас должен появиться вместо эмулятора терминала. Проясните, пожалуйста, этот момент.

Да, конечно же спавнится новый процесс и уже в нем запускается Shell. Смотрите эту функцию: https://developer.gnome.org/vte/unstable/VteTerminal.html#vte-terminal-spawn-async. Это — VTE widget, созданный и поддерживаемый GNOME. В нем и происходит почти вся работа по созданию терминалов. Конкретно в данной функции 4 аргументом принимается нужная команда, создается PTY и в новом процессе запускается данная команда на созданном PTY.

Статья у вас фундаментальная. И по её изучении я в том числе нарисовал схему (некий сухой остаток для закрепления). Если не сложно, посмотрите, что нужно в ней подправить.
Заголовок спойлера

Посмотрел.


  1. /dev/ptmx — это все таки устройство. Фраза — "это не устройство, а интерфейс" странная, так как данное и является интерфейсом для создания pty. Как это работает? Мы вызываем open(/dev/ptmx), и вызов open обслуживает драйвер данного устройства, конкретнее мы видели, что за это отвечает функция ptmx_open.
  2. "PTM и PTS — это виртуальные устройства...". Да, это верно, но не по той причине что вы написали, а потому, что они не существуют физически на диске, а живут в виртуальной файловой системе /dev, т.е. живут в памяти, в ядре. Вообще, то, как я определил виртуальные устройства — расходится с тем, что говорит википедия. Там виртуальные устройства — это устройства, не взаимодействующие напрямую с аппаратными устройствами. Так что лучше избегать понятия "виртуальное устройство" по отношению к ptm/pts и говорить, что PTM и PTS являются файлами устройств, а конкретнее, терминальными устройствами. Не думаю, что их можно назвать виртуальными устройствами, так как формально они взаимодействуют с терминалом. Вот /dev/null уже является виртуальным устройством.
  3. Ну и последнее я считаю своей самой большой ошибкой в статье. Зря я вообще заикнулся о gnome терминале. Дело в том, что его работа намного сложнее, чем какой-нибудь xterm. Он не создает новые процессы для терминалов, а запускает их внутри тредов. Программы внутри терминала конечно же запускаются в отдельных процессах (а конкретнее этим занимается vte widget и его функция vte_terminal_spawn_async). Мой вам совет — поизучайте xterm — крайне простой и понятный эмулятор терминала, который, более того, работает в обход gtk, gnome и всяких других графических тулкитов.
    Если вам интересно, убедиться в том, что gnome терминал — не отдельный процесс, можно достаточно просто. Введите:
    $ ps --pid $$ --format ppid=

И вы увидите, что родителем баша является сам Gnome Terminal Server. Да, это кажется странным со стороны, но наверняка на то были причины, что gnome терминалы работают внутри тредов. Первую причину, которую я вижу, это функциональность вкладок (tabs).


Пишите в лс, можем еще что-то обсудить, если понятнее не стало :)

Хотя насчет простоты xterm я все таки погорячился — его соурс код сложно понятен, да и вообще сам он раздут сильно по возможностям и наполнен многими ненужными в актуальное время вещами. Но в качестве понимания того, как примерно эмулятор терминала работает, вполне пойдет

Рекомендую st для более глубого изучения устройства терминалов — это точно самый простой и понятной терминал на сегодня. https://st.suckless.org/

Only those users with full accounts are able to leave comments. Log in, please.