Вопрос или проблема
Каковы именно шаги от момента запуска псевдо-терминала (CTRL+ALT+T) до момента, когда оболочка начинает слушать ввод с клавиатуры?
Я примерно знаю, что терминальный процесс вызывает dev/pts/ptmx
, затем создается slave-сторона (например /dev/pts/0
), и тогда терминальный процесс форкается (я так полагаю?), настраивает сеанс и выполняет оболочку.
Однако мне любопытно узнать, как именно это работает.
Меня особенно смущает следующее в этой процедуре:
- Я думал, что мой эмулятор терминала (псевдо-терминал) — это
xterm-256color
, так как это то, что я получаю, когда ввожуecho $TERM
. Так чтоxterm
вызывал быptmx
. Однако, когда я проверяю PPID оболочки (bash), это оказывается/usr/libexec/gnome-terminal-server
. Так что я запутался, в чем разница между этими двумя? Сначалаxterm
форкает/выполняет/usr/libexec/gnome-terminal-server
, а затем он вызываетptmx
и дальше форкает/выполняет оболочку, или как? - Я думал, что сеанс был чем-то, исключительно связанным с терминалом. То есть у каждого терминала есть только один сеанс, и на этом все. Однако, когда я копнул глубже, оказалось, что это “вещь ядра” и что у каждого процесса есть сеанс, включая
/usr/libexec/gnome-terminal-server
. Почему же тогда создается новый сеанс для bash, а не используется тот, что у/usr/libexec/gnome-terminal-server
, так как это на самом деле терминал? - Как
/usr/libexec/gnome-terminal-server
знает, какую оболочку запускать/выполнять (в моем случае bash)? Он читает это откуда-то, могу ли я это изменить?
Мне интересно, как именно работают эти шаги.
Спасибо
Я думал, что мой эмулятор терминала (псевдо-терминал) — это xterm-256color, так как это то, что я получаю, когда ввожу echo $TERM. Так что xterm вызывал бы ptmx. Однако, когда я проверяю PPID оболочки (bash), это оказывается /usr/libexec/gnome-terminal-server. Так что я запутался, в чем разница между этими двумя? Сначала xterm форкает/выполняет /usr/libexec/gnome-terminal-server, а затем он вызывает ptmx и дальше форкает/выполняет оболочку, или как?
$TERM — это не то же самое, что $SHELL, и не указывает на фактический эмулятор терминала. Скорее, он указывает возможности эмулятора терминала — какие управляющие последовательности он будет генерировать и принимать. Программы используют значение $TERM для поиска в базе данных ‘termcap’ или ‘terminfo’ (см. infocmp
) или сопоставляют его с жёстко закодированными случаями.
К сожалению, это не очень полезная система в наши дни, поскольку эти записи terminfo должны распространяться на каждую систему, к которой вы подключаетесь через SSH, и так далее. (Удачи вам, если когда-нибудь придется подключиться к не-Linux системам!) Например, если вы установите терминал Foot и подключитесь через SSH к системе, которая ничего не знает о TERM=foot
, программы не будут знать, как с ним взаимодействовать. В результате большинство терминалов имитируют Xterm и заявляют о совместимости с xterm
или xterm-256color
, чтобы они работали из коробки.
GNOME Terminal делает именно это: он не использует /bin/xterm для чего-либо, а скорее заявляет о совместимости с /bin/xterm, устанавливая то же значение $TERM, которое бы установил Xterm.
Я думал, что сеанс был чем-то, исключительно связанным с терминалом. То есть, у каждого терминала есть только один сеанс, и на этом все. Однако, когда я копнул глубже, оказалось, что это “вещь ядра” и что у каждого процесса есть сеанс, включая /usr/libexec/gnome-terminal-server. Почему же тогда создается новый сеанс для bash, а не используется тот, что у /usr/libexec/gnome-terminal-server, так как это на самом деле терминал?
У процессов может быть ‘управляющий терминал’, и, насколько я знаю, каждый сеанс ядра также ассоциируется с ‘управляющим терминалом’. Но слово ‘терминал’ здесь относится не к терминальному эмулятору, а к терминальному устройству (tty) — его присутствие позволяет оболочке осуществлять управление заданиями (Ctrl-Z и т.д.) на своем собственном tty — поэтому вам нужно, чтобы у каждого устройства pty был свой собственный сеанс и свой собственный “лидер” процесса (оболочка) с этим pty как управляющим терминалом. Между тем сам процесс терминального эмулятора (если он вообще есть!) не имеет никакого отношения к этому и вовсе не обязательно должен быть в сеансе.
Это предел моих знаний о сеансах ядра, так что я надеюсь, что кто-то еще даст лучший ответ.
Как /usr/libexec/gnome-terminal-server знает, какую оболочку запускать/выполнять (в моем случае bash)? Он читает это откуда-то, могу ли я это изменить?
Оболочка по умолчанию является параметром вашей учетной записи пользователя и читается из вашего /etc/passwd
, который можно изменить с помощью chsh
или usermod
(или из другой базы данных пользователей через getpwnam()
, и вы можете изменить его, используя те методы, которые подходят для этой базы данных). Используйте getent passwd $USER
– или lslogins $USER
– чтобы узнать свою запись passwd.
В GNOME Terminal можно определить пользовательскую команду для каждого ‘профиля’ через окно “Preferences” приложения, как и в большинстве других терминальных эмуляторов.
.
Ответ или решение
Запуск терминала и переход в режим ожидания ввода от клавиатуры включает в себя несколько шагов, каждый из которых выполняет свою специфическую роль в обеспечении работы системы. Рассмотрим подробно этот процесс.
Теория
Когда вы запускаете терминал (например, через сочетание клавиш CTRL+ALT+T
), начинается взаимодействие с псевдотерминалом (PTY), который является программным аналогом аппаратного терминала. PTY разделяется на мастер-узел и слейв-узел. Мастер-узел позволяет манипулировать данными, которые передаются в слейв-узел, который в свою очередь взаимодействует непосредственно с пользовательской программой, такой как оболочка (shell).
С назначением PTY связан терминал-эмулятор, который отображает интерфейс и управляет вводом-выводом. Запуск пользовательской оболочки в слейв-узле PTY позволяет пользователю взаимодействовать с операционной системой через текстовый интерфейс.
Пример
-
Инициация терминала: Когда вы нажимаете
CTRL+ALT+T
, запускается терминал-эмулятор, такой как GNOME Terminal. Эмулятор вызывает системные API для открытия и получения доступа к PTY черезdev/pts/ptmx
. -
Создание узлов PTY: Мастер-узел PTY создается и привязывается к определенному устройству, например,
/dev/pts/0
. После этого терминал-эмулятор разделяет PTY на мастер и слейв, управляя первым и предоставляя доступ ко второму оболочке. -
Форк и исполнение: Терминал-эмулятор создает процесс-оболочку (например, bash) через системный вызов fork и exec в слейв-узле PTY. Это запускает пользовательскую сессию с уникальным ID процесса (PID).
-
Установка аттрибутов среды: Сессия и связанные с ней аттрибуты, такие как переменные окружения ($TERM и др.), настраиваются согласно профилям пользовательской оболочки и системным настройкам (например,
/etc/passwd
для выбора оболочки). -
Начало работы оболочки: После этого оболочка начинает взаимодействие с пользователем, принимая клавиатурный ввод в качестве команд.
Применение
Процесс, описанный выше, подчеркивает, что $TERM (например, xterm-256color) — это переменная окружения, отражающая возможности терминала, но не сам эмулятор. GNOME Terminal, хотя и использует GNOME-сервер, может претендовать на совместимость с xterm, устанавливая такую переменную. Таким образом, вся сложность процесса остается невидимой для пользователя, обеспечивая ему привычный интерфейс для взаимодействия с системой.
Кроме того, оборудование сессий является неотъемлемой функцией ядра, что позволяет каждому PTY иметь свою собственную сессию и ведущий процесс. Это позволяет оболочке реализовывать управление задачами (например, использование сочетаний клавиш типа Ctrl-Z) внутри своего собственного терминального устройства.
Эти знания важны для глубинного понимания работы Unix-подобных систем и позволяют настроить терминал и оболочку под специфические нужды пользователя, в том числе изменяя настройки запуска оболочки через параметры в профиле терминала или системные утилиты, такие как chsh.