udev

Aus Mikiwiki
Zur Navigation springen Zur Suche springen

Mit dem Programm (Subsystem) udev verwaltet der Linux-Kernel über den Hotplug-Mechanismus Gerätedateien für die Datenein- und -ausgabe (input/output). Es ersetzte ab dem Linux-Kernel 2.6 das früher genutzte Dateisystem devfs. Genauso wie devfs verwaltet dazu der im Hintergrund laufende Daemon udevd das Verzeichnis "/dev", das die speziellen Gerätedateien enthält, um von Programmen aus auf die vom System zur Verfügung gestellten Geräte zuzugreifen. Sobald neue Geräte erkannt werden, werden hier dynamisch entsprechende Gerätedateien erzeugt.

Funktionsweise

Beim Anschliessen oder Entfernen eines Geräts im laufenden Betrieb (Hotplugging) oder bei der ersten Initialisierung während des Bootvorgangs (Coldplugging) geschieht folgendes:

  • Der jeweilige Systembus-Controller (ISA, PCI, USB, Firewire, Bluetooth) signalisiert das Anschliessen bzw. Entfernen durch einen Interrupt.
  • Als Reaktion auf diese Unterbrechung ermittelt der Linux-Kernel Einzelheiten über das neu hinzugekommene Gerät, indem er entweder den Hardware-Controller befragt, die Busse abfragt oder an fest vorgegebenen Adressen (z. B. im Konfigurationsbereich von PCI-Karten) nach dort abgelegten Informationen sucht, insbesondere nach der Vendor- und der Product-ID des Geräts. Anhand des Ergebnisses werden Dateien mit dem Namen "uevent" angelegt, welche (weil beim Bootvorgang anfänglich kein beschreibbares Root-Dateisystem vorhanden ist) im virtuellen Sysfs abgelegt werden. Später erzeugt udev anhand dieser Dateien für jedes während des Bootvorganges gefundene Gerät einen Event an. Ab hier gleichen die Abläufe genau denen beim späteren Anschliessen der Geräte zur Laufzeit (Hotplugging).
  • Danach legt der Linux-Kernel für das neue Gerät ein sogenanntes "Kobject" an, das die Verwaltungsinformationen aufnimmt, wobei es die Informationen über den Gerätetyp (zeichen- oder blockorientiert) und die Major- und Minor-Nummer über den mit Linux-Kernel 2.6 eingeführten globalen Namensraum für Kernelmodule erhält.
  • Diese Verwaltungsinformation macht der Linux-Kernel dann seinerseits über das normalerweise unter "/sys" eingehängte Dateisystem Sysfs (das in diesem Punkt das alte procfs ablöst) auch anderen zugänglich.
  • Bei älteren udev-Versionen ruft der Linux-Kernel danach das in "/proc/sys/kernel/hotplug" eingetragene Programm auf (meist "/sbin/hotplug"), um Usermode-Programme über den neuen Gerätestatus zu informieren. Dabei kann es beispielsweise nötige Treiber laden oder konfigurieren - welche das sein müssen, ermittelt es anhand der erwähnten IDs. Moderne udev-Versionen kommunizieren direkt mit dem Linux-Kernel und stossen dieselben Aktionen ohne Umweg an. Dann entfällt das Skript ersatzlos.

Bis zur udev-Version 0.58 lädt das Hotplug-Paket Treiber und Firmware - dabei bleibt "/sbin/hotplug" der Hotplug-Manager und ruft nach getaner Arbeit als Multiplayer alle in "/etc/hotplug.d" eingetragenen Programme auf. Ab Version 0.59 übernimmt udev beide Aufgaben.

Nachdem udev das neue Gerät ins System eingebunden hat, dient anschliessend der Hardware Abstraction Layer / HAL als Schnittstelle zwischen der Hardware und den Anwendungsprogrammen.

Beispiel

Folgende Auflistung zeigt ein mit dem Diagnosewerkzeug "udevmonitor" erzeugtes Log, das die Ereignisse beim Einstecken eines USB-Sticks anzeigt. Der Linux-Kernel überwacht dabei den USB-Bus und erkennt das neu angeschlossene Gerät. Über ein Uevent meldet er den Fund an den Daemon udevd. Das udev-System liest daraufhin die Daten des Geräts aus der Kernel-Gerätedatenbank Sysfs aus. Wie udev mit dem neuen Gerät verfährt, legen die udev-Regeln unter "/etc/udev/rules.d" fest - hier befinden sich einzelne Dateien, die jeweils die Aktionen für verschiedene Ereignisse festlegen.

  • Die mit "UEVENT" beginnenden Zeilen entsprechen den Kernelmeldungen.
  • Die mit "UDEV" beginnenden Zeilen entsprechen den udev-Aktionen.
  • Im Beispiel steht die neue Hardware unter der Gerätedatei "/dev/sdc1" bereit. Im Verzeichnis "/dev/disk" sind Links mit den Namen zu sehen, mit denen sich der USB-Stick am System angemeldet hat.
Verzeichnis Link
/dev/disk/by-id lrwxrwxrwx 1 root root 10 2009-08-04 10:51 usb-Generic_USB_Flash_Disk_00000000001AB4-0:0-part1 -> ../../sdc1
/dev/disk/by-path lrwxrwxrwx 1 root root 10 2009-08-04 10:51 pci-0000:00:1d.7-usb-0:3:1.0-scsi-0:0:0:0-part1 -> ../../sdc1
/dev/disk/by-uuid lrwxrwxrwx 1 root root 10 2009-08-04 10:51 54B3-2682 -> ../../sdc1
$ sudo udevmonitor
udevmonitor will print the received events for:
UDEV the event which udev sends out after rule processing
UEVENT the kernel uevent

UEVENT[1249375863.024031] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3 (usb)
UEVENT[1249375863.024105] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/usb_endpoint/usbdev5.2_ep00 (usb_endpoint)
UEVENT[1249375863.025338] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0 (usb)
UEVENT[1249375863.025386] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0/usb_endpoint/usbdev5.2_ep01 (usb_endpoint)
UEVENT[1249375863.025401] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0/usb_endpoint/usbdev5.2_ep82 (usb_endpoint)
UEVENT[1249375863.025413] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0/usb_endpoint/usbdev5.2_ep83 (usb_endpoint)
UDEV  [1249375863.031131] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3 (usb)
UDEV  [1249375863.066113] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/usb_endpoint/usbdev5.2_ep00 (usb_endpoint)
UEVENT[1249375863.362675] add      /module/libusual (module)
UDEV  [1249375863.364779] add      /module/libusual (module)
UEVENT[1249375863.365537] add      /bus/usb/drivers/libusual (drivers)
UDEV  [1249375863.367470] add      /bus/usb/drivers/libusual (drivers)
UDEV  [1249375863.369452] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0 (usb)
UDEV  [1249375863.402454] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0/usb_endpoint/usbdev5.2_ep01 (usb_endpoint)
UDEV  [1249375863.413143] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0/usb_endpoint/usbdev5.2_ep82 (usb_endpoint)
UDEV  [1249375863.423124] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0/usb_endpoint/usbdev5.2_ep83 (usb_endpoint)
UEVENT[1249375863.432804] add      /module/usb_storage (module)
UEVENT[1249375863.446285] add      /bus/usb/drivers/usb-storage (drivers)
UDEV  [1249375863.447901] add      /module/usb_storage (module)
UDEV  [1249375863.450156] add      /bus/usb/drivers/usb-storage (drivers)
UEVENT[1249375863.451717] add      /class/scsi_host/host4 (scsi_host)
UDEV  [1249375863.453713] add      /class/scsi_host/host4 (scsi_host)
UEVENT[1249375868.457256] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0/host4/target4:0:0/4:0:0:0 (scsi)
UEVENT[1249375868.457308] add      /class/scsi_disk/4:0:0:0 (scsi_disk)
UDEV  [1249375868.523133] add      /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0/host4/target4:0:0/4:0:0:0 (scsi)
UDEV  [1249375868.528413] add      /class/scsi_disk/4:0:0:0 (scsi_disk)
UEVENT[1249375868.544408] add      /block/sdc (block)
UEVENT[1249375868.544448] add      /block/sdc/sdc1 (block)
UEVENT[1249375868.544462] add      /class/scsi_device/4:0:0:0 (scsi_device)
UEVENT[1249375868.544474] add      /class/scsi_generic/sg3 (scsi_generic)
UDEV  [1249375868.587317] add      /class/scsi_device/4:0:0:0 (scsi_device)
UDEV  [1249375868.620134] add      /class/scsi_generic/sg3 (scsi_generic)
UDEV  [1249375868.842624] add      /block/sdc (block)
UDEV  [1249375868.871278] add      /block/sdc/sdc1 (block)
UEVENT[1249375869.632530] add      /module/fat (module)
UDEV  [1249375869.634740] add      /module/fat (module)
UEVENT[1249375869.635764] add      /slab/fat_cache (slab)
UEVENT[1249375869.635814] add      /slab/fat_inode_cache (slab)
UDEV  [1249375869.638020] add      /slab/fat_cache (slab)
UDEV  [1249375869.640370] add      /slab/fat_inode_cache (slab)
UEVENT[1249375869.685266] add      /module/vfat (module)
UDEV  [1249375869.699419] add      /module/vfat (module)
UEVENT[1249375869.749940] add      /module/nls_cp437 (module)
UDEV  [1249375869.751914] add      /module/nls_cp437 (module)
UEVENT[1249375869.777361] add      /module/nls_iso8859_1 (module)
UDEV  [1249375869.779437] add      /module/nls_iso8859_1 (module)

Viele Geräte melden sich mit ihrer Typenbezeichnung oder wenigstens dem Herstellernamen am System an, leider aber nicht alle. Bei USB-Geräten kann die Bezeichnung bei Bedraf mit dem Befehl lsusb festgestellt werden.

$ lsusb
Bus 005 Device 002: ID 3538:0042 Power Quotient International Co., Ltd Cool Drive U339 Flash Disk
Bus 005 Device 001: ID 0000:0000  
Bus 004 Device 001: ID 0000:0000  
Bus 003 Device 001: ID 0000:0000  
Bus 002 Device 001: ID 0000:0000  
Bus 001 Device 001: ID 0000:0000 

Konfiguration

Die udev-Konfigurationsdateien befinden sich im Verzeichnis "/etc/udev", bei einigen Distributionen auch in "/lib/udev".

Die wichtigsten Variablen für allgemeine Einstellungen stehen in der Datei "/etc/udev/udev.conf". Sie speichern beispielsweise das Wurzelverzeichnis der Gerätedateien, den Ort der internen udev-Datenbank, das Verzeichnis der regeln für das Anlegen und Benennen der Gerätedatei und der Protokollierungsstufe:

# more /etc/udev/udev.conf
udev_root="/dev/"
udev_db="/dev/.udevdb"
udev_rules="/etc/udev/rules.d"
udev_log="err"

Zur Konfiguration seiner Funktionsweise bietet udev zwei weitere Eingriffspunkte:

  • In "/etc/udev/rules.d" befinden sich Dateien, die regeln, wie die Devicenodes zu benennen sind, die udev bei bedarf erzeugt.
  • In "/etc/udev/make-dev.d" liegen Skripte mit den Namen der statischen Gerätedateien, die z. B. für die Parallelschnittstelle nötig sind. Bei einigen Distributionen fehlt diese Datei.

Die Zugriffsrechte stehen bei aktuellen udev-Versionen nicht mehr im Verzeichnis "/etc/udev/permissions.d", sondern in der normalen udev-Konfiguration.

Regeln

Der erste Teil jeder Regel gibt jene Bedingung an, die erfüllt sein muss, damit udev den zweiten Teil ausführt bzw. anwendet. Im einfachsten Fall muss nur der kernelinterne Name eines Geräts oder eines Subsystems zutreffen. Für eine Tastatur lautet die Regel z. B.

KERNEL=="kbd"

Die Bedingungen sind wie bei einer Programmiersprache mit doppelten Gleichheitszeichen gekennzeichnet. Nach einem Komma können weitere Bedingungen folgen. Die auszuführenden Aktionen enthalten dagegen nur einfache Gleichheitszeichen. Z. B. setzt folgender Ausdruck die Zugriffsrechte:

MODE="0660"

Analog lassen sich mit "OWNER" der Eigentümer oder mit "GROUP" die Gruppe bestimmen, die eine Gerätedatei zugeordnet bekommt. Ihren namen gibt das Schlüsselwort "NAME" vor, das einige Platzhalter verarbeitet. So steht etwa "%k" für den oben genannten Kernelnamen. Eine Regel nach diesem Muster könnte z. B. wie folgt aussehen. Dabei wird für jedes Gerät, dessen Kernelname mit "isdn" beginnt, ein Devicenode gleichen Namens mit Lese- und Schreibrechten für den Eigentümer und seine Gruppe angelegt.

KERNEL=="isdn", NAME="%k", MODE="0660"

Normalerweise geht udev alle zutreffenden Regeln durch, bis keine weiteren mehr vorhanden sind. Zum Abbruch der Verarbeitung nach dem Zutreffen einer Regel ist unter "OPTIONS" die Anweisung "last_rule" anzugeben.

Die udev-Regeln können auch externe Programmaufrufe enthalten, die ebenfalls als Bedingung gelten. Nur wenn der Aufruf das gewünschte Ergebnis liefert, führt udev die anschliessend aufgeführten Aktionen aus. Die Manpage enthält ein Beispiel für ATAPI-CD-ROMs, das untersucht, ob ein entsprechendes "/proc"-Verzeichnis vorhanden ist, das ein Gerät als CD-ROM identifiziert. Dabei gibt udev für alle Geräte, deren Name mit "hd" beginnt, mit "/bin/cat" den Inhalt der entsprechenden "media"-Datei aus. Wenn sie "cdrom" enthält ("RESULT"), behält udev die Gerätedatei bei ("NAME="%k""), legt aber zusätzlich mit "SYMLINK" einen symbolischen Link "cdrom" an, wobei "%e" die nächste freie Dezimalzahl bestimmt, falls eine gleichnamige Datei bereits vorhanden ist.

KERNEL=="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="%k", SYMLINK="cdrom%e"

Wertet man mit Hilfe einer udev-Regel die eindeutige Serienummer eines angeschlossenen Geräts aus, so lassen sich auch für Hotplug-Geräte stabile Namen erreichen, die unabhängig von der Anschluss- oder Einschaltreihenfolge sind. Eine Regel dafür könnte wie folgt aussehen. Damit erhält der eingesteckte Drucker mit der zutreffenden Serienummer stets den Gerätenamen "lp-kyocera".

BUS=="usb", SYSFS_serial=="W09090207101241330", NAME="lp-kyocera"

Die häufigsten Anwendungen für selbst geschriebene oder von Benutzern geänderte udev-Regeln sind wohl individuell angepasste Gerätenamen oder besondere Rechte für Gerätedateien. Beispielsweise soll der in die Arbeitsumgebung eingeloggte Benutzer auf die zur Laufzeit hinzugefügte USB-Festplatte schreiben dürfen. Fedora löst dieses Problem z. B. dadurch, dass udev deren gerätedateien einfach dem in die Arbeitsumgebung eingeloggten Benutzer übereignet.

Fehlersuche

Bei der Fehlersuche hilft der udev-Daemon durch seine einstellbare Protokollierungsstufe, die bei der Standardeinstellung "err" allerdings nur Fehler ausgibt. Mit der Vorgabe "info" wird der udev-Daemon etwas mitteilsamer, die Vorgabe "debug" macht ihn noch geschwätziger. Diese Werte können entweder in die Konfigurationsdatei eingetragen oder zur Laufzeit über das Werkzeug "udevcontrol" eingestellt werden. Den Loglevel setzt z. B. der Eintrag "udevcontrol log_priority=debug". Über die Anweisung "reload_rules" bewegt udevcontrol den udev-Daemon zum erneuten Laden aller Regeln.

Weblinks

Herausgeber Sprache Webseitentitel Anmerkungen
Wikipedia ger udevwbm Enzyklopädischer Artikel
Ubuntu Users ger udevwbm
Daniel Drake eng Writing udev ruleswbm