Пока к компьютеру подключена одна флешка, путь /dev/sdb1 кажется надёжным. Стоит добавить второй накопитель или два одинаковых USB-адаптера, и имена начинают меняться после каждой перезагрузки. Скрипты пишут не туда, правила монтирования ломаются. Ядро выдаёт имена по порядку обнаружения, а не по смыслу устройства. udev — механизм systemd, который превращает временные имена в стабильные, задаёт права и запускает обработчики событий.

Как udev встроен в систему

Когда ядро обнаруживает устройство, оно отправляет uevent в пространство пользователя. Демон systemd-udevd получает событие, читает атрибуты из /sys, применяет правила и создаёт недостающие узлы в /dev. Базовые узлы делает devtmpfs, а udev дополняет их символическими ссылками, владельцами, группами и правами.

На старте выполняется coldplug: udevadm trigger проигрывает события для уже существующих устройств. Поэтому правило должно работать и при горячем подключении, и при загрузке. Если устройство зависит от другого, дождитесь его через udevadm settle, а не sleep внутри правила.

Где лежат правила и что важнее

Правила — текстовые файлы .rules. Места поиска идут по возрастанию приоритета:

  • /usr/lib/udev/rules.d/ — правила пакетов, редактировать не нужно;
  • /run/udev/rules.d/ — временные, исчезают после перезагрузки;
  • /etc/udev/rules.d/ — ваши постоянные правила, перекрывают системные с тем же именем.

Файлы читаются в лексикографическом порядке, поэтому номер задаёт последовательность. Не называйте файл 10-my.rules, если он должен сработать после 60-persistent-storage.rules: берите 99-local.rules. Для NAME действует «первый победил», а SYMLINK может накапливать имена.

Анатомия правила

Строка состоит из пар «ключ, оператор, значение». == проверяет, = присваивает, += добавляет. KERNEL, SUBSYSTEM и ENV смотрят на событие, ATTR — на текущее устройство, ATTRS — на него и родителей. ATTRS нужен, когда idVendor находится на USB-родителе, а не на конечном интерфейсе.

SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", ENV{ID_SERIAL_SHORT}=="A50285BI", SYMLINK+="tty-gps", GROUP="dialout", MODE="0660"

Правило создаёт /dev/tty-gps для конкретного переходника, выдаёт группе dialout чтение и запись и не трогает остальные устройства. Значения заключаются в кавычки; пробелы внутри значений лучше не оставлять.

Ключ PROGRAM запускает внешнюю команду и сравнивает её вывод с RESULT, а TEST проверяет существование файла. Эти проверки нужны, когда одного идентификатора мало. Помните: PROGRAM и RUN выполняются от root, поэтому не передавайте им непроверенные данные.

Диагностика: сначала смотреть, потом писать

Не угадывайте атрибуты. udevadm показывает всё, что видит демон, и проверяет правило без перезагрузки:

udevadm info --attribute-walk --name=/dev/ttyUSB0
udevadm info --query=property --name=/dev/ttyUSB0
udevadm monitor --udev --property
udevadm test /sys/class/tty/ttyUSB0

--attribute-walk выводит цепочку родителей и подсказывает ATTRS. monitor показывает события при подключении. test прогоняет правила для sysfs-пути и печатает, какие ссылки и права были бы применены. Если вывод слишком длинный, ищите блоки по строке looking at и проверяйте, на каком уровне находится нужный атрибут. После правки перечитайте правила и проиграйте события:

sudo udevadm control --reload-rules
sudo udevadm trigger --action=change --subsystem-match=tty
sudo udevadm settle

Стабильные имена для USB-устройств

Лучший идентификатор — серийный номер. Он есть не у всех дешёвых переходников: клоны CH340 и PL2303 часто сообщают один номер или не сообщают ничего. Проверьте ID_SERIAL_SHORT и ID_PATH. Если серийник уникален, привязывайтесь к нему. Если нет — к физическому порту:

SUBSYSTEM=="tty", KERNELS=="1-2.3:1.0", SYMLINK+="tty-radio"
SUBSYSTEM=="tty", ENV{ID_PATH}=="pci-0000:00:14.0-usb-0:2.3:1.0", SYMLINK+="tty-radio"

Привязка к порту требует вставлять устройство в тот же разъём. Для двух одинаковых адаптеров без серийника остаётся привязка к разным физическим портам. Для накопителей правило не нужно: используйте /dev/disk/by-uuid, by-partuuid или by-id в /etc/fstab. Эти ссылки создаёт штатный набор правил, и они переживают перестановку дисков.

Постоянные имена сетевых интерфейсов

Для сети NAME= в udev не является правильным инструментом: переименованием управляет systemd через .link-файлы. Создайте файл в /etc/systemd/network/, сопоставьте по MAC и задайте имя:

sudo tee /etc/systemd/network/10-lan.link <<'EOF'
[Match]
MACAddress=aa:bb:cc:dd:ee:ff

[Link]
Name=lan0
EOF
sudo udevadm control --reload

Имя применится при следующей загрузке или переподключении. Проверьте MAC через ip link и ethtool -P eth0. Не используйте Name=eth0 для двух адаптеров: конфликт оставит один интерфейс без имени.

Права доступа и uaccess

MODE="0666" — плохая привычка: устройство получает любой пользователь. Для рабочего места корректнее TAG+="uaccess": systemd-logind выдаёт ACL активному пользователю, а после выхода снимает доступ.

SUBSYSTEM=="usb", ATTR{idVendor}=="1050", ATTR{idProduct}=="0407", TAG+="uaccess"
SUBSYSTEM=="tty", GROUP="dialout", MODE="0660"

Для последовательных портов группа dialout удобна на сервере без графической сессии. Добавьте пользователя и перелогиньтесь: sudo usermod -aG dialout $USER. Проверка — ls -l /dev/tty-gps и getfacl.

Отладка и типичные ошибки

Если правило не срабатывает, включите подробный лог, повторите событие и посмотрите журнал. Не забудьте вернуть обычный уровень:

sudo udevadm control --log-priority=debug
sudo udevadm trigger --action=change --subsystem-match=tty
journalctl -u systemd-udevd -n 100 --no-pager
sudo udevadm control --log-priority=info

Частые причины: перепутаны ATTR и ATTRS; RUN+= оставляет долгий процесс работать в фоне; файл читается раньше системного; не выполнен --reload-rules. Для сложных действий — монтирования или запуска службы — используйте RUN+= только как короткий вызов, а работу передавайте systemd-юниту.

Чек-лист

  • Найдите уникальный атрибут через udevadm info --attribute-walk.
  • Кладите правило в /etc/udev/rules.d/99-local.rules.
  • Проверьте его через udevadm test до перезагрузки.
  • Для дисков используйте UUID, для сети — .link, для прав — uaccess.
  • После изменений выполните reload, trigger и ls -l.

Итог

udev решает инженерную задачу: превращает порядок обнаружения в предсказуемые имена и права. Правило из одной строки может годами удерживать /dev/tty-gps на нужном адаптере, но только если вы опираетесь на реальные атрибуты. Смотрите udevadm info, проверяйте udevadm test, держите локальные файлы в /etc и не давайте устройствам лишних прав. Тогда горячее подключение перестанет быть лотереей.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте