Htop на выделенном VT
от Kalter
Htop — это интерактивная программа для наблюдения за процессами, созданная как альтернатива программе top. Каждый, кто работает за машиной с линуксом на борту, использовал её хотя бы один раз: будь то поиск процесса (и его последующее убийство) или тщательный мониторинг используемых ресурсов.
Для удобства это программу можно держать всегда запущенной: в отдельном окне терминала, в его вкладках или на каком-нибудь рабочем столе. Я же предлагаю запустить его на фиксированном VT, на который можно в любой момент переключиться. Преимущество такого подхода заключается в чистом окружении.
Это возможно (и правильно) сделать с помощью системы инициализации systemd:
● Вызов по требованию, либо загрузка зависимостью getty.target.
● Избегаем логина. Он нам не нужен.
How it works?
agetty — это такая программа, которая открывает порт tty, выдаёт prompt для аутентификации и передаёт последующее управление другой программе — login.
Традиционные системы инициализации Linux конфигурируются на запуск фиксированного количества agetty при загрузке. В большинстве случаев пораждаются шесть инстансов для шести VT: от tty1 до tty6 соответственно.
В systemd используется другой подход.
● Первый — динамический. Инстанс сервиса [email protected] запускается по требованию. То есть только в том случае, если нам нужен какой-то конкретный VT. За это отвечает logind, который при переключении на ttyN запускает сервис [email protected], который является симлинком на [email protected]. Такая логика работает для tty2-tty6.
● Второй — статический. Конкретный инстанс сервиса [email protected] втягивается автоматически через getty.target, что даёт нам всегда запущенный getty на tty1.
Можете набрать в терминале команду systemctl cat [email protected], чтобы получить содержимое этого сервиса. Рассматривать подробно мы его не собираемся, поскольку это для нас не столь важно.
Соответственно, если предположить, что у нас есть некий [email protected], то и добавить его в автозагрузку можно двумя путями: либо сделать симлинк под именем [email protected] — тогда при переключении на выбранный VT htop будет запускаться вместо getty, либо отключить [email protected] и вместо него включить [email protected] — это даёт нам всегда запущенный htop на фиксированном VT.
Пишем собственный getty-подобный юнит
Теперь переходим в /etc/systemd/system — это одна из директорий, имеющая наивысший приоритет, где располагаются юниты systemd, — и создаём собственный сервис:
Наличие суффикса (@) означает, что стартует не сам по себе сервис, а один из его инстансов. А суффикс передаётся в него парамметром (%i и %I).
Выше уже было отмечено, что содержимое [email protected] для нас не столь важно. Всё так, потому что его можно занклюдить в наш сервис:
Это избавляет нас от лишнего копирования кода, учитывая что наш сервис getty-подобный.
Секция UserПереходим к секции User. Здесь описываются общие парамметры, применимые к любому типу юнита (а не конкретно к сервису).
Здесь всё прозрачно: директива Description задаёт краткое описание юнита, а Documentation путь к документации. %I — имя инстанса. Важно заметить, что обе переменные, задающие имя инстанса, различны по значению: %I - тоже самое что и %i, но с отменённым экранированием нечитаемых символов.
Секция ServiceЭта секция задаёт конфигурацию конкретно сервиса. Иными словами, описывает способ запуска процесса.
Нужные унаследованные значения директив мы оставим в покое, а некоторые необходимо сбросить (задаём для них пустое значение) и определить самостоятельно. К таковым относятся Environment — задание переменных, и ExecStart — собственно, запуск процесса.
— это указание systemd запускать htop подсоединённым напрямую к терминалу.
Можно, кстати, добавить не мгновенный запуск, а с ожиданием ввода. Для этого создаём простой скрипт на баше:
Всё что он делает — ожидает ввода и запускает параллельно какую-то программу (которой будет являться htop в нашем случае). Помещаем куда угодно, называем как угодно, делаем его исполняемым (chmod +x) и правим ExecStart в нашем сервисе:
Ограничиваем праваЕсли необходимо наложить какие-либо ограничения на права, то сделать это, конечно же, нужно. Нельзя запускать приложение с правами root и давать доступ к нему кому попало.
Создаём копии нашего сервиса и скрипта к нему:
И редактируем каждый из них. Для сервиса в секции Service изменяем значение Environment и задаём имя пользователя с его группой:
А в скрипте обращаемся к su(1):
Установка сервисаТеперь наш сервис готов, осталось только добавить его в автозагрузку:
Первая команда обновляет менеджер конфигурации systemd, а вторая создаёт симлинк на наш сервис в getty.target.wants (это определено в шаблонном юните в секции Install).
ЗаключениеТеперь перезагружаемся (либо вручную убиваем getty@ и включаем htop@ для инстанса tty2), переключаемся на второй VT и наблюдаем успешно запущенный htop. Если немного поискать, то можно заметить, что он является потомком PID1 (то есть /lib/systemd/systemd). Продемонстрированный трюк задевает лишь малую часть systemd, как системы инициализации, от всего простора возможностей systemd, как универсального plumbing layer-а — набора программ для решения совершенно разных задач. Успехов!
Для удобства это программу можно держать всегда запущенной: в отдельном окне терминала, в его вкладках или на каком-нибудь рабочем столе. Я же предлагаю запустить его на фиксированном VT, на который можно в любой момент переключиться. Преимущество такого подхода заключается в чистом окружении.
Это возможно (и правильно) сделать с помощью системы инициализации systemd:
● Вызов по требованию, либо загрузка зависимостью getty.target.
● Избегаем логина. Он нам не нужен.
How it works?
agetty — это такая программа, которая открывает порт tty, выдаёт prompt для аутентификации и передаёт последующее управление другой программе — login.
- $ ls -l `which agetty login`
- -rwxr-xr-x 1 root root 44104 Sep 29 05:21 /usr/bin/agetty
- -rwxr-xr-x 1 root root 35968 Sep 29 05:21 /usr/bin/login
Традиционные системы инициализации Linux конфигурируются на запуск фиксированного количества agetty при загрузке. В большинстве случаев пораждаются шесть инстансов для шести VT: от tty1 до tty6 соответственно.
В systemd используется другой подход.
● Первый — динамический. Инстанс сервиса [email protected] запускается по требованию. То есть только в том случае, если нам нужен какой-то конкретный VT. За это отвечает logind, который при переключении на ttyN запускает сервис [email protected], который является симлинком на [email protected]. Такая логика работает для tty2-tty6.
● Второй — статический. Конкретный инстанс сервиса [email protected] втягивается автоматически через getty.target, что даёт нам всегда запущенный getty на tty1.
Можете набрать в терминале команду systemctl cat [email protected], чтобы получить содержимое этого сервиса. Рассматривать подробно мы его не собираемся, поскольку это для нас не столь важно.
Соответственно, если предположить, что у нас есть некий [email protected], то и добавить его в автозагрузку можно двумя путями: либо сделать симлинк под именем [email protected] — тогда при переключении на выбранный VT htop будет запускаться вместо getty, либо отключить [email protected] и вместо него включить [email protected] — это даёт нам всегда запущенный htop на фиксированном VT.
Пишем собственный getty-подобный юнит
Теперь переходим в /etc/systemd/system — это одна из директорий, имеющая наивысший приоритет, где располагаются юниты systemd, — и создаём собственный сервис:
- $ touch htop@.service
- $ $EDITOR htop@.service
Выше уже было отмечено, что содержимое [email protected] для нас не столь важно. Всё так, потому что его можно занклюдить в наш сервис:
- .include /usr/lib/systemd/system/getty@.service
Секция UserПереходим к секции User. Здесь описываются общие парамметры, применимые к любому типу юнита (а не конкретно к сервису).
- [Unit]
- Description=htop on %I
- Documentation=man:htop(1)
Секция ServiceЭта секция задаёт конфигурацию конкретно сервиса. Иными словами, описывает способ запуска процесса.
- Environment=
- Environment=TERM=linux HOME=/root
- ExecStart=
- ExecStart=/usr/bin/htop
- StandardInput=tty-fail
- StandardOutput=tty
- StandardInput=tty-fail
- StandardOutput=tty
Можно, кстати, добавить не мгновенный запуск, а с ожиданием ввода. Для этого создаём простой скрипт на баше:
- #!/bin/bash
- echo "Press a key to launch $(basename "$1")"
- read
- exec "$@"
Всё что он делает — ожидает ввода и запускает параллельно какую-то программу (которой будет являться htop в нашем случае). Помещаем куда угодно, называем как угодно, делаем его исполняемым (chmod +x) и правим ExecStart в нашем сервисе:
- ExecStart=/etc/systemd/scripts/run_wait /usr/bin/htop
Ограничиваем праваЕсли необходимо наложить какие-либо ограничения на права, то сделать это, конечно же, нужно. Нельзя запускать приложение с правами root и давать доступ к нему кому попало.
Создаём копии нашего сервиса и скрипта к нему:
- $ cd /etc/systemd
- $ cp system/htop@.service system/htop_secure@.service
- $ cp scripts/run_wait scripts/run_wait_su
И редактируем каждый из них. Для сервиса в секции Service изменяем значение Environment и задаём имя пользователя с его группой:
- User=kalterfive
- Group=users
- Environment=TERM=linux
А в скрипте обращаемся к su(1):
- #!/bin/bash
- echo "Press a key to launch $(basename "$1")"
- read
- exec su -c "$@"
Установка сервисаТеперь наш сервис готов, осталось только добавить его в автозагрузку:
- $ systemctl daemon-reload
- $ systemctl disable getty@tty2.service
- $ systemctl enable htop@tty2.service
ЗаключениеТеперь перезагружаемся (либо вручную убиваем getty@ и включаем htop@ для инстанса tty2), переключаемся на второй VT и наблюдаем успешно запущенный htop. Если немного поискать, то можно заметить, что он является потомком PID1 (то есть /lib/systemd/systemd). Продемонстрированный трюк задевает лишь малую часть systemd, как системы инициализации, от всего простора возможностей systemd, как универсального plumbing layer-а — набора программ для решения совершенно разных задач. Успехов!