Еще раз про udev

Автор: Алексей Федорчук

Несколько лет назад, почти сразу после внедрения в Linux механизма udev, я написал краткую заметку по поводу с первых разборок с оным. Нынче, в связи со вновь образовавшимися обстоятельствами, настало время опять обратиться к этой теме, расширив и даже, как сказал бы один из наших президентов, углубив её.

Прежде чем начать настоящую заметку, оговорюсь, что в неё включён весь материал заметки прежней — тот, что сохранил актуальность. Так что обращаться к последней необходимости нет — разве что в историческом аспекте.

Udev — это механизм поддержки настраиваемогодинамического именования устройств в Linux, пришедшая на смену виртуальной файловой системе устройств devfs; во FreeBSD эта функция возлагается на последнюю. Первый и основной разработчик udev — Грег Кроа-Хартман (Greg Kroah-Hartman).

В отличие от devfs, udev — не файловая система, поддерживаемая ядром, а обычная пользовательская программа. Для своего функционирования udev нуждается в виртуальной файловой системе — sysfs. Основываясь на информации из неё, udev и присваивает имена различным устройствам, в том числе и при горячем их подключении.

Как известно, любой POSIX-системе имена конкретных устройств более или менее безразличны, так как оперирует она не с ними, а с их идентификаторами. Ранее, до внедрения devfs и, позднее, udev), в качестве таковых выступали так называемые номера устройств — старший номер устройства, определяющий его класс (например, ide-накопители) и младший его номер, указывающий на конкретный экземпляр данного представителя класса. Ныне же используются непосредственные идентификаторы устройств — серийный номер винчестера, его положение на SATA-разъёме или канале PATA-шины, и так далее. Сочетание их для каждого диска (раздела, и так далее) оказывается уникальным. Так вот, udev извлекает эти сведения из файловой системы sysfs и, руководствуясь определенными правилами,
ставит им в соответствие “человеческие” имена (вроде тех же /dev/sda и так далее).

Процесс включения поддержки udev очень прост и сводится к установке пакета udev — во всех современных дистрибутивах Linux он входит в базовую систему, так что специально его устанавливать не нужно.

Далее, следует позаботиться о запуске демона udevd при старте системы. За это отвечает один из сценариев инициализации, зависящий от дистрибутива. Например, в Ubuntu это будет файл /etc/init.d/udev. Впрочем, в любом современном дистрибутиве это также происходит по умолчанию, так что руками ничего править не надо.

Теперь в каталоге /dev можно видеть привычные имена файлов устройств — /dev/sda, соответствующее винчестеру на первом разъёме SATA, /dev/sda[1-4] для его разделов, а также /dev/sr0 для CD-привода; имеется и традиционный файл устройства /dev/cdrom — символическая ссылка на /dev/sr0:

$ ls -l /dev/cdrom
lrwxrwxrwx 1 root root 3 2009-05-19 08:27 /dev/cdrom -> sr0

Подключение флэш-накопителя в USB-разъем немедленно приводит к появлению в списке устройства с именем /dev/sdb, не меняющееся, сколько бы ни повторять эту процедуру.

Иными словами, каталог /dev приобретает вид, привычный по временам статического именования устройств. С той только разницей, что теперь он не заполнен впрок файлами возможных, но не существующих устройств.

За конфигурирование механизма udev отвечает специальный файл —
/etc/udev/udev.conf, определяющий глобальные параметры, корневой каталог для файлов устройств (по умолчанию — /dev), файл базы данных устройств, файлы описания правил именования устройств и прав доступа к ним, а также правила создания символических ссылок (подобных /dev/cdrom). Конкретные имена этих файлов и их местоположение зависят от дистрибутива. Обычно это файлы вида /etc/udev/rules.d/udev.rules и
/etc/udev/permissions.d/udev.permissions.

Ручное вмешательство в конфигурационные файлы требуется редко, но иногда такая
необходимость возникает. Так, на заре внедрения механизма udev я столкнулся (в
дистрибутиве Archlinux) с такой ситуацией: после перезапуска машины с задействованным udev у меня исчез звук — и с первого же взгляда на файл /etc/udev/permissions.d/udev.permissions стало ясно, почему. Права доступа ко всем аудио-устройствам имели примерно такой вид:

dsp*:root:root:0660

где dsp — имя устройства, root:root — хозяин и группа, соответственно, 0660 — маска,
определяющая запрещение доступа для всех, кроме хозяин и группы. У меня же
ранее устройства, связанные с воспроизведением аудио, относились к
группе sound, в которую я и включал себя.

Так что пришлось срочно заменить второе вхождение root’а на группу sound — и
после перезапуска со звуком все стало нормально.

Для управления механизмом udev “на лету” служит утилита udevadm. В частности,
с её помощью можно определить уникальные идентификаторы любых устройств — в
современных дистрибутивах, как уже было сказано, именно они используются,
например, для автоматического монтирования файловых систем при старте машины. Для этой цели следует дать команду udevadm примерно в таком виде:

$ udevadm info --query=env --name=/dev/sdb1 | grep UUID

Здесь субкоманда info предписывает вывести информацию, опция –query определяет, какую именно (env — спецификации устройства), а значением опции –name будет имя файла устройства. Среди множества параметров, таких, как модель диска, его интерфейс
и многое другое, будет и искомый идентификатор устройства примерно такого облика (именно его мы отфильтровываем, передавая вывод утилиты udevadm команде
grep):

ID_FS_UUID=56b2dede-e113-425a-9f50-c1017f9e9113

Этот идентификатор можно использовать в файле /etc/fstab вместо имени устройства,
примерно таким образом:

# / was on /dev/sda6 during installation
UUID=f65d488b-a4c0-455c-9372-34bbbae2f5c1 / ext4 relatime 0 1

Что имеет и свои недостатки, и свои достоинства. Недостатки — очевидны:
громоздкость и неудобочитаемость файла.

Достоинства не лежат на поверхности, но также имеют место быть: в частности, при переключении дисков с одного SATA-разъема на другой, или при смене последовательности обращения к винчестерам в BIOS Setup, не нужно думать об
изменении соответствующих строк в /etc/fstab.

Ещё одна напрашивающаяся сфера применения UUID — обеспечение безопасности.
Так, внесением в /etc/fstab строк вида

UUID=значение /mountpoint vfat noauto,user 0 0

можно разрешить монтировать от лица обычного пользователя, скажем, не
флэш-накопители вообще, а только совершенно конкретные флэшки. То же
самое можно распространить на CD- и DVD-носители, камеры etc. Способ довольно
хлопотный — потребуется вносить много строк в /etc/fstab и отключать автомонтирование
сменных накопителей через HAL (о котором речь пойдёт в следующем разделе). Однако
можно представить себе ситуации, когда он будет оправдан.

Одна из дополнительных особенностей udev — возможность создавать файлы
устройств с нестандартными именами, например, /dev/camera — для цифрового
фотоаппарата, /dev/flash — для флэш-накопителя, и так далее. Это полезно, в частности,
если одновременно подключено несколько устройств с интерфейсом одного типа —
скажем, та же камера и флэшка, поскольку не нужно задать, какое из имен файлов
устройств вида /dev/sd?# чему соответствует.

Рассмотрим этот вопрос на примере обычного флэш-накопителя с USB-интерфейсом.
Для чего подключаем интересующее нас устройство и в с помощью всё той же
команды udevadm определяем его идентификатор:

$ udevadm info --query=env --name=/dev/sdb1 | grep UUID
ID_FS_UUID=D3B2-6597

Теперь нам понадобятся права администратора для создания файла описания правил,
получаемый, например, так:

$ sudoedit /etc/udev/rules.d/00-flash.rules

После ввода пользовательского пароля мы оказываемся в редакторе по умолчанию,
определяемом значением переменной EDITOR данного пользователя (у меня это nano); если таковая не определена, будет вызван стандартный vi. В открытый в нём пустой файл (имя его произвольно, важно только проследить, чтобы он считывался раньше стандартных для данного дистрибутива файлов описаний правил), вносим единственную строку

ID_FS_UUID="D3B2-6597", NAME="fl256"

где значением переменной ID_FS_UUID будет полученный выше идентификатор устройства, значением переменной NAME — какое-либо мнемонически удобное имя, в данном случае символизирующее, что мы имеем дело с флэшкой объёмом 256 Мбайт.

Перезагрузки системы не потребуется: для проверки правильности выполненных действий достаточно отсоединить устройство и подключить его заново.

Конфигурационные файлы udev при этом будут перечитаны, в результате чего в
каталоге /dev/ появится файл с соответствующим именем:

$ ls /dev/fl*
/dev/fl256

Повторяем процедуру для всех интересующих нас устройств: так, я проделываю это для
постоянно используемых мной флэшек объемом 1 Гбайт и 16 Гбайт, определяя для них имена fl1g и fl16g, соответственно.

С камерой всё точно также, однако разнообразия ради проделаем описанную процедуру несколько иным путём, а именно: подключаем камеру и даём команду devadm в несколько иной форме:

$ udevadm info --query=env --path=/block/sdd/sdd1 | grep MODEL
ID_MODEL=Samsung_Digital_Camera

После чего в файл /etc/udev/rules.d/00-flash.rules добавляем соответствующую строку:

ID_MODEL="Samsung_Digital_Camera", NAME="camera"

И после отключения и повторного присоединения устройства имеем счастье наблюдать в каталоге /dev новый файл:

$ ls -l /dev/camera
brw-rw---- 1 root disk 8, 49 2009-05-20 08:38 /dev/camera

Ещё один способ придать файлам устройств имена, отличные от присваиваемых ядром
— использование символических ссылок. Это целесообразно, в частности, для
файлов устройств компакт- и DVD-приводов: ряд программ, например, Mplayer, при
проигрывании аудио-, видео-CD и DVD по умолчанию рассчитывает обнаружить их
в устройствах типа /dev/cdrom и /dev/dvd.

Поскольку файлы устройств создаются динамически при загрузке системы, то и
ссылки должны создаваться динамически, что также описывается соответствующими
правилами. В большинстве современных дистрибутивов Linux’а такие правила
задаются по умолчанию при инсталляции системы. Так, в Ubuntu они содержатся в
файле /etc/udev/rules.d/70-persistent-cd.rules в следующем виде:

ENV{ID_CDROM}=="?*", ENV{ID_PATH}=="pci-0000:00:1f.5-scsi-1:0:0:0", SYMLINK+="cdrom", ENV{GENERATED}="1"
ENV{ID_CDROM}=="?*", ENV{ID_PATH}=="pci-0000:00:1f.5-scsi-1:0:0:0", SYMLINK+="cdrw", ENV{GENERATED}="1"
ENV{ID_CDROM}=="?*", ENV{ID_PATH}=="pci-0000:00:1f.5-scsi-1:0:0:0", SYMLINK+="dvd", ENV{GENERATED}="1"
ENV{ID_CDROM}=="?*", ENV{ID_PATH}=="pci-0000:00:1f.5-scsi-1:0:0:0", SYMLINK+="dvdrw", ENV{GENERATED}="1"

Если по каким-либо причинам ссылок вида /dev/cdrom -> /dev/sr0 при старте системы не создаётся, следует прописать правила, по образу и подобию приведённых, вручную.

Еще раз про udev: 1 комментарий

  1. Спасибо за статью, узнал много нового. О том, что устройства можно именовать произвольно я догадывался, но не знал, что сие настолько просто.
    По поводу симлинка /dev/cdrom — у меня его почему-то нет. В файле /etc/udev/rules.d/70-persistent-cd.rules примерно следующее содержимое:
    # _NEC_DVD_RW_ND-3550A (pci-0000:00:06.0-ide-0:0)
    ENV{ID_CDROM}==»?*», ENV{ID_PATH}==»pci-0000:00:06.0-ide0-0:0″, SYMLINK+=»cdrom», ENV{GENERATED}=»1″
    ENV{ID_CDROM}==»?*», ENV{ID_PATH}==»pci-0000:00:06.0-ide0-0:0″, SYMLINK+=»cdrw», ENV{GENERATED}=»1″
    ENV{ID_CDROM}==»?*», ENV{ID_PATH}==»pci-0000:00:06.0-ide0-0:0″, SYMLINK+=»dvd», ENV{GENERATED}=»1″
    ENV{ID_CDROM}==»?*», ENV{ID_PATH}==»pci-0000:00:06.0-ide0-0:0″, SYMLINK+=»dvdrw», ENV{GENERATED}=»1″
    Судя по комментарию, DVD-привод вроде бы даже и сам определился, и сам подправил конфиг, как надо… Вот только почему-то не работает оно как надо.
    Привод у меня /dev/hdc. Как узнать, какой адрес списывать вместо ENV?

    Да, ещё по поводу камеры. Если я вставлю сразу две камеры с ID_MODEL=»Samsung_Digital_Camera», а такое, как я понимаю, вполне возможно, что будет?

Обсуждение закрыто.