Разборки с HAL’ом

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

Заметка была написана в связи в некоторой практической работой — и как её часть. Это во-первых. А во-вторых — в связи с тем, что проблемы автоматического общения с оборудованием возникают постоянно. И при этом — каждый раз новые. Ну неймётся разработчикам… Так что ниже — просто набор рецептов, опробованных на ограниченном материале.

Механизм udev, только что описанный в соответствующей заметке, отвечая за создание файлов устройств в соответствие с реальным оборудованием, в том числе и горячего подключения, не обеспечивает, однако, монтирования сменных накопителей. Это надо выполнять в ручном или в полуавтоматическом (с определением в файле /etc/fstab соответствующих устройств с опциями типа noauto,user и т.д.) режиме.

Однако есть и более радикальный метод настройки монтирования сменных носителей
от лица пользователя — использование механизма HAL (Hardware Abstraction Level).
В общем случае HAL предназначен для сокрытия различий в аппаратном обеспечении
от основной части ядра операционной системы, и в той или иной мере используется
в самых разных ОС, от Windows до NetBSD (именно абстрагирование от аппаратуры обеспечивает быстрое и безболезненное портирование последней на самые различные платформы).

Однако здесь речь пойдёт об одной из вполне конкретных реализаций HAL — той, что прижилась в Linux’е и может быть задействована в родственных BSD-системах. Это — демон, первоначально разрабатывавшийся фирмой Red Hat (первый разработчик — David
Zeuthen), а ныне представляющий собой составную часть freedesktop.org.
На официальной
странице проекта
  можно найти исходные тексты программы, её зависимости,
а также некоторую документацию — не очень богатую и, разумеется, англоязычную.

Демон HAL получает информацию об аппаратном обеспечении от ядра ОС (в
Linux, например, — из sysfs), и предоставляет её прикладным программам в подходящем
для них (и, что немаловажно, одинаковом для всех платформ) формате, избавляя их
от необходимости обращаться к ядру самостоятельно.

При посредстве демона HAL осуществляется, в частности, автоматическое монтирование
сменных накопителей. Однако этим его роль не исчерпывается. В современных версиях Xorg через него получает информацию об аппаратуре (клавиатуре и мыши) X-сервер
— что делает возможным запуск Иксов без традиционного их конфигурационного
файла /etc/X11/xorg.conf.

Следует, однако, подчеркнуть, что сам по себе демон HAL никакие накопители не
монтирует, никакие устройства в X-сервере не настраивает. Он лишь определяет
наличные устройства, фиксирует их параметры и представляет их в виде,
доступном тем программам, которые будут заниматься непосредственно указанными
действиями — монтированием, управлением раскладками клавиатуры, поведением
кнопок мыши, и так далее.

Вообще, просмотреть, какие устройства определяются HAL’ом, можно с помощью
кломанды:

$ lshal | less

Предупреждаю, вывод её будет весьма длинным (почему и целесообразно передать
его команде less). Зато внимательное его рассмотрение даст практически
исчерпывающую информацию о наличных устройствах и их параметрах, почему нам
ещё придётся к ней возвращаться. Например, так выглядит фрагмент, относящийся к
500-гигабайтному SATA-винчестеру Samsung:

...
  scsi.model = 'SAMSUNG HD501LJ'  (string)
udi = '/org/freedesktop/Hal/devices/storage_serial_SATA_SAMSUNG_HD501LJS0MUJ1EPB12062'
  block.storage_device = '/org/freedesktop/Hal/devices/storage_serial_SATA_SAMSUNG_HD501LJS0MUJ1EPB12062'  (string)
  info.product = 'SAMSUNG HD501LJ'  (string)
  info.udi = '/org/freedesktop/Hal/devices/storage_serial_SATA_SAMSUNG_HD501LJS0MUJ1EPB12062'  (string)
  storage.model = 'SAMSUNG HD501LJ'  (string)
  storage.serial = 'SATA_SAMSUNG_HD501LJS0MUJ1EPB12062'  (string)
...

Это вывод команды в так называемом “длинном” формате, обеспечиваемом опцией -l (или –long), каковая, впрочем, используется по умолчанию. Возможны и более компактные или более удочитаемые формы вывода команды lshal. Так, данная в форме

$ lshal -s

она представит только список устройств, без подробной расшифровки:

...
storage_serial_SATA_SAMSUNG_HD501LJS0MUJ1EPB12062
...

А форма

$ lshal -t

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

...

pci_8086_2921

    pci_8086_2921_scsi_host_0

      pci_8086_2921_scsi_host_0_scsi_host

      pci_8086_2921_scsi_host_0_scsi_device_lun0

        storage_serial_SATA_SAMSUNG_HD501LJS0MUJ1EPB12062

          volume_uuid_69458f4c_c6d5_4102_a5ea_083593dbc811

          volume_uuid_eb0b9b6c_8102_4704_b254_389cf8d44b92

          volume_uuid_41ad983d_e238_4c51_8555_355b45ce10af

          volume_uuid_56b2dede_e113_425a_9f50_c1017f9e9113

...

Посредством lshal с опцией -u можно вытащить сведения о некоем конкретном устройстве. Для чего нужно только знать его UDI (Unique Device Identifier — уникальный идентификатор устройства в системе именования HAL — это не то же самое, о чем говорилось в предыдущей заметке), который задаётся в качестве значения этой опции. Например, команда

lshal -u storage_serial_SATA_SAMSUNG_HD501LJS0MUJ1EPB12062

даст нам полные сведения всё о том же винчестере:

udi = '/org/freedesktop/Hal/devices/storage_serial_SATA_SAMSUNG_HD501LJS0MUJ1EPB12062'

  block.device = '/dev/sdb'  (string)

  block.is_volume = false  (bool)

  block.major = 8  (0x8)  (int)

  block.minor = 16  (0x10)  (int)

  block.storage_device = '/org/freedesktop/Hal/devices/storage_serial_SATA_SAMSUNG_HD501LJS0MUJ1EPB12062'  (string)

  info.capabilities = {'storage', 'block'} (string list)

  info.category = 'storage'  (string)

  info.parent = '/org/freedesktop/Hal/devices/pci_8086_2921_scsi_host_0_scsi_device_lun0'  (string)

  info.product = 'SAMSUNG HD501LJ'  (string)

  info.udi = '/org/freedesktop/Hal/devices/storage_serial_SATA_SAMSUNG_HD501LJS0MUJ1EPB12062'  (string)

  info.vendor = 'ATA'  (string)

  linux.hotplug_type = 3  (0x3)  (int)

  linux.sysfs_path = '/sys/devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sdb'  (string)

  storage.automount_enabled_hint = false  (bool)

  storage.bus = 'pci'  (string)

  storage.drive_type = 'disk'  (string)

  storage.firmware_version = 'CR10'  (string)

  storage.hotpluggable = false  (bool)

  storage.lun = 0  (0x0)  (int)

  storage.media_check_enabled = false  (bool)

  storage.model = 'SAMSUNG HD501LJ'  (string)

  storage.no_partitions_hint = false  (bool)

  storage.originating_device = '/org/freedesktop/Hal/devices/computer'  (string)

  storage.partitioning_scheme = 'mbr'  (string)

  storage.removable = false  (bool)

  storage.removable.media_available = true  (bool)

  storage.removable.media_size = 500107862016  (0x7470c06000)  (uint64)

  storage.requires_eject = false  (bool)

  storage.serial = 'SATA_SAMSUNG_HD501LJS0MUJ1EPB12062'  (string)

  storage.size = 500107862016  (0x7470c06000)  (uint64)

  storage.vendor = 'ATA'  (string)

в относительно читаемом виде.

“Посредничество” между демоном HAL и программами, использующими полученную
от него информацию, выполняется специальными конфигурационными файлами
— именно с помощью них можно переопределить параметры устройств и условия их
использования. Это, во-первых, файл /etc/PolicyKit/PolicyKit.conf, определяющий глобальную “политику” демона, во-вторых — набор fdi-файлов для конкретных устройств,
расположенных обычно в каталоге /etc/hal/fdi/policy. Следует отметить, что в
свежеустановленном дистрибутиве последний может быть практически пуст, однако их образцы, описывающие умолчания системы, можно найти в каталоге /usr/share/hal/fdi/policy/.

Все конфигурационные файлы HAL’а представляют собой XML-документы, начинающиеся с определения типа, например,

<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- --><!DOCTYPE pkconfig PUBLIC "-//freedesktop//DTD PolicyKit Configuration 1.0//EN"

"http://hal.freedesktop.org/releases/PolicyKit/1.0/config.dtd">

для файла PolicyKit.conf, или

<?xml version="1.0" encoding="ISO-8859-1"?> <!-- -*- SGML -*- -->

для одного из fdi-файлов. Внутренний формат конфигов мы рассмотрим на конкретных примерах.

Начнём с монтирования сменных устройств. Во всех современных дистрибутивах Linux, которые мне доводилось видеть в последнее время, он задействован по умолчанию, соответствующие пакеты — Xorg, интегрированные декстопы GNOME, KDE, Xfce — уже собраны с его поддерожкой. Тем не менее, если это окажется не так, то настроить HAL руками тоже не составит большого труда.

Итак, для начала необходимо установить (средствами пакетного менеджмента данного дистрибутива) соответствующий пакет, который так и называется — hal. Хотя, как только что было сказано, при установке Иксов и какой-либо из интегрированных сред он уже будет инсталлирован как зависимость. Причём, возможно, вместе с собственно монтировщиком — в случае с GNOME и Xfce это будет пакет gnome-mount; если такового не окажется — нужно будет дополнительно озаботиться его установкой.

Далее, надо обеспечить запуск соответствующих демонов при старте системы. Собственно, демон, отвечающий за механизм HAL, так и называется — hald. Однако он зависит еще от нескольких стартовых служб — devd, usbd, dbus. Некоторые из них могут быть уже запущены. Определить, какие демоны уже функционируют можно, например, командой

$ ps aux

Просматриваем её вывод и вписываем в файл (или файлы), отвечающий за запуск
стартовых служб, недостающие демоны.

Подчеркну, что никакой необходимости в установке прав доступа к файлам устройств или редактировании /etc/fstab, что требовалось при настройке пользовательского монтировании вручную, при использовании механизма HAL не возникает.

Теперь — собственно настройка. И тут возможны варианты, опять-таки зависящие
от дистрибутива. Рассмотрим самый простой способ: отправляемся в каталог
/etc/PolicyKit и обнаруживаем там файл PolicyKit.conf, о котором говорилось выше. По
умолчанию содержимое его примерно следующее:

<config version="0.1">

    <match user="root">

        <return result="yes"/>

    </match>

    <define_admin_auth group="wheel"/>

</config>

Что предваряется следующей фразой:

<!-- See the manual page PolicyKit.conf(5) for file format -->

Руководствуясь man (5) PolicyKit.conf, между строками

    <define_admin_auth group="wheel"/>

и

</config>

дописываем следующие строки:

        <match action="org.freedesktop.hal.storage.mount-removable">

              <return result="yes"/>

        </match>

    <match action="org.freedesktop.hal.storage.mount-fixed">

               <return result="yes"/>

        </match>

разрешающие членам группы wheel монтирование сменных и внутренних носителей,
соответственно. Для чего, разумеется, надо предварительно включить нашего
соответствующего пользователя в эту группу.

Это пример для дистрибутивов, в которых группа wheel задействована: только её
члены могут получить доступ к правам администратора, например, командой su.
Но в принципе группу можно определить произвольно — главное, чтобы пользователь,
которому разрешено автоматическое монтирование сменных накопителей, был её членом.

И после реинициализации системы (например, посредством временного перехода в однопользовательский режим или полного рестарта) указанный пользователь получает возможность автоматического монтирования сменных устройств сразу вслед за их помещением в привод или подсоединением к USB-порту. Точнее, монтирование это происходит само, без всякого его участия.

По собственному опыту, через HAL нормально монтируется всё, что способно монтироваться: CD- и DVD-диски, флэшки, внешние винчестеры с USB-интерфейсом, носители внутри фотокамер и они же, подключённые через кард-ридер. Единственная проблема у меня возникла с флэшкой, переформатированной через штатную опцию Windows, то есть с файловой системой VFAT не на разделе, а непосредственно на raw-устройстве. Впрочем, и было это не в Linux’е, а во FreeBSD.

После монтирования флэшки или компакта описанным способом на рабочем столе
интегрированного десктопа типа KDE, GNOME, Xfce появляется соответствующая
пиктограмма, а команда mount без параметров показывает в списке смонтированных
файловых систем соответствующее устройство.

Содержимое смонтированного устройства можно просмотреть в каталоге
/media/mount_point. Точке монтирования, как правило, присваивается имя метки (Label)
накопителя. Если таковая не была задана — каталог для монтирования будет носить
имя типа Disk1 и так далее. Иногда раньше бывали случаи, когда устройство без
метки отказывалось монтироваться, но я с этим давно уже не сталкивался.

При необходимости извлечь автоматически смонтированное устройство его, тем не
менее, следует размонтировать. Для этого достаточно щелкнуть правой клавишей
на указанной пиктограмме и в контекстном меню выбрать соответствующий пункт —
Отключить том для USB-накопителей или Извлечь том — для компакт-диска.

Однако в некоторых ситуациях возникает необходимость в ручном отмонтировании
автоматически смонтированного накопителя. По крайней мере с одной такой я неоднократно сталкивался: это запись уже использовавшихся CD-RW или DVD-RW. Будучи вставленные в привод, они автоматически монтируются и некоторыми фронт-эндами для записи дисков (например, Brasero), не могут быть повторно записаны даже после принудительной очистки. Подчеркну — это баг конкретных программ записи (или даже конкретных их сборок — например, Brasero в дистрибутиве Zenwalk), а не самого механизма HAL.

Решается проблема просто, хотя и не очень изящно: нужно просто в командной
строке (например, терминала) от лица администратора отмонтировать
“неправильное” устройство, например, так:

sudo umount /dev/sr0

Указывать в качестве аргумента имя устройства предпочтительно, потому что
метки компакт-дисков (и, соответственно, точки их монтирования) иногда могут
иметь длинные и нечленораздельные имена.

Ещё раз подчеркну, что в большинстве современных дистрибутивов Linux’ никаких
специальных действий по настройке автоматического монтирования делать,
скорее всего не придётся. В отличие, скажем, от FreeBSD, где хотя HAL и задействуется
точно также, как в Linux’е, но по умолчанию не настроен совершенно (на счет чего имеется соответствующая заметка).

А вот с настройками Иксов через HAL, возможно, придётся иметь дело в любом случае. Ибо современные версии X-сервера (в исполнении Xorg) именно через него по умолчанию получают сведения об аппаратуре, не используя данные в файле
/etc/X11/xorg.conf. Такое положение можно (пока?) изменить, но, похоже, на ближайшее время именно оно будет соответствовать генеральной линии развития, так что разбираться с этим так или иначе придётся.

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

Для начала проверяем текущее состояние с раскладками клавиатуры. Это цели служит всё та же команда lshal. Для начала, дав её без опций в составе конструкции примерно такого вида

$ lshal | grep _logicaldev_input

выловим UDI нашего устройства ввода:

usb_device_46d_c517_noserial_if0_logicaldev_input

который и зададим как значение опции -u, повторив команду:

$ lshal -u usb_device_46d_c517_noserial_if1_logicaldev_input

Нас будет интересовать лишь фрагмент её вывода:

input.product = 'Logitech USB Receiver'  (string)

input.x11_driver = 'evdev'  (string)

input.xkb.layout = 'us'  (string)

input.xkb.model = 'pc105'  (string)

В котором мы видим название клавиатуры, имя драйвера, ею управляющего, доступные
ракладки и модель.

Для начала обращаем внимание на драйвер: при использовании HAL вместо
стандартного драйвера клавиатуры kbd (он содержится в пакете xserver-xorg-input-kbd) по умолчанию применяется драйвер evdev (пакет xserver-xorg-input-evdev), хотя, вроде бы, и kbd не возбраняется. Я лично не заметил между ними никакой разницы — единственное, нужно проследить за тем, чтобы указанный здесь драйвер соответствовал установленному пакету.

Далее мы видим, что в наличие имеется единственная раскладка, и та американская;
соответственно, о каких-либо вариантах и переключателях говорить не приходится.
Вот это положение нам и надлежит исправить.

За настройки клавиатуры отвечает файл вида 10-keymap.fdi — умолчальный его вариант
можно найти в каталоге /usr/share/hal/fdi/policy/10osvendor: точный путь может
различаться в разных дистрибутивах, поэтому для страховки лучше воспользоваться
поиском (например, утилитой find) по маске \*keymap.fdi. Во избежание разночтений копируем его в место, специально предназначенное для конфигурационных файлов — а именно:

$ sudo /usr/share/hal/fdi/policy/10osvendor/10-keymap.fdi
/etc/hal/fdi/policy

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

sudoedit /etc/hal/fdi/policy/10-keymap.fdi

Большая часть его содержимого в модификации не нуждается. Нужно только вписать строки, описывающие раскладки клавиатуры, их варианты, переключатель раскладок и, при необходимости, индикатор текущей раскладки:

<merge key="input.xkb.layout" type="string">us,ru</merge>

<merge key="input.xkb.variant" type="string">,winkeys</merge>

<merge key="input.xkb.options" type="string">grp:lwin_toggle,grp_led:caps</merge>

В данном примере задано переключение с латиницы на кирилицу по левой win-клавише, а в качестве индикатора кириллической раскладки выбран ScrollLock; разумеется, эти значения следует заменить на привычные.

В качестве варианта раскладки, вместо winkeys (соответствующего фабричной маркировке всех современных клавиатур) при желании можно указать legacy (маркировка
старых клавиатур времён “чёрного” DOS’а) или typewriter (маркировка пишущих машинок — по моему мнению, самая разумная, но, увы, напрочь забытая).

После этого перезапускаем демона HAL:

$ sudo /etc/init.d/hal restart

[sudo] password for username:

 * Restarting Hardware abstraction layer hald   [ OK ]

$

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

$ lshal -u usb_device_46d_c517_noserial_if1_logicaldev_input

в выводе которой наблюдаем все сделанные нами изменения:

  input.xkb.layout = 'us,ru'  (string)

  input.xkb.options = 'grp:lwin_toggle,grp_led:scroll'  (string)

  input.xkb.variant = ',winkeys'  (string)

Впрочем, у меня в Xubuntu изменения в выводе команды lshal появляются только после
перезапуска X-сервера.

Сходным способом, насколько я знаю, в принципе возможно настроить разного рода не вполне стандартные мыши — в частности, игровые, с изобилием всяких дополнительных кнопок, да ещё и способные выступать в роли джойстика. Однако у меня таких устройств никогда не было, и я этим не занимался.

Кроме задачи подключения HAL’а, в ряде случаев не менее актуальной оказывается обратная задача — его отключения, по крайней мере отдельных компонентов. И именно тех, которые касаются настройки клавиатуры и мыши в Иксах.

Как я уже говорил, современные версии X-сервера благополучно могут стартовать без всякого конфигурационного файла вообще (то есть без /etc/X11/xorg.conf). Тем не менее, многие пользователи предпочитают использовать его и поныне — во-первых, в силу привычки (у меня, например, до недавнего времени один и тот же xorg.conf на протяжении многих лет кочевал, с минимальными правками, из дистрибутива в дистрибутив и из системы в систему).

Да и гораздо проще дописать в автоматически сгенерированный, например, посредством

$ sudo Xorg -configure

конфиг две-три строки, чем разбираться с не вполне прозрачными XML-файлами HAL’а.

И вот тут могут начаться проблемы: результаты автоопределения оборудования через HAL, в частности, мышь и клавиатура, вступают в противоречие с их описанием в соответствующих секциях xorg.conf.

И в результате после успешного, казалось бы, старта Иксов (вне зависимости, через startx или какой-либо менеджер сеансов) оба эти устройства не подают признаков жизни. А в файле /var/log/Xorg.0.log обнаруживается такое сообщение:

(WW) AllowEmptyInput is on, devices using drivers
'kbd' or 'mouse' will be disabled.

Правда, решается эта проблема очень просто: достаточно в секцию Section
“ServerLayout” файла /etc/X11/xorg.conf после строк,
идентифицирующих устройства ввода

 InputDevice    "Mouse0" "CorePointer"
InputDevice    "Keyboard0" "CoreKeyboard"

вписать запрет их автоматического добавления:

 Option "AutoAddDevices" "False"
Option "AllowEmptyInput" "False"

После чего Иксы наконец благополучно запускаются. Не возникает при этом и проблемы с переключением раскладок.

И в заключение надо сказать несколько слов о D-Bus. Потому что это тот самый механизм, который обеспечивает передачу данных об оборудовании, полученных посредством HAL’а, системным и прикладным программам, таковые использующим. Хотя значение его далеко выходит за эти рамки.

D-Bus – это один из механизмов межпроцессного взаимодействия (иначе IPC – InterProcess Communication), подобный широко известному CORBA или DCOP, до недавнего времени использовавшемуся в KDE вплоть до вертки 3.X включительно. Он, как и HAL, разрабатывается в рамках метапроекта freedesktop.org (официальная страница проекта здесь). И первоначально использовался в GNOME, хотя ныне передаваемые по нему данные
доступны и в других рабочих средах (Xfce, KDE, начиная с ветки 4.X) и системах разработки (Mono, Java и другие).

Практически этот механизм реализован в виде одноимённого демона dbus (как уже говорилось, он выступает в качестве записимости пакета hal), работа которого организована по шинному принципу. Шин, то есть каналов передачи сообщений, две:

  • системная шина – по ней происходит обмен сообщениями с другими демонами (например, с тем же демоном hal);
  • сессионная шина –- создаёт для зарегистрированного в системе пользователя, для каждого из которых запускается собственная копия демона; по этой шине происходит обмен сообщениями с приложениями, запущенными пользователем (например, X-сервером или программой монтирования накопителей).

Я не очень представляю, каково может быть вмешательство пользователя в работу демона dbus (помимо установки соответствующего пакета и обеспечения его запуска). Разве что сочинить сценарий для отслеживания устройств, и поиграться с подсоединением и отсоединением мыши, USB-накопителей и так далее.

Разборки с HAL’ом: 10 комментариев

  1. 2 adw0rd
    Спасибо за идею и ссылку
    Хотя в принципе необходимости в этом нету — пишу в текстовом редакторе, где она и так есть

  2. Странно, но у меня все листинги (особенно тот что начинается с «udi = ‘/org/freedesktop/Hal/dev….», он самый длинный) вылезают за пределы страницы, как будто там нет символов перевода строки… Firefox 3, Windows, в других статьях такого не наблюдается :/

  3. 2 mannequin
    все другие статьи писались в текстовом редакторе :)
    а эту и предыдущую я скопипастил из OOo — и, как показала практика, напрасно :)
    Больше этого делать не буду

  4. >>> и, как показала практика, напрасно

    А в теории не пробовал объяснить? Я, кстати, это тоже заметил — копипастить из какого-нибудь навороченного текстового процессора означает реальную головную боль.

  5. 2 hymnazix
    Да и в теории знал… Лень-матушка. Так ведь всегда: на пять минут поленишься, а потом три часа е…я

  6. Ходят слухи, что hal уже помер, и на замену ему пришел devicekit. Как обычно это происходит в мире линукс: не успели стабилизировать, внедрить и описать одну технологию, новая кривая-косая альтернатива уже спешит на помощь.
    Разумная консервативность — одна из причин моей любви к BSD-системам.

  7. 2 anonymous
    Еще не помер, вроде, но к тому дело идёт. Но эта заметка писалась для «здесь и сейчас».
    А так — ну что сказать, кроме как согласиться?
    Кстати, HAL при желании легко прикрутить и к FreeBSD — http://alv.me/?p=194

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