Стань повелителем загрузки Linux
Сначала мы познакомимся с udev и научимся с его помощью исследовать установленные в компьютере устройства прямо во время загрузки: в качестве примера будем автоматически выбирать настройки видеокарт для Xorg. Затем решим задачу работы с одним образом на десятках компьютеров одновременно путём внедрения собственного обработчика в initramfs, а заодно оптимизируем систему для сетевой загрузки. Чтобы дополнительно уменьшить время загрузки и снизить нагрузку на сеть попробуем NFS заменить на NBD, и помочь TFTP с помощью HTTP. В конце вернёмся в начало — к загрузочному серверу, который также переведём в режим «только для чтения».
Данная статья — скорее исследование, а не готовое руководство (все решения работают, просто они не всегда оптимальны). В конце у вас появится достаточно знаний, чтобы сделать всё так, как захотите именно вы.
Начало смотрите здесь:
Первоначальная настройка сервера
Подготовка образа для загрузки по сети
Мы остановились на том, что загрузили по сети машину VirtualBox и запустили Firefox. Если сейчас попытаться сделать то же самое с настоящим компьютером, то на экране появится циклическая авторизация пользователя username и безуспешные попытки запустить графическое окружение — Xorg не находит нужный драйвер.
Запускаем видеокарты
Для работы графического режима в VirtualBox у нас установлено всё необходимое. Изначально планировалось, что наша бездисковая система будет функционировать на любом «железе», но из-за лени мы не станем пытаться объять необъятное, поэтому ограничимся поддержкой графических решений следующих доминирующих производителей: nVidia, Intel и AMD.
Переключимся на машине-клиенте во второй терминал нажатием Ctrl+Alt+F2 и установим открытые драйверы:
Вероятнее всего, что на этот раз Xorg не сможет самостоятельно выбрать подходящие настройки для каждого случая, и судя по экрану загруженного клиента будет казаться, что вообще ничего не изменилось.
Простейший способ узнать какие видеоустройства имеются в системе, это ввести в консоли команду:
Но мы не будем искать лёгких путей, а в награду получим новую порцию знаний.
Ближе знакомимся с udev
Раньше я уже упоминал, что менеджер устройств в Archlinux называется udev. Он входит в пакет systemd под именем systemd-udevd.
По мере обнаружения новых устройств в загружаемой системе, ядро создаёт их иерархию в каталоге /devices. Сначала появляется сама система PCI, затем в ней обнаруживаются шины, на которых «сидят» конечные устройства, а их драйверы рассортировывают устройства по классам. Устройства внутри классов обнаруживаются параллельно, точно как systemd параллельно запускает службы для достижения следующей цели.
Асинхронный поиск устройств приводит к тому, что если в компьютере одновременно присутствует несколько устройств, относящихся к одному классу, то они могут обнаруживаться в разном порядке от включения к включению, например, сначала одна видеокарта, а потом — другая, и их имена при этом будут меняться между собой. К счастью, появление нового элемента в иерархии устройств является событием udev, которое можно отследить и принять необходимые меры.
Для менеджера udev придуманы правила, призванные упорядочить хаос, и упростить жизнь установленных программ. Правила хранятся в папках /usr/lib/udev/rules.d/ и /etc/udev/rules.d/ (последняя, как и в случае обработчиков (hooks), имеет более высокий приоритет и файлы оттуда проверяются первыми). Появление нового элемента в иерархии устройств сопровождается проверкой всех установленных правил udev, и автоматическим выполнением указанных там действий, в случае совпадения. Обычно эти действия заключаются в переименовании устройств и установки на них ссылок в каталогах внутри /dev и /sys для удобства использования в программах.
Драйверы видеокарт относят их к подсистеме (классу) drm, поэтому сведения о подобных устройствах дублируются в каталоге /sys/class/drm. Первая видеокарта, обнаруженная в системе, по-умолчанию получает имя «card0», если в ней имеется несколько видеовыходов, то они получают имена вида «card0-CON-n», где «CON» — тип разъема (VGA, HDMI, DVI и др.), а «n» — порядковый номер разъема (причём одни производители нумеруют разъёмы начиная с «0», а другие — с «1»). Следующая видеокарта становится “card1” и т. д.
Если ничего не предпринять, то в виду параллельности обнаружения при следующем включении card1 может стать card0 и наоборот. Udev станет добавлять такие устройства в /dev то с одним, то с другим именем. Случаи, когда такое поведение udev нежелательно, подробно описаны в Интернете, и в них в основном обсуждаются различные USB устройства. Нам же требуется при обнаружении видеокарт запускать определённую программу, которую напишем чуть позже, а пока выясним, что известно udev.
Чтобы узнать то же самое, что знает про видеокарту udev, введём команду на клиенте:
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device ‘/devices/pci0000:00/0000:00:02.0/drm/card0’:
KERNEL==«card0»
SUBSYSTEM==«drm»
DRIVER==»»
looking at parent device ‘/devices/pci0000:00’:
KERNELS==«pci0000:00»
SUBSYSTEMS==»»
DRIVERS==»»
Обратите внимание на древовидную структуру с использованием парадигмы родительских и дочерних устройств. В строках, начинающихся с «looking at . » указан путь к данному устройству относительно каталога /sys, т. е. обратившись к видеокарте по пути /sys/class/drm/card0, мы обнаружили, что на самом деле это ссылка на /sys/devices/pci0000:00/0000:00:02.0/drm/card0.
У родительского устройства /devices/pci0000:00/0000:00:02.0 есть атрибут vendor с идентификатором производителя. Udev располагает доступом к обширной базе данных и может перевести этот код в удобоваримый вид:
Сравните с выводом команды:
Динамическая настройка видеокарты с помощью udev
Подключитесь к загрузочному серверу. И создайте файл с правилами:
Каждое правило записывается в новой строке. Первая часть служит для идентификации события udev, к которому нужно применить действие, указанное в конце строки. Для опознания события используются данные, которые можно получить в выводе команды «udevadm info -a -p /sys. ».
Правило из первой строки срабатывает для всех устройств с именем (ядром) card0, card1… подсистемы drm. Второе правило сработает только для активных устройств из подсистемы drm, к которым в данный момент подключен монитор (оно не сработает для card0, card1, а только для имен вида card0-HDMI-1, т. к. только у таких устройств есть атрибуты enabled и status). При совпадении события с его описанием выполняется одна и та же программа, в которую в первом случае передаётся один параметр %n (порядковый номер ядра, который для card0 будет «0»), а во втором — дополнительный параметр %k (само имя ядра «card0»).
Программа /etc/default/xdevice будет изменять содержимое файла в папке /etc/X11/xorg.conf.d/, в котором содержится информация о настройках видеоадаптера для xorg. Для разных производителей мы подготовим разные шаблоны, учитывающие особенности реализации. Достаточно указать минимально необходимую информацию для однозначной идентификации устройства, а остальное xorg сделает сам:
Необходимые данные мы укажем в самом шаблоне или получим исследуя вывод команды «udevadm info».
Программа будет срабатывать для каждого выхода каждой видеокарты, к которому подключен монитор. Для упрощения задачи заставим работать последний обнаруженный вариант, чтобы на мультимониторных системах работал хотя бы один монитор. Это не самый оптимальный способ настройки, и было бы лучше проверить графическую подсистему один раз перед достижением graphical.target, но наш вариантрабочий и подходит для изучения правил udev в действии.
Создаём файл программы со следующим содержанием:
Сделаем файл исполняемым:
Отключаем автоматическую загрузку службы VirtualBox, т. к. теперь она будет запускаться нашей программой только при необходимости:
Добавляем шаблоны конфигурационных файлов xorg, с оптимизированными под основных производителей настройками:
Добавляйте свои шаблоны и не забывайте устанавливать драйверы для этих устройств. Укажите в комментариях проверенные комбинации.
В завершение настройки xorg сделаем ”Windows like” переключение раскладки клавиатуры комбинацией Alt+Shift:
Оптимизируем систему
Логи работы всех составляющих Archlinux сохраняются в журнале. Если всё оставить как есть, то журнал может довольно сильно раздуть, поэтому ограничим его размер, скажем 30Мб (добавьте или раскомментируйте строку):
Каждое действие протоколируется в папку /var/log/journal. В нашем случае передача данных осуществляется по сети, которая на практике имеет невысокую пропускную способность. Можно удалить папку с журналом, то он будет сохраняться только в оперативной памяти, что идеально подходит для бездискового клиента:
При различных ошибках в работе приложений в папке /var/lib/systemd/coredump создаются автоматические дампы ядра. Мы их отключим по той же причине:
Отключаем SWAP:
Удалим ненужные локализации. Это простое действие поможет сэкономить более 65 Мб. Заодно посмотрим, как устанавливаются программы из AUR (фактически они собираются из исходников). Зайдите на загрузочный сервер с правами обычного пользователя и выполните следующие действия:
Пакет готов. Устанавливаем его из файла, а не из репозитория, поэтому ключ S заменяется на U (исправьте название файла, если версия собранной вами програмы не совпадает с моей):
Теперь настроим. Закомментируйте строку «NEEDCONFIGFIRST» в начале файла и укажите используемые локализации в самом конце:
Конфигурируем и запускаем программу:
Переходим в read-only
Если мы попробуем загрузить существующую систему на нескольких компьютерах одновременно, то все копии будут изменять одни и те же папки на сервере. Если один клиент удалит какой-то файл, то он неожиданно исчезнет и у другого. Самый надежный способ защититься от изменений — перейти в режим только для чтения.
Проблема в том, что для нормальной работы системы необходима возможность записывать данные в некоторые папки. Решение на поверхности — подключить эти папки через fstab как tmpfs — замечательно подойдёт для /var/log, например. Но как поступить, например, с каталогом /etc, ведь наше правило udev меняет там файлы, да и другие программы активно с ним работают? Можно где-то сохранить информацию перед монтированием, а потом переписать обратно. Или сразу перенести всё куда-то ещё, а потом вернуть. Ясно одно: придётся долго тестировать и следить за работой системы, чтобы понять какие ещё папки сделать доступными для записи, или же настроить все программы так, чтобы они оставляли продукты своей жизнедеятельности строго в отведённом месте. Слишком мудрёно. Предлагаю всю систему развернуть в RAM. Останется только предварительно переписать в неё всё самое нужное для работы.
Существует одна папка, в которую во время работы ничего не записывается, если мы ничего не устанавливаем — это /usr. Если подмонтировать её на позднем этапе работы initramfs с доступом только для чтения, то на работу Firefox это никак не повлияет. Обязательно сравните размер каталога /usr с размером всего остального, и получится, что копировать останется не так много, а если при этом исключить всё лишнее… Вы тоже подумали о rsync?
Переделываем файловую систему на лету
Устанавливаем rsync на клиента:
Заниматься копированием предстоит на этапе работы intramfs, следовательно, понадобится новый обработчик, назовём его «live». Сначала сохраним все необходимые параметры монтирования оригинального корневого каталога, путём анализа файла /etc/fstab с помощью утилиты findmnt. Затем корневой каталог отмонтируем от папки /new_root, где он всегда находится внутри initramfs. На его месте создадим ramfs с возможностью записи и подготовим точку монтирования /srv/new_root, куда вернём оригинальный корневой каталог. Останется только переписать все самые нужные файлы и каталоги, за исключением папки /usr, которую забиндим в режиме только для чтения. Копии файлов в ramfs будут доступны для чтения и для записи.
К файлу /etc/fstab мы обращаемся дважды: первый раз получаем информацию по параметрам монтирования корневого каталога, а второй раз проверяем, есть ли в fstab какая-нибудь информация по /usr. Для позднего монтирования /usr в Archlinux есть специальный обработчик usr, которому мы не будем мешать выполнять свою работу. Если /usr монтируется каким-то особым образом, то наш обработчик его пропускает.
В тексте упомянут файл /etc/default/live_filter с правилами фильтрации, предназначенными для rsync, нам нужно не забыть его подготовить. Сделаем это автоматически из установщика обработчика:
Rsync «не видит» дальше одной директории. Файлы и папки в директории проверяются каждым правилом по порядку до первого совпадения («+» — объект копируется, «-» — объект не копируется). Если совпадений нет, то файл копируется, а директория создаётся пустой. Далее rsync заходит в «выжившую» директорию и снова применяет правила к её содержимому. Так повторяется до тех пор пока совсем ничего не останется.
В нашем случае корневой каталог не попадает ни под одно правило, поэтому его структура полностью переносится (копируются все файлы и создаются пустые каталоги). Каталоги /boot, /dev, /lost+found, /mnt, /opt, /proc, /root, /run, /srv, /sys, /tmp попадают под действие последнего правила «- /*/*», т.е. никакое их содержимое никуда не копируется, но сами они создаются. Каталог /etc сразу же попадает под правило «+ /etc/*», и всё его содержимое копируется, но сначала только в пределах одного каталога (в дальнейшем вся его структура будет перенесена по порядку, потому что для уровней вложенности /etc/*/ и далее никаких правил нет). Похожее начало ждёт каталог /home — папки всех пользователей попадают под правило «+ /home/*» и будут воссозданы в копии (пока пустыми). Следующее правило «+ /home/*/.config» копирует каталоги .config, вложенные в домашние папки каждого из пользователей, а «- /home/*/*/» исключает все остальные каталоги (правило идёт после «спасательного», поэтому для /home/*/.config не срабатывает). Про сами файлы из домашнего каталога ничего не говорится, поэтому они полностью переносятся. Файлы из исключённых вложенных каталогов не копируются, потому что эти каталоги не были созданы. Правило «- /var/cache/*/*» сохраняет всю структуру каталогов в /var/cache, но их содержимое не переносится. Остальные правила действуют аналогичным образом.
Правила для rsync, находящиеся во внешнем файле /etc/default/live_filter, вы можете менять по своему усмотрению без необходимости заново создавать initramfs. Буду рад увидеть ваш вариант правил в комментариях.
Возможностей у rsync очень много (man rsync — почти 3000 строк). Предложите в комментариях какой-нибудь экзотический способ использования rsync внутри initramfs?
Теоретически rsync можно заменить на какой-нибудь torrent, и собирать корневую файловую систему с его помощью.
Добавляем обработчик в initramfs:
Сервер и клиент работают в VirtualBox.
Исходная файловая система:
Состояние файловой системы на загруженном клиенте после выполнения обработчика live:
Во время загрузки клиента на сервере были собраны следующие данные:
Разгоняем сеть
Физически, естественно, разгон сети сейчас невозможен без замены оборудования, зато программные оптимизации не запрещаются. Нам нужно передавать содержимое связанной папки /usr по сети. Не отправлять эти данные мы не можем, зато способны уменьшить объём занимаемого ими места — заархивировать. На сервере сжимаем, а на клиенте — распаковываем, и через ту же самую сеть теоретически передаётся больше данных за единицу времени.
Файловая система squashfs совмещает в себе возможности архиватора и монтирования архивов через fstab, как обычную файловую систему. Основной недостаток данной файловой системы — невозможность работать в режиме записи (только для чтения) — для нас недостатком не является:
Монтировать будем так:
На позднем этапе работы initramfs монтированием папки /usr занимается обработчик usr, который нужно немного подправить:
Нужно, чтобы строка монтирования выглядела так:
Исходная файловая система:
Состояние файловой системы на загруженном клиенте после выполнения обработчиков live и usr:
Во время загрузки клиента на сервере были собраны следующие данные:
Данных пришлось передать примерно на 20% меньше, чем в предыдущий раз. Можно упаковать весь корневой каталог в один файл, тогда обработчик live для заполнения ramfs будет забирать с сервера данные в сжатом виде.
Можно скопировать файл /srv/source_usr.sfs в ramfs поменяв правила в фильтре rsync, а потом примонтировать его через fstab из нового места, и, когда вся система целиком окажется в RAM, попробовать отключиться от загрузочного сервера.
Убираем лишнее
Если вы заглядывали сюда, то у вас не возникнет вопрос: «Как мы будем отдавать с сервера файл?». Можно, конечно, передавать данные squashfs посредством NFS (что и происходило выше), но существует менее документированное решение Network Block Device, с которым можно работать как с обычным диском. Поскольку это «блочное устройство», а не «файловая система», мы можем использовать на нём любую файловую систему с возможностью сжатия данных. Для доступа на чтение и запись подойдёт btrfs с архивацией zlib, но нам не нужна запись и squashfs вполне устраивает.
Чтобы из initramfs можно было подключиться к NBD-серверу при загрузке понадобится скачать из AUR пакет mkinitcpio-nbd (нужно скачивать и собирать с правами обычного пользователя):
Добавляем в конец файла $root/boot/grub/grub.cfg новый пункт меню:
Как видите, поменялась только одна строчка:
После подключения к NBD серверу в клиенте появляется блочное устройство с именем /dev/nbd0, поэтому поступаем с ним как с обычным диском:
В последних версиях NBD сервера появилась непрятная особенность (скорее всего это баг). Когда клиент NBD устанавливает соединение с сервером, а потом внезапно выключается не завершая соединение корректно, и оно продолжает «болтаться» на сервере в виде незавершенного процесса. Если клиент во время загрузки попробует подключиться к NBD заново, то есть вероятность, что сервер не станет создавать новое соедиенение считая старое активным. Предлагаю непосредственно перед подключением к NBD отправлять свой IP адрес через netcat на сервер, чтобы тот закрыл старые подключения, связанные с этим IP адресом:
Нужно отредактировать только один файл. Вставьте между строками следующий фрагмент:
В initramfs сетью по-прежнему заведует наш модифицированный net_nfs4, после которого вставляем nbd:
Перед выполнением следующей команды удалите или переместите файл $root/srv/source_usr.sfs за пределы $root — не имеет смысла помещать архив /usr внутрь архива, содержащего оригинал /usr:
Переходим к настройке сервера
Настраиваем NBD сервер:
Всё достаточно просто. Мы создаём шару с именем habrahabr, ссылаемся на наш файл, устанавливаем таймаут соединения, раздаём в режиме «только для чтения», отдаём только один файл и функция copyonwrite нам не нужна. Copyonwrite позволяет использовать одну и ту же раздачу несколькими клиентами одновременно, при этом каждому клиенту создаётся отдельный файл, куда будут записываться все произведённые им изменения оригинального файла. После отключения клиента файлы с изменениями удаляются автоматически. Использование этой функции замедляет сервер. Информации по NBD в интернете не так много, но man’ы решают.
Проверять и завершать процессы, связанные с незакрытыми соединениями будет вот этот файл:
Файл делаем исполняемым:
Устанавливаем пакеты, в которых находятся утилиты netcat и netstat:
Модифицируем запуск службы NBD:
Возможно, выбрано не самое изящное решение, но оно достаточно понятно и замечательно работает.
Исходная файловая система:
Состояние файловой системы на загруженном клиенте после выполнения обработчиков live и usr:
Во время загрузки клиента на сервере были получены следующие данные:
На этот раз мы сэкономили ещё всего лишь 3% трафика (в пределах погрешности). Разница во времени загрузки объясняется тем, что при использовании NFS перед подключением к серверу делается принудительная пауза в 10 секунд, а в случае сервера NBD такой задержки нет.
Педаль в пол
Давайте попробуем ускорить загрузку. Самое слабое звено в нашей цепочке загрузки — TFTP сервер. Полностью исключить его мы не сможем, но минимизировать его присутствие можно с помощью загрузчика iPXE, как посоветовал kvaps в комментариях к предыдущей статье.
Подключитесь к загрузочному серверу под именем username.
Меню с вариантами загрузки мы делать не будем, а автоматически загрузимся в самый быстрый на текущий момент:
Мы планируем получать файлы vmlinuz-linux и initramfs по протоколу HTTP. Внедрим наш скрипт в загрузчик:
Возвращаемся в root на сервере и копируем загрузчик:
Исправим DHCP сервер таким образом, чтобы он предлагал скачивать новый файл:
Устанавливаем HTTP сервер:
привязываем папку с загрузчиком к рабочей папки сервера:
Можно перемонтировать в режим «только для чтения»:
Смотрим, что происходит на сервере:
Выигрыш в скорости загрузки от замены TFTP на HTTP заметен невооружённым глазом и это не единственный примечательный момент iPXE. Например, здесь показано, как можно прямо во время загрузки выбрать сервер с официальным образом установочной флешки и загрузиться в него прямо через Интернет без необходимости предварительного скачивания. Уверен, что теперь вы сможете повторить то же самое и со своим образом.
Возвращаемся на сервер
Попробуйте добавить обработчик live в наш загрузочный сервер. Сейчас правила rsync пропускают копирование содержимого /srv, где у нас находятся файлы клиента. Мы можем поменять правила или примонтировать директорию с помощью systemd:
В данном случае папки /srv/new_root/srv и /srv связываются в режиме полного доступа на чтение и запись, но мы знаем решения.
Тот факт, что загрузочный сервер может работать в режиме «только для чтения», будет весьма полезен для систем, установленных на недорогую USB флешку. С такого накопителя лучше побольше читать, и поменьше на него записывать. Если вы откроете его в интернет, то получите дополнительную степень защиты. Например, роутер открывает защищенный VPN канал, на другом конце которого находится загрузочный сервер…
Чтобы переписать систему на флешку (с жёстким диском принцип тот же самый), её нужно вставить в компьютер и подключить к VirtualBox (Меню Устройства > Устройства USB и выбрать нужную из списка). Список доступных блочных устройств проверяется командой lsblk, как в самой первой статье. Разметьте флешку пометив загрузочной, отформатируйте с той же меткой HABR и примонтируйте к /mnt.
Создадим новый файл с правилами для rsync:
Дождитесь выполнения команды:
В моём случае флешка — /dev/sdb
Остаётся отмонтировать /mnt и можно загружаться из копии.
PS Решение разрабатывалось для автоматизации компьютерных классов. Система одинаково работает на пожертвованных и новых компьютерах с самыми разнообразными конфигурациями. Восстановление системы на клиенте к первоначальному состоянию производится обычной перезагрузкой. Нужные данные можно сохранять на диске загрузочного сервера или на любом другом сетевом или локальном накопителе.
udev/ru
Warning: Display title «udev/ru» overrides earlier display title «udev».
Not to be confused with eudev.
udev (user /dev ) это менеджер устройств из systemd для ядра Linux. Он управляет файлами устройств в каталоге /dev и обрабатывает все действия из пользовательского пространства при добавлении или удалении устройств.
The sys-fs/udev package is used as the default device manager for Gentoo systems using the OpenRC init system, independently of systemd.
Содержание
Что такое udev?
Каталог /dev
Большинство пользователей Linux знают, что /dev/sda1 это простой способ сослаться на первый раздел на первом, обнаруженным ядром, диске. Это довольно просто, не так ли?
Представим себе устройства «горячей замены» вроде USB, IEEE 1394, PCI с возможностью горячей замены и так далее. Какое из них является первым по счету? Надолго ли? Как изменятся названия других устройств, если первое отключить? Как это повлияет на текущие операции? Было бы забавно, если бы задание печати вдруг переключалось с вашего супер навороченного лазерного принтера на старый полудохлый матричный принтер из-за того, что кто-то решил выдернуть разъем лазерного принтера, который, по счастью, оказался первым принтером?
Обзор диспетчера устройств. Современный диспетчер устройств (включая udev и eudev ) должен уметь:
- запуск в пользовательском пространстве.
- динамически создавать и удалять файлы устройств.
- предоставлять согласованное назначение имен устройств.
- предоставлять (API) для программ работающих в пространстве пользователя.
Каждая раз, когда в структуре устройств появляется изменение, ядро генерирует uevent, который ловится диспетчером устройств ( eudev , udev ). Затем диспетчер устройств следует правилам, которые определены в каталогах /etc/udev/rules.d , /run/udev/rules.d и /lib/udev/rules.d . На основании информации из uevent, он находит правило или правила, которые он должен вызвать, и выполняет необходимые действия. Эти действия могут заключаться в создании или удалении файлов устройств, но могут и загружать нужные файлы прошивки в память ядра.
Установка
Для udev требуется включить следующие параметры ядра:
USE-флаги
Portage знает о глобальном udev USE-флаге для включения поддержки udev в остальных пакетах. Добавьте этот USE-флаг в список USE-флагов (он включен по умолчанию для всех Linux профилях) приведет к тому, что пакет sys-fs/udev автоматически установится:
Настройка udev rules в Linux
Начнём с небольшого введения для новичков. Философия Unix гласит, что всё есть файл. Таким образом, файлы в Unix — это не только информация, хранимая на жёстком диске, но и устройства. Да, в Linux жёсткий диск, мышь, клавиатура, флешка, сетевой адаптер и другие устройства имеют свои файлы, с помощью которых с ними и взаимодействуют различные системные программы.
Все файлы устройств хранятся в каталоге /dev. Этот каталог генерируется во время загрузки специальным сервисом — udev. Происходит это на основе подключённых к компьютеру устройств и определённых правил. По умолчанию в udev уже заложены все необходимые для нормальной работы устройств правила. Но некоторые пользователи хотят самим настраивать устройства и выбирать им имена и права доступа. Кроме того, понимание процесса генерации файлов устройств даёт возможность глубже понять работу операционной системы.
Правила udev помогут вам, если вы хотите:
- переименовать устройство, например жёсткий диск или сетевую карту;
- создать дополнительное имя для устройства;
- поменять права доступа к устройству;
- установить владельца и группу;
- выполнить скрипт при подключении или отключении устройства.
Общая информация про udev
Правила udev хранятся в папке /etc/udev/rules.d. Файл правил обязательно должен иметь расширение .rules. Обычно в этой папке уже есть несколько файлов udev rules, но их трогать не рекомендуется, для своих правил лучше создать отдельный файл, например:
Правило udev состоит из нескольких пар ключ — значение, разделённых запятой. Одни ключи используются для проверки соответствия устройства определённому правилу. В таких ключах используется знак == для разделения пары, например: SUBSYSTEM == «block». Это значит, что правило будет применено, только если значение ключа SUBSYSTEM для этого устройства равно block. Другие ключи используются для указания действия, если все условия соответствия выполняются. Для разделения пар в таких ключах используется знак равно » mydisk». Ну и полностью правило:
SUBSYSTEM==»block», ATTR(size)==»1343153213″, NAME=»mydisk»
Это правило выполниться только для устройства подсистемы block и с размером 1343153213 байт. Откуда брать эти значения, мы рассмотрим ниже, а пока разберёмся, что же значат те или иные ключи. Сначала ключи соответствия:
- SUBSYSTEM — подсистема устройства;
- KERNEL — имя, выдаваемое устройству ядром;
- DRIVER — драйвер, обслуживающий устройство;
- ATTR — sysfs-атрибут устройства;
- SUBSYSTEMS — подсистема родительского устройства.
Устройство может иметь родительские устройства, например, жёсткий диск имеет родительское устройство SSCI, которое в свою очередь имеет родительское устройство — шину BUS. Иногда необходимо получить информацию от родительского устройства. Для этого используются ключи SUBSYSTEMS, KERNELS, DRIVERS, ATTRS соответственно.
Для действий используются ключи:
- NAME — установить имя файла устройства;
- SYMLINK — альтернативное имя устройства;
- RUN — выполнить скрипт при подключении устройства;
- GROUP — группа, у которой есть доступ к файлу;
- OWNER — владелец файла устройства;
- MODE — маска прав доступа.
Рассмотрим подробнее ключ ATTR. Он позволяет получить информацию об устройстве, доступную в sysfs. Например, ATTR
udevadm info -a -n sda1
Опция -n задаёт имя устройства, -p — путь в sysfs. Например, то же самое получим, если выполнить:
udevadm info -a -p /sys/block/sda/sda1
Как переименовать устройство в Linux
Теперь на основе полученной из udevadm информации можем составить udev rules для добавления альтернативного имени диска:
SUBSYSTEM==»block», ATTR
Или смены названия:
SUBSYSTEM==»block», ATTR
Получим устройство /dev/root, которое будет указывать на корневой раздел (sda1), то же самое можно сделать для привода оптических дисков:
udevadm info -a -p /sys/block/sr0
Затем добавляем правило на основе модели:
SUBSYSTEM==»block», ATTRS
После перезагрузки появится файл устройства /dev/cdrom. Хотя, конечно, это можно сделать без udev, прописав в автозагрузку команду создания символической ссылки:
ln -s /dev/sr0 /dev/cdrom
Как переименовать сетевую карту
Настройка udev Linux на этом не заканчивается. Сетевая карта — тоже устройство и тоже управляется udev. Файлы сетевых устройств хранятся в /sys/class/net. Поэтому получаем информацию о ней с помощью udevadm:
udevadm info -a -p /sys/class/net/enp24s0
И создаём правило, например на основе mac-адреса:
SUBSYSTEM==»net», ATTR
==»00:d8:61:16:a5:a5″, NAME=»eth0″Перезагружаем компьютер, и теперь устройство называется eth0.
Как запустить скрипт при подключении устройства
Например, мы хотим автоматически скопировать все данные с флешки при её подключении к компьютеру. Мы знаем, что флешка будет называться /dev/sdb, тогда можно создать правило udev такого вида:
При подключении флешки выполнится скрипт /usr/bin/my_script и сделает необходимые действия. Нужно заметить, что скрипт не должен выполняться слишком долго, так как udev остановится и будет ожидать завершения его работы.
Отладка правил
Если вы не уверены, правильно ли составлено правило, можно воспользоваться командой udevadm test для проверки. В единственном параметре нужно передать путь sysfs-устройства. Например, проверим наше правило для жёсткого диска:
udevadm test /sys/block/sda
Среди многочисленного вывода видим строчку:
creating link ‘/dev/root’ to ‘/dev/sda’
Значит всё работает, и настройка udev выполнена успешно. Если же в правиле допустить синтаксическую ошибку, например UBSYSTEM вместо SUBSYSTEM, udevadm test выдаст что-то подобное:
read rules file: /etc/udev/rules.d/10-local.rules
unknown key ‘UBSYSTEM’ in /etc/udev/rules.d/10-local.rules:2
invalid rule ‘/etc/udev/rules.d/10-local.rules:2’
Здесь мы видим саму причину ошибки, неверный ключ, а также файл и строку, в которой допущена ошибка.
Выводы
На этом всё. Теперь вы знаете, как создать правило udev и взять под полный контроль все ваши устройства. Если нужна более подробная информация по созданию и использованию правил udev, читайте официальную документацию по udev в man.
Правила UDEV
Последнюю версию этого документа можно найти по адресу:
Содержание
- Введение
Введение
Об этом документе
udev предназначен для Linux ядер 2.6 и последующих за ними. Обеспечивает управление из пространства пользователя динамическим каталогом /dev с устойчивым наименованием устройств (устойчивый означает, что наименование не меняется после перезагрузки системы или переподключения устройства). Предыдущее решение для /dev , так называемое devfs, сегодня устарело, и похоже, что udev всех победило. udev против devfs — это весьма болезненная область споров и вам следует прочитать этот документ прежде чем проводить сравнения.
За прошедшие годы поменялось то, для чего вы может быть использовали правила udev, так же как и гибкость самих правил. На современных системах udev обеспечивает устойчивое наименование некоторых типов устройств прямо из коробки, исключая необходимость создания собственных правил для таких устройств. Однако, некоторым пользователям всё ещё требуется некоторый дополнительный уровень собственной донастройки.
Этот документ предполагает, что udev установлен и запущен в конфигурации, которая предлагается по умолчанию. Это обычно обеспечивает ваш дистрибутив Linux.
Этот документ не описывает каждую деталь того, как писать правила, целью является дать представление об основных концепциях. Все уточнения можно найти на страницах «man udev».
Этот документ даёт множестов примеров (многие из которых полностью придуманы) для иллюстрации идеи и концепций. В комментариях к строкам правил объясняется не весь синтаксис, удостоверьтесь, что вы изучили до полного понимания сами правила приведённые в примерах.
История
- April 5th 2008 v0.74: Typo fixes.
- December 3rd 2007 v0.73: Update for new udev versions, and some miscellaneous improvements.
- October 2nd 2006 v0.72: Fixed a typo in one of the example rules.
- June 10th 2006 v0.71: Misc changes based on recent feedback — thanks!
- June 3rd 2006 v0.7: Complete rework, to be more suited for the modern-day udev.
- May 9th 2005 v0.6: Misc updates, including information about udevinfo, groups and permissions, logging, and udevtest.
- June 20th 2004 v0.55: Added info on multiple symlinks, and some minor changes/updates.
- April 26th 2004 v0.54: Added some Debian info. Minor corrections. Re-reverted information about what to call your rule file. Added info about naming network interfaces.
- April 15th 2004 v0.53: Minor corrections. Added info about NAME
. Added info about other udevinfo tricks. - April 14th 2004 v0.52: Reverted to suggesting using «udev.rules» until the udev defaults allow for other files. Minor work.
- April 6th 2004 v0.51: I now write suggest users to use their own «local.rules» file rather than prepending «udev.rules».
- April 3rd 2004 v0.5: Minor cleanups and preparations for possible inclusion in the udev distribution.
- March 20th 2004 v0.4: General improvements, clarifications, and cleanups. Added more information about writing rules for usb-storage.
- February 23rd 2004 v0.3: Rewrote some parts to emphasise how sysfs naming works, and how it can be matched. Updated rule-writing parts to represent udev 018s new SYSFS
naming scheme. Improved sectioning, and clarified many points. Added info about KDE. - February 18th 2004 v0.2: Fixed a small omission in an example. Updated section on identifying mass-storage devices. Updated section on nvidia.
- February 15th 2004 v0.1: Initial publication.
Концепции
Терминология: devfs, sysfs, nodes, etc.
Это всего лишь общее введение. Может быть не во всех частях полностью точное.
На обычных Linux-системах каталог /dev содержит похожие на файлы узлы(nodes) устройств, которые ссылаются на конкретные устройства в системе. Каждый узел указывает на часть системы (на устройство), которое может присутствовать, а может и нет. Приложения из пространства пользователя могут использовать эти узлы устройства для взаимодействия с оборудованием системы. Например, X сервер слушает /dev/input/mice и может соотнести физические перемещения мыши с позиционированием мышиного курсора на экране.
Исходно каталоги /dev наполнялись узлами каждого устройства, которое могло бы стать частью системы. По этой причине каталоги /dev обычно были очень большими. devfs пошла дальше, чтобы дать более управляемую систему (отличием было то, что она наполняла /dev устройствами, которые подключены к системе), а также и некоторую дополнительную функциональность. Однако эта система доказала, что в ней есть не очень-то легко решаемые проблемы.
udev — это новый способ управления каталогами /dev, созданный для того, чтобы избавиться от некоторых проблем предыдущих решений для /dev, и чтобы обеспечить гибкость в будущем развитии. Для создания узлов устройств и их имён в /dev, которые соответствовали ли бы устройствам, присутствующим в системе, udev полагается на соответствие между информацией, которая присутствует в sysfs, и правилами, заданных пользователем. Цель этого документа — детализировать процесс написания правил. Это одна из задач, относящаяся к udev, которую быть может придётся выполнять самому пользователю.
sysfs это новая файловая система в ядрах 2.6. Она управляется ядром и экспортирует основную информацию об устройствах, которые в текущий момен подключены в вашу систему. udev может использовать эту информацию для создания узлов устройств, соответствующих вашему оборудованию. sysfs монтирована в каталог /sys и доступна для просмотра. Вы можете поизучать некоторые из хранящихся там файлов до того, как вплотную приступить к udev. В этом документе термины /sys и sysfs полностью взаимозаменяемы.
Зачем?
Правила udev очень гибкие и очень мощные. Вот несколько вещей, которые вы можете достичь используя правила udev:
- Сменить имя по умолчанию для узла устройства на что-нибудь другое.
- Задать альтернативное/устойчивое имя для узла устройства созданием сиволического линка на узел, который был создан по умолчанию
- Присвоить имя узлу устройства на основе вывода, получаемого от программы.
- Сменить права и владельца узла устройства
- Запустить скрипт в момент когда узел устройства создаётся или удаляется (обычно в моменты подключения или отключения устройства)
- Переименование сетевых интерфейсов
Написанием правил не решить проблему, когда для вашего конкретного устройства нет узла этого устройства.
Даже если нет соответствующего правила, udev создаст узел устройства с именем по умолчанию, которое будет получено от ядра.
Иметь устойчивые наименования для узлов устройст имеет свои преимущества. Предположим, что у вас есть 2 USB устройства-накопителя: цифровая камера и USB-флэш диск. Эти устройства обычно получают узлы с именами /dev/sda и /dev/sdb, но наименование зависит от того, в каком порядке вы они были подключены в систему. Это может стать проблемой для некоторых пользователей, которые очень сильно выиграют, если устройства будут всегда именоваться устойчиво, например /dev/camera и /dev/flashdisk.
Встроенные устойчивые схемы наименований
udev обеспечивает устойчивое наименование для некоторых типов устройств прямо из коробки. Это очень полезное свойство и во многих случаях это означает, что ваше путешествие прямо здесь и заканчивается: вам вообще не требуется писать хоть какое-либо правило.
udev обеспечивает прямо-из-коробки устойчивое наименование устройств хранения данных в каталоге /dev/disk. Чтобы увидеть устойчивые имена, которые были сделаны для ваших устройств хранения данных, используйте следующую команду:
Это работает для всех типов устройст хранения данных. Например, udev создал /dev/disk/by-id/scsi-SATA_ST3120827AS_4MS1NDXZ-part3, что является устойчивым именем символического линка к моему корневому разделу. udev создаёт /dev/disk/by-id/usb-Prolific_Technology_Inc._USB_Mass_Storage_Device-part1, когда я втыкаю свой USB флэш диск. И это также устойчивое имя.
Написание правил
Файлы правил и семантики
Чтобы дать имя устройству и быть может произвести дополнительные действия, udev читает последовательно файлы с правилами. Эти файлы содержатся в каталоге /etc/udev/rules.d, и должны иметь суффикс .rules .
Правила по умолчанию для udev хранятся в /etc/udev/rules.d/50-udev.rules. Вам может показаться интерестным взглянуть на этот файл — он содержит несколько примеров, и затем несколько правил по умолчанию, которые структурируют содержимое каталога /dev в стиле devfs. Однако вам не следует записывать правила напрямую в этот файл.
Файлы в /etc/udev/rules.d/ обрабатываются в алфавитном порядке, и в ряде случаем порядок, в котором разбираются правила может быть важным. Обычно вы хотите, чтобы ваши собственные правила обрабатывались до правил по умолчанию, так что, я советую создать файл /etc/udev/rules.d/10-local.rules и вписывать все свои правила в него.
В файлах правил строки, начинающиеся с «#» трактуются как комментарии. Каждая непустая строка — это правило. Правила не могут занимать более одной строки.
Одному устройству может соответствовать более одного правила. Удобство состоит в том, что, например, мы можем написать два правила, соответствующих одному и тому же устройству, и каждое правило обеспечит своё собственное альтернативное имя для устройства. Оба альтернативных имени будут созданы, даже если правила находятся в разных файлах. Важно понять, что udev не заканчивает обработку после нахождения подходящего, а продолжит просмотр и применит каждое правило, которое подходит.
Синтаксис правил
Каждое правило состоит из серии пар «ключ»-«значение», которые разделены запятой. ключи соответствия — это условия, которые используются для идентификации устройства, на которое действует правило. Когда все ключи соответствия правила соответствуют обрабатываемому устройству, правило применяется и производится действие, которое задано ключамиприсвоения. Каждое правило состоит как минимум из одного ключа соответствия и одного присвоения.
Вот пример правила для иллюстрации вышесказанного:
Приведённое правило содержит один ключ соответствия (KERNEL) и один присвоения (NAME). Семантика этих ключей и их свойства будут обсуждены в деталях позже. Важно заметить, что ключ соответствия связан со своим значением оператором сравнения на равенство (==), в то время как присваивающий ключ связан со своим значением оператором присваивания (=).
Знайте, что udev не поддерживает никаких продолжений строк. Не вставляйте переводы строк в ваши правила, так как это заставит udev рассматривать ваше одно правило как несколько правил и это точно не сработает так, как вы хотели бы.
Базовые правила
udev даёт несколько ключей соответствия, которые можно использовать при написании правил, и по которым очень точно устанавливается соответствие с устройством. Некоторые из наиболее общих ключей представлены ниже, остальные будут представлены в этом документе позднее. Чтобы увидеть полный список, читайте страницы манов по udev.
- KERNEL — соответствие с именем устройства в ядре
- SUBSYSTEM — соответствие с подсистемой устройства
- DRIVER — соответствие с именем драйвера, обслуживающего устройство
После того, как вы использовали список ключей соответствия, чтобы точно определить устройство, udev позволяет вам удобно управлять тем, что делать далее с помощью набора присваивающих ключей. Чтобы увидеть полный список возможных присваивающих ключей, читайте маны udev. Наиболее общие присваивающие ключи представлены ниже. Остальные будут представлены в этом документе позднее.
- NAME — имя, которое будет использовано для узла устройства
- SYMLINK — список символических линков, которые действуют как альтернативные имена для узла устройства
Как можно догадаться из вышесказанного, udev создаёт один реальный узел для одного устройства. Есил вы хотите иметь ещё альтернативные имена для этого узла, используйте возможность создания символических линков. С помощью SYMLINK, вы действительно поддерживаете список символических линков, каждый из которых указывает на реальный узел устройства. Для манипуляций этими линками используйте другой оператор, которым можно добавлять что-то в списки: +=. Вы можете добавлять в любом правиле несколько символических линков в список, разделяя каждое добавление пробелом.
Вышенаписанное правило гласит: при обнаружении устройства, которое имеет в ядре имя hdb, вместо того, чтобы назвать его hdb, дать имя узлу устройства my_spare_disk. В результате узел устройства будет появится как /dev/my_spare_disk.
Вышенаписанное правило гласит: при обнаружении устройства, которое имеет имя в ядре как hdb И для которого драйвер называется ide-disk, дать имя устройству по умолчанию и создать символический линк с именем sparedisk. Замечу, поскольку мы не указали имя устройства, udev использует имя по умолчанию. Чтобы сохранить стандартное содержимое /dev, наши собственные правила обычно не включают в себя NAME, а создают несколько SYMLINK-ов и/или делают другие присвоения.
Вышеприведённое правило наверное более похоже на правила, которые вы может быть пишите. Оно создаёт два символьных линка /dev/cdrom и /dev/cdrom0, каждый из которых указывает на /dev/hdc. Опять же , присвоения NAME не указано, так что, будет использовано имя по умолчанию из ядра (hdc).
Соответствие с аттрибутами sysfs
Такое описание ключей соответствия, какое было дано, имеет весьма ограниченные возможности поиска по соответствию. В жизни нам нужен существенно лучший контроль: нам надо идентифицировать устройства по большему числу свойств, таких как коды поставщиков (vendor code), точный номер продукта(product number), серийные номера, объём ресурса хранения, номер раздела, и т.д.
Многие драйвера экспортируют подобную информацию в sysfs, а udev позволяет нам включить в наши правила поиск соответствия с данными sysfs. Для этого используется ключ ATTR, у которого немного другой синтаксис.
Вот пример правила, в котором ищется соответствие с одним из аттрибутом из sysfs. Далее в документе будут дополнительные подробности, которые помогут вам в написании правил, базирующихся на аттрибутах из sysfs.
Иерархия для устройств
Ядро Linux сегодня представляет нам устройства в виде деревообразных структур, и эта информация выдаётся через sysfs и может быть использована при написании правил. Например, мой жёсткий диск представлен как потомок от SCSI-диска , который в свою очередь является потомком Serial ATA контроллера, который в свою очередь потомок PCI-шины. Найти ту информацию, что вам нужна, вы вероятно сможете у родительского устройства, например, серийный номер моего жёсткого диска не представлен на уровне диска, а представлен в его прямом родителе на уровне SCSI-диска.
Четыре главных ключа соответствия, описанных далее (KERNEL/SUBSYSTEM/DRIVER/ATTR) соответствуют только значениям, которые указаны в запросе для устройства и не соответствуют значениям от родительских устройств. udev позволяет писать варианты ключей соответствия, которые будут просматривать дерево вверх.
- KERNELS — поиск соответствия по имени устройства из ядра, или по имени из ядра любого устройства-родителя.
- SUBSYSTEMS — поиск соответствия по подсиcтеме устройства, или по подсистеме любого устройства-родителя
- DRIVERS — поиск по имени драйвера для устройства, или по имени драйвера любого устройства-родителя
- ATTRS — поиск соответствия по аттрибуту устройства в sysfs, или по аттрибуту sysfs любого устройства-родителя
Зная эти иерархические соглашения, вам может показаться, что написание правил слегка сложновато. В дальнейшем вы убедитесь, что существуют средства, которые облегчат вашу работу. О них будет рассказано далее.
Подстановка строк
При написании правил, которые обслуживают несколько схожих устройств, оказываются очень полезны операторы подстановки строк, схожие с printf. Вы можете просто вставить эти операторы в любое присвоение, которое делается вашим правилом, а udev во время выполнения выполнит подстановку.
Наиболее общими операторы — это %k и %n. %k заменяется именем устройства из ядра, например , «sda3» для устройства, которое появится по умолчанию как /dev/sda3. %n заменяется номером для устройства из ядра (для устройств хранения данных это номер раздела), например, «3» для /dev/sda3.
Для расширения функциональности udev такде предоставляет дополнительные подстановки. Проконсультируйтесь со страницами man для udev после прочтения оставшейся части этого документа. Для этих операторов, которые выше приведены в примерах, есть альтернативный синтаксис — $kernel и $number. В случаях, когда в правиле вам необходимо указать соответствие с символом %, следует писать %%, а для символа $ следует писать $$.
Для иллюстрации концепции подстановки строк, посмотрите на следующие правила:
Первое правило заставляет создать узел устройства для мыши только в каталоге /dev/input (по умолчанию он должен был бы быть /dev/mice). Второе правило создаёт узел для устройства с именем loop0 как /dev/loop/0, и так же создаёт символический линк /dev/loop0, что является обычным именем для этого устройства.
Использование вышеприведённых правил весьма спорно, поскольку их можно переписать и без использования операторов подстановки. Настоящая мощь этих подстановок станет очевидной в следующей части.
Поиск совпадений строк
udev позволяет искать как точные совпадения строк, так и сравнение по образцу, как в шелле. Поддерживаются 3 образца:
- * — отождествляется с любым символом, от 0 и более раз
- ? — отождествляется с одним символом, ровно с одним
- [] — отождествляется с любым одиночным символом, указанным в квадратных скобках, позволяется указывать диапазон символов
Вот несколько примеров, которые включают в себя указанные образцы. Обратите внимание на операторы подстановки строк.
Первое правило соответствует всем флоппи-дисководам, и обеспечивает размещение узлов устройств в каталоге /dev/floppy, также как и создание символического линка с именем, которое должно было бы быть по умолчанию. Второе правило обеспечивает то, что устройства hiddev будут присутствовать только в каталоге /dev/usb.
Нахождение информации в sysfs
Дерево sysfs
Мы раньше уже немного затронули идею получения информации из sysfs. Чтобы писать правила, базирующиеся на этой информации, сначала следует знать имена аттрибутов и их текущие значения.
sysfs на сегодня имеет очень простую структуру. Логически она поделена на каталоги. Каждый каталог содержит некоторое количество файлов (аттрибутов), которые обычно содержат всего одно значение. Также присутствуют некоторые символические линки, которые связывают устройства с их родителями. Мы ранее обсуждали эту иерархическую структуру.
Некоторые каталоги ссылаются на пути к устройствам верхнего уровня по дереву. Эти каталоги представляют текущие устройства, которые имеют соответствующие узлы устройств в /dev. Пути к устройствам верхнего уровня могут быть классифицированы как каталоги sysf, которые содержат файл dev. Вы можете посмотреть из список с помощью следующей команды:
Например, в моей системе каталог /sys/block/sda — это путь к устройству, соответствующему моему жёсткому диску. Он слинкован со своим родителем, SCSI диском, через символическую связь the /sys/block/sda/device.
Когда вы пишете правило, основываясь на информации из sysfs, вы просто ищете соответствие значения аттрибута в каких-то файлах из части цепочки. Например, я могу прочесть размер моего жёсткого диска так:
В правиле для udev я могу использовать ATTR
Хотя вышесказанное и может пригодиться как знакомство со структурой sysfs и как точное представление о том, как udev ищет соответствие значений, выуживание вручную данных из sysfs отнимет много времени и вообщем-то необязательно.
udevinfo
Запустить программу udevinfo, может оказаться самым прямым путём, который можно использовать для создания правил. Всё, что вам надо знать — это путь к устройству в sysfs, чтобы правильно сформулировать запрос. Пример запроса показан ниже:
Как вы видите, udevinfo просто выдаёт список аттрибутов, которые вы можете использовать «как есть» в ключах соответствия ваших правил для udev. Из вышеприведённого примера я могу создать (для примера) следующие два правила для этого устройства:
Вы может заметили выделение цветом в этих примерах. Здесь продемонстрировано, что допустимо комбинировать аттрибуты запрашиваемого устройства и одного родительского устройства. Но вы не должны смешивать в поиске аттрибуты от разных родительских устройств — такое правило работать не будет. Например, следующее правило недопустимо, поскольку пытается найти соответствие от двух родительских устройств:
Обычно у вас есть множество аттрибутов и вы должны выбрать какие-то для создания своего правила. В большинстве случаев хочется выбрать аттрибуты, с помощью которых можно устойчиво идентифицировать устройство и так, чтобы это было понятно человеку. В вышеприведённых примерах я выбрал в качестве аттрибутов размер и модель моего диска. Я не использовал бессмысленные цифры типа ATTRS
Посмотрим на эффекты от иерархии в выводе udevinfo. Зелёная секция , соответствующая устройству в запросе, использует стандартные ключи соответствия, такие как KERNEL и ATTR. Голубая и бордовая секции, соответствующие родительским устройствам используют варианты с поиском в родительских секциях, такие как SUBSYSTEMS и ATTRS. Вот почему на самом деле довольно просто иметь дело со сложной иерархической структурой, надо всего лишь использовать точные значения, которые можно получить с помощью udevinfo.
Другое общее замечание касается текстовых аттрибутов в выводе udevinfo. К ним добавляются пробелы (для примера посмотрите на ST3120827AS). В ваших правилах вы можете указать дополнительные пробелы или выкинуть их совсем, как я и сделал.
Единственная сложность в использовании udevinfo это то, что вы должны знать вершину пути к устройству ( в вышеприведённом примере это /sys/block/sda). И эта вершина не всегда очевидна. Однако, поскольку в большинстве случаев вы пишите правила для узлов устройств, которые уже существуют, вы можете использовать udevinfo, чтобы определить путь к вершине дерева для устройства:
Альтернативные методы
Хотя udevinfo это наиболее прямой путь получения списка точных аттрибутов, из которых можно построить правила, некоторые пользователи довольны и другими утилитами. Такие утилиты как usbview отображают схожий набор информации, большая часть которой может быть использована в правилах.
Продвинутые темы
Управление доступом и владельцами устройств
udev позволяет вам использовать дополнительные присвоения в правилах для управления аттрибутами доступа к устройству и прав владения на устройство.
Присвоение GROUP позволяет задать группу, которой будет принадлежать узел устройства. Ниже приведено правило, которое определяет, что все устройства фреймбуферы будут принадлежать группе video:
Ключевое слово OWNER, быть может и менее полезно, но позволяет вам задать имя Unix-пользователя, который будет владельцем узла устройства. Предположим, что мы столкнулись с несколько необычной ситуацией, когда вам надо, чтобы пользователь john был владельцем накопителей на гибких дисках. Для этого вы можете использовать следующее правило:
udev по умолчанию создаёт узлы с Unix-правами 0660 (разрешено читать/писать владельцу и группе). Если требуется, вы можете заменить эти умолчания для конкретных устройств, используя правила с оператором присваивания MODE . Для примера, следующее правило определяет, что узел inotify должен быть доступен всем на чтение и запись:
Использование внешних программ для присвоения имён устройствам.
В некоторых случаях вам может потребоваться большая гибкость, чем позволяют вам стандартные правила udev. В таком случае вы можете попросить udev запустить внешнюю программу и использовать стандартный вывод из этой для присвоения имени устройству.
Для того, чтобы использовать эту возможность, вы просто указываете абсолютный путь к запускаемой программе (и любые другие параметры) в операторе присвоения PROGRAM, и затем используете какой-то из вариантов подстановки %c в операторах присвоения NAME/SYMLINK.
Следующие примеры используют фиктивную программу /bin/device_namer. device_namer использует один аргумент — имя устройства из ядра. device_namer обрабатывает это имя устройства и выдаёт результат в stdout. Результат состоит из нескольких частей. Каждая часть — это отдельное слово. Части отделены друг от друга одним пробелом.
В первом примере предполагается, что device_namer выдаёт несколько частей, каждая из которых создаёт симлинк (альтернативное имя) для устройства из запроса к программе.
Следующий пример предполагает, что device_namer выдаёт два слова, первое — имя устройства, второе имя — для симлинка. Здесь мы показываем использование подстановки %c , которая указывает на часть с номером N в выводе программы:
Следующий пример предполагает, что device_namer выдаёт одно слово для имени устройства, за которым следуют слова, которые создают дополнительные симлинки. Здесь представлено то, как использовать подстановку %c , которая выдаёт раскрывается как части N, N+1, N+2, . и так до конечного слова из вывода программы.
Выходные слова можно использовать с любым присваивающим ключевым словом, а не только с NAME и SYMLINK. Приводимый далее пример использует фиктивную программу, с помощью которой определяется Unix-группа, которой должно принадлежать устройство:
Запуск внешних программ при определённых событиях.
Дополнительной причиной написания правил udev может послужить необходимость в запуске специальной программы в моменты, когда устройство подключают к системе или отключают. Например, вам хочется выполнить скрипт автоматического скачивания ваших фотографий с камеры после того, как камеру вы подключили к компьютеру.
Вас не должны вводить в заблуждение ранее описанные возможности PROGRAM. PROGRAM используется для запуска программ которые выдают имена устройств (и эти программы ничего другого делать и не должны). В момент, когда эти программы выполняются, узел устройства ещё не создан, так что работать с устройством в этот момент никак не получится.
Далее описанная функциональность позволяет запустить программу уже после того, как узел устройства уже создан. В этом случае программа может работать с устройством, однако она не должна делать это долго, поскольку udev приостанавливается на время пока такая программа работает. Обойти это ограничение можно тем, что программа должна после запуска сразу отсоединиться.
Вот пример правила, которое демонстрирует оператор присвоения RUN, добавляющий указанную программу в список запускаемых:
Когда выполняется /usr/bin/my_program, некоторые переменные udev доступны через переменные окружения, включая такие значения, как SUBSYSTEM. Вы можете также использовать переменную окружения ACTION, чтобы определить было ли устройство подключено или отключено — значение ACTION будет или «add» или «remove» соответственно.
udev не запускает такие программы на каком-нибудь активном терминале, и не выполняет их через shell. Удостоверьтесь, что файлы программ имеют аттрибут исполняемости, а если это shell-скрипт, то удостоверьтесь, что первой строкой в скрипте указан правильный shell (т.е. #!/bin/sh ), и не надейтесь увидеть на своём терминале то, что выводит программа в stdout.
Взаимодействие с окружением
udev позволяет использовать ключевое слово ENV key для получения значений из окружения как для поиска соответствия, так и для присваивания.
В случае присваивания, вы можете устанавливать переменные окружения, по содержимому которых вы позже можете проверить соответствие. Вы также можете устанавливать переменнные окружения и использовать из в любой внешней программе, которую запускаете при помощи ранее описанной техники. Ниже показан выдуманный пример правила, которое устанавливает переменную окружения.
В случае поиска соответствия , вы можете заставить срабатыват правило в зависимости от значения внешней переменной. Замечу, что окружение udev вовсе те то, что имеет пользователь за своей консолью. Ниже показано выдуманное правило, которое осуществляет поиск соответствия с переменной окружения.
Это правило создаст ссылку /dev/floppy только если $an_env_var будет иметь значение «yes» в окружении udev’s.
Дополнительные опции
Ещё одно присваивание может оказаться полезным. Это список OPTIONS. Доступно несколько опций:
- all_partitions — создать все возможные разделы для блочного устройства, а не только те, что были найдены изначально
- ignore_device — игнорировать события полностью
- last_rule — гарантировать, что никакие более поздние правила применяться не будут
Например, следующее правило устанавливает принадлежность к группе для моего жёсткого диска, и гарантирует, что последующие правила применяться не будут:
Примеры
USB Принтер
Я включил свой принтер и узел устройства получил имя /dev/lp0. Это имя меня не устраивает, и я решил использовать udevinfo, чтобы написать правило, создающее другое имя:
Моё правило выглядит так:
USB камера
Как и большинство камер, моя камера определяется как внешний жёсткий диск, подключенный через шину USB, и использует эмуляцию SCSI. Чтобы получить доступ к моим фотографиям, я монтирую устройство и копирую файлы на мой жёсткий диск.
Не все камеры так работают: некоторые из них используют протокол, который не представляет их как устройства хранения данных. Подобные камеры поддерживаются программой gphoto2. В случаях, когда с камерой работаешь через gphoto, вам не надо писать правила для устройства, поскольку оно полностью управляется из пространства пользователя (а не специальным драйвером ядра).
Сложностью работы с устройствами USB камеры является то, что она обычно показывает себя как диск с одним разделом, например как /dev/sdb с разделом /dev/sdb1. Узел sdb для меня бесполезен, но вот sdb1 нужен — это раздел, который хочу смонтировать. Поскольку в sysfs данные представлены в виде цепочки, нужные мне аттрибуты, которые udevinfo выдаёт для /dev/sdb1 полностью совпадают в выводом для /dev/sdb. Такие результаты в вашме правиле потенциально подходят как для всего диска, так и для раздела. И это не то, что вам хочется, так что ваше правило должно быть специфично.
Чтобы обойти проблему, надо подумать, в чём разница между sdb и sdb1. Ответ удивительно прост: имена отличаются, так что мы можем использовать простой образец, который бы соответствовал полю имени устройства:
Жёсткий USB диск
Жёсткий USB диск вполне похож на USB камеру, описанную выше. Однако образец того, как работать с ним, отличается. В примере с камерой меня не интересовал узел sdb — он нужен только при работе с разделами (т.е. при работе программы fdisk). Ну зачем мне надо делать разделы в накопителе моей камеры!?
И конечно, когда у вас 100GB жёсткий USB диск, вполне понятно, что вы можете захотеть разбить его на разделы. И для этого можно воспользоваться возможностями подстановки строк, которые есть в udev:
Это правило создаст следующие симлинки:
- /dev/usbhd — Устройство, с которым работаем с помощью fdisk-а
- /dev/usbhd1 — Первый раздел (монтируемый)
- /dev/usbhd2 — Второй раздел (монтируемый)
USB кардридер
USB кардридеры (CompactFlash, SmartMedia, etc) это совсем другой диапазон USB устройств хранения, и при их использовании есть другие требования.
Эти устройства обычно не информируют компьютер о смене носителя. Так, если вы вставили устройство без носителя данныХ, а затем вставили в него карту памяти, компьютер об этом не узнает, и у вас не будет узла sdb1 для раздела, который вы могли бы смонтировать.
Одно из возможных решений — использовать возможности опции all_partitions, которая создасть 16 узлов для разделов для каждого блочного устройства, которое подходит под правило:
У вас теперь появятся узлы устройств с именами: cfrdr, cfrdr1, cfrdr2, cfrdr3, . cfrdr15.
USB Palm Pilot
Эти устройства работают как USB-serial, так что по умолчанию у вас будет только узел устройства ttyUSB1. Утилиты palm работают с /dev/pilot, так что, многие юзеры хотели бы использовать правило, которое обеспечит создание /dev/pilot.
Carsten Clasohm’s blog post содержит то, как это сделать. Правило от Carsten-а представлено ниже:
Отмечу, что строка для продукта может меняться от продукта к продукту, так что проверьте (используйте udevinfo) какая подойдёт в вашем случае.
CD/DVD приводы
У меня 2 оптических привода: DVD (hdc), и DVD-RW (hdd). Я не жду что, узды устройств поменяются, разве что я физически поменяю что-то в моей системе. Однако многим пользователям удобны такие названия как /dev/dvd.
Поскольку я знаю, как ядро именует эти устройства, правила очень просты. Вот пример для моей системы:
Сетевый интерфейсы
Хотя к ним мы и обращаемся по имени, сетевые интерфейсы обычно не имеют узлов устройств, связанных с ними. Несмотря на это, процесс создания правил для них практически такой же.
Имеет смысл в правиле просто найти соответствие с MAC-адресом вашего интерфейса, поскольку MAC-адреса уникальны. Однако удостоверьтесь, что вы используете абсолютно тот MAC-адрес, который выдаёт udevinfo, поскольку если регистр букв не совпадает полностью, правило работать не будет.
Вот моё правило:
Следует перегрузить драйвер для сетевой карты, чтобы правило сработало. Вы можете выгрузить и затем загрузить модуль или просто перезагрузить систему. Также вам потребуется изменить конфигурацию системы, чтобы она использовала «lan» а не «eth0». У меня были некоторые проблемы с эти (интерфейс не переименовыволя) пока я полностью не удалил всё, что ссылалось на eth0. После этого вы сможете использовать «lan» вместо «eth0» в ifconfig или подобных утилитах.
Тестирование и отладка
Ввод в действие ваших правил
Если у вас ядро из последних с поддержкой inotify, udev автоматически контролирует содержимое каталога с вашими правилами и автоматически применит любые модификации, которые вы сделали в файлах правил.
Несмотря на сказанное, udev не будет автоматически заново обрабатывать все устройства и пытаться применить все новый правила. Например, вы написали правило, которое делает дополнительный симлинк для вашей камеры, а камера уже была подключена к системе. В этом случае вам не стоит ожидать, что симлинк сразу появится.
Чтобы он появился, вам надо отключить и заново подключить камеру. Альтернативой для непереподключаемых устройств служит запуск программы udevtrigger.
Если ядро не поддерживает inotify, новые правила автоматически не определятся. В таком случае следует запустить udevcontrol reload_rules после изменения файлов с правилами.
udevtest
Если вы знаете верхнюю точку пути к устройству в sysfs, вы можете использовать udevtest для просмотра действий, которые предпримет udev. Это может помочь в отладке ваших правил. Предположим, что вы хотите отладить правило, действующее на/sys/class/sound/dsp:
Отмечу, что префикс /sys был удалён из командной строки для udevtest. Это потому, что udevtest работает с путями к устройствам. Также замечу, что udevtest — это чисто тестовое/отладочное средство, оно не создаёт узлов устройств, несмотря на содержимое того, что эта программа выводит на экран!
Автор и контакты
This document is written by Daniel Drake <dan@reactivated.net>. Feedback is appreciated.
For support, you should mail the linux-hotplug mailing list: linux-hotplug-devel@lists.sourceforge.net.
Copyright (C) 2003-2006 Daniel Drake.
This document is licensed under the GNU General Public License, Version 2.