Продолжаем цикл популярного балета, под названием Systemd для продолжающих. В этой части, являющейся логическим продолжением предыдущей, поговорим о различных триггерах не связанных со временем. Эта часть будет не такой объёмной, но, не менее интересной. Вперёд!
Systemd.path триггер на события в файловой системе
Как известно, linux имеет большое количество системных вызовов,
среди которых имеется замечательный вызов inotify()
,
позволяющий вешать обработчики на события в файловой системе на
создание, удаление, изменение etc, файлов и каталогов. Наиболее
распространёнными утилитами, использующими inotify()
являются утилиты inotifywait
и
inotifywatch
из пакета inotify-tools
,
которые хорошо использовать в скриптах, а так-же проект
incron
cron для файловой системы, о котором уже писали на Хабре. Systemd тоже
имеет специальные юниты, которые хоть и ограничены по функционалу
(я надеюсь пока), по сравнению с incron
и тем более с
inotify-tools
, но зато умеют запускать юниты
systemd.
Практическое применение systemd.path
Вот такой триггер пришлось ваять одному товарищу, когда он захотел использовать дискретную видеокарту, в качестве основной, на своём ноутбуке (предвидя вопрос... Нет, параметра ядра для этой фигувины нет):
$ cat /etc/systemd/system/enable-radeon.path[Unit]Description=Enable radeon path[Path]PathExists=/sys/kernel/debug/vgaswitcheroo/switch[Install]WantedBy=multi-user.target
Всё то-же самое, как и в
случае с таймерами. Если в основной секции, в данном случае
[Path]
, не указана директива Unit=
, ищем
и запускаем одноимённый *.service
:
$ cat /etc/systemd/system/enable-radeon.service[Unit]Description=Enable radeon service[Service]Type=oneshotRemainAfterExit=yesExecStart=/usr/bin/sh -c "echo DDIS > /sys/kernel/debug/vgaswitcheroo/switch"[Install]WantedBy=multi-user.target
Итак всё просто. Энейблим *.path
sudo
systemctl enable enable-radeon.path
и, во время загрузки,
как только в дереве файловой системы появляется файл
(PathExists=
)
/sys/kernel/debug/vgaswitcheroo/switch
, запускаем
соответствующий сервис.
Возможные директивы слежения для systemd.path
К сожалению их мало, но базовые потребности для старта каких-либо юнитов они, в принципе, покрывают:
-
PathExists=
Триггерится на появление файла или директории, в файловой системе. -
PathExistsGlob=
То же самое что и предыдущая директива, но можно использовать файлы / каталоги по маске. -
PathChanged=
Если в файле или каталоге произошли изменения, при этом он не будет реагировать на каждый вызовwrite()
, а сработает только после первогоclose()
-
PathModified=
Подобно предыдущему, только в этом случае не ждём close(), а сразу реагируем на первый попавшийся write(). -
DirectoryNotEmpty=
Как понятно из названия срабатывает только в отношении директорий, когда в директории появляется хотя-бы один файл.
Все эти директивы можно комбинировать между собой в одном юните,
в том числе можно в одном юните следить за разными файлами и
каталогами. Внимание! Если в каком-либо из этих
параметров указана пустая строка, остальные параметры сбросятся и
ваш *.path
никогда не сработает.
Дополнительные параметры
-
Unit=
Юнит для запуска. Важное замечание, о котором я забыл в предыдущей статье. В параметреUnit=
не обязательно может быть*.service
, но и любой другой (кроме*.path
) юнит. Например*.mount
. -
MakeDirectory=
Булевый параметр. Создавать-ли каталоги слежения. По умолчаниюfalse
. -
DirectoryMode=
Связанный с предыдущим параметром параметр раздачи прав на создаваемую директорию. По умолчанию0755
.
Сравнение функционала systemd.path c incron и inotify-tools
В таблице пропущено парочка специфичных для incron
параметров.
Функция |
systemd.path |
inotify-tools |
incron |
read |
|
|
|
write |
|
|
|
attrib |
|
|
|
close & write |
|
|
|
close |
|
|
|
open |
|
|
|
moved to watched |
|
|
|
moved from watched |
|
|
|
moved self |
|
|
|
create |
|
|
|
delete |
|
|
|
delete self |
|
|
|
unmount |
|
||
systemd support |
yes |
И да, чуть не забыл. Все утилиты использующие
inotify()
работают только и
исключительно на локальных файловых системах.
То-есть, например, на SMB / NFS они работать не будут, но при этом
спокойно будут работать в /run
, /sys
,
/proc
!
Systemd.automount триггеры автомонтирования ФС
Очень простые юниты позволяющие как сэкономить немного времени, при загрузке системы, так и немного обезопасить критические (не все, с корнем такой трюк не пройдёт) файловые системы, от повреждения в случае, например, пропадания питания.
Практика
Сразу два примера. Для автомонтирования локальной и удалённой
файловой системы. Два *.automount
и два
*.mount
юнита к ним в пару. В отличие от
*.timer
и *.path
юнитов в случае
автомаунта отсутствует директива Unit=
, поэтому
используется или одноимённый persistent *.mount
, что
предпочтительнее, либо *.mount
автоматически
сгенерированный из содержимого /etc/fstab
.
Первый пример: Локальная файловая система, смонтированная в
/boot
. По большому счёту, содержимое каталога
/boot
практически не нужно при работе системы.
Исключение обновление ядра и соответственно обновление
initrd
образов и конфигурации загрузчика, что бывает,
не сказать что-бы часто. Поэтому, мы спокойно можем выслать раздел
/boot
в автомонтирование.
$ cat /etc/systemd/system/boot.automount[Unit]Description=Automount boot partition when needed.[Automount]Where=/boot## Time to automatic umount of inactivityTimeoutIdleSec=120[Install]WantedBy=multi-user.target
И в пару к нему одноимённый *.mount
файл:
$ cat /etc/systemd/system/boot.mount[Unit]Description=Boot partition (running by automount) /dev/sda1Documentation=man:systemd.mount(5)After=blockdev@dev-disk-by\x2duuid-ea65285a\x2d01da\x2d451c\x2da93a\x2d4b155c46aeeb.target[Mount]Where=/bootWhat=/dev/disk/by-uuid/ea65285a-01da-451c-a93a-4b155c46aeebType=ext4Options=rw,relatimeDirectoryMode=0755
Всё практически как в fstab
, только раскидано по
нескольким строчкам. Что происходит в автомаунте: Когда какой-либо
процесс пытается прочитать/записать что-то в каталоге
/boot
или получить его листинг, автомаунт запускает
одноимённый юнит *.mount
и начинает мониторить
обращения к /boot
. Через 2 минуты после последнего
обращения (TimeoutIdleSec=
), раздел будет
автоматически отмонтирован.
И второй пример, который я всё никак не соберусь перевести на rclone автомонтирование облака яндекса, когда я к нему обращаюсь.
$ cat /etc/systemd/system/home-oxyd-Clouds-yadisk.automount[Unit]Description=Automount yandex disc when needed.[Automount]Where=/home/oxyd/Clouds/yadiskDirectoryMode=0777## Time to automatic umount of inactivityTimeoutIdleSec=300[Install]WantedBy=multi-user.target
И ответочка к нему:
$ cat /etc/systemd/system/home-oxyd-Clouds-yadisk.mount[Unit]Description=Yandex disk automounted driveDocumentation=man:systemd.mount(8) [Mount]Where=/home/oxyd/Clouds/yadiskWhat=https://webdav.yandex.ru/Type=davfsOptions=noauto,user
Тут тоже всё прозрачно, единственно добавлен параметр раздачи прав для создания директории, если таковой не окажется на законном месте. Да у автомаунта ровно три параметра:
-
Where=
Путь который мониторим. -
TimeoutIdleSec=
Таймаут перед автоотмонтированием, если параметр отсутствует, или равен0
(по умолчанию) раздел не автоотмонтируется. -
DirectoryMode=
права на создание каталога для мониторинга, по умолчанию0755
.
Вот, вкратце, как-то примерно так. И, как всегда, какие маны почитать:
man systemd.pathman 7 inotifyman inotifywaitman inotifywatchman systemd.automountman systemd.mountman systemd-mountman 5 fstabman systemd.time
Список статей серии
-
Почему хабражители предпочитают велосипеды, вместо готовых решений? Или о systemd, part 0
-
Systemd для продолжающих. Part 1 Запуск юнитов по временным событиям
-
Systemd для продолжающих. Part 2 Триггеры на различные события
Ресурсы
-
systemd.io Статьи по внутренней кухне systemd. Частенько упоминается в манах.
-
systemd @ freedesktop.org Основная страница с манами, документацией, видео, блогами и прочими ссылками на ресурсы.
-
@ru_systemd Русскоязычный чат в Telegram. У нас тепло и лампово.