Statische Gerätedateien sind angesichts aktueller Hardware nicht mehr zeitgemäß. So erfordert Hotplugging an USB- und anderen Bussen dynamisches Gerätehandling. DevFS erfüllt zwar viele Ansprüche an eine solche Lösung, wird aber nun von Udev abgelöst.
Von Unix hat Linux das Konzept “Alles ist eine Datei” geerbt. Dabei greifen Programme auf angeschlossene Hardware über so genannte Device Nodes (Gerätedateien) zu. Diese speziellen Dateien sind durch ihren Typ (Block- oder Zeichengerät) sowie Major- und Minor-Nummer definiert und wurden bislang mit »mknod« angelegt. Bei dieser statischen Lösung enthält das Verzeichnis »/dev« für jedes Gerät, das eventuell einmal dem System hinzugefügt werden könnte, bereits einen Eintrag – insgesamt einige tausend Gerätedateien, was die Übersicht doch sehr erschwert.
Zu statisch
Das Konzept hat noch weitere Nachteile: So bietet die Struktur keinen Überblick, welche Geräte wirklich vorhanden sind oder korrekt von Treibern erkannt wurden. Zudem besitzen Device Nodes kein über mehrere Bootvorgänge stabiles Namensschema: Welches SCSI-Gerät via »/dev/sg*« oder welcher USB-Drucker mit »/dev/usblp?« angesprochen wird, hängt allein von der zufälligen Reihenfolge ab, in der sie ins System gelangen. Wünschenswert ist oft auch eine flexiblere Namensgebung, etwa in Serversystemen mit sehr vielen Platten, wo ein eindeutiger UUID (Universal Unique Identifier) beim gezielten Wiederfinden hilft oder dem Anwender besser lesbare Namen bringt.
Alternative: DevFS
Standardmäßig verwendet zum Beispiel Mandrake 10.0 statt statischer Files das DevFS, um die beschriebenen Probleme zu lösen. Da DevFS bereits Thema in Heft 03/04[1] war, soll an dieser Stelle ein kurzer Überblick genügen.
DevFS erfüllt einen Teil der oben beschriebenen Anforderungen: Es erzeugt nur für erkannte Geräte überhaupt Device Nodes und verwendet dafür auch lesbare Namen, die der Benutzer durch Symlinks erweitert kann. Seine Arbeit erledigt DevFS im Kernel. Gerätetreiber benötigen spezielle Unterstützung und müssen mit den Funktionen »devfs_mk _dir()«, »devfs_mk_bdev()«, »devfs_mk _cdev()« und »devfs_remove()« die Device Nodes selbst registrieren und wieder entfernen.
DevFS verwendet standardmäßig andere Namen als die gewohnten. IDE-Geräte finden sich in »/devfs/ide/«, SCSI-Geräte in »/devfs/scsi/«, serielle Schnittstellen in »/devfs/tts/« wieder. Alle Festplatten werden durch symbolische Links in »/devfs/discs«, CD-ROMs in »/devfs/cdroms« zusammengefasst. Die Dateinamen sind bei DevFS auch fest im Kernel kodiert. Jeder Treiber muss Funktionen für die spezielle DevFS-Registrierung enthalten.
Nach Aussagen vieler Kernelentwickler enthält DevFS allerdings auch Race-Conditions, die bei ungünstigen Event-Reihenfolgen auftreten können. Aus diesen und anderen Gründen benutzen die meisten aktuellen Distributionen mittlerweile das andere dynamische Gerätedatei-System Udev.
Newcomer: Udev
Udev[2] ist nach den Vorstellungen der Kernelentwickler[3] der designierte DevFS-Nachfolger. Es verwendet den schon länger im Kernel vorhandenen Hotplug-Mechanismus (siehe Kasten “Hotplug im Detail”), um im Userspace Gerätedateien anzulegen. Der Kernel ruft bei Veränderungen an Geräten das in »/proc/sys/kernel/hotplug« eingetragene Programm auf, standardmäßig »/sbin/hotplug«. Dies kann je nach Art des Geräts Module laden, Zugriffsrechte ändern, Netzwerkgeräte konfigurieren oder eben im Fall von Udev, Device Nodes verwalten.
Udev benötigt Informationen über den Gerätetyp (Char oder Block) und die Major- und Minor-Nummer. Beides erhält Udev über den in Kernel 2.6 eingeführten globalen Namensraum für Kernelkomponenten. Jeder Gerätetreiber soll nun ein Kobject implementieren, um Attribute abzubilden. Diese Informationen macht der Kernel dann über das SysFS verfügbar, das in diesem Punkt das alte Proc-Dateisystem ablöst[5]. Üblicherweise mounten Distributionen SysFS nach »/sys«, was von Hand folgender Befehl erledigt:
mount -t sysfs none /sys
Das SysFS bildet die Blockgeräte in »/sys/block« und die Zeichengeräte in »/sys/class« ab, wobei die Major- und Minor-Nummern jeweils in einer Pseudodatei namens »dev« enthalten sind, zum Beispiel:
cat /sys/block/hda/dev 3:0
Udev findet über SysFS alle Informationen wie Geräteklasse, Name und Nummern, um die passenden Device Nodes zu erzeugen.
Udev einrichten
Für stabile Namen führt Udev im Userspace beliebig komplexe Operationen aus, um beispielsweise die Seriennummer des Druckers zu erfahren und so zu entscheiden, ob der soeben eingeschaltete Drucker »/dev/usb/lp0« oder doch »/dev/usb/lp1« ist. Es besteht sogar die Möglichkeit, beliebige Namen zu verwenden und die Gerätedateien etwa »/dev/lp-epson« oder »/dev/lp-kyocera« zu benennen.
|
Hotplug im Detail |
|---|
|
Wenn ein Kobject hinzugefügt oder entfernt wird, ruft der Kernel in der Funktion »kset_hotplug« in der Datei »lib/kobject.c« für jedes Object »/sbin/hotplug« auf. Als Argument dient die Klasse des Subsystems, also zum Beispiel »ieee1394«, »net«, »pci« oder »usb«. Weitere Informationen stecken in Umgebungsvariablen. Hierbei besitzt »ACTION« den Wert »add« oder »remove«. Die Variable »SEQNUM« wird bei jedem Aufruf inkrementiert. »DEVPATH« spezifiziert, wo im SysFS die Geräte-Informationen zu finden sind, zum Beispiel: /devices/pci0001:01/0001:01:19.0/usb2/2-1/2-1:1.0 Je nach Objekttyp exportiert Hotplug weitere Variablen: für physikalische Hardware die Vendor- und Produkt-IDs oder für USB in »DEVICE« den entsprechenden Eintrag im USB-FS, passend zum obigen Beispiel wäre dies »/proc/ bus/usb/002/010«. Die Hotplug-Skripte ordnen daraufhin anhand der Hardware-IDs das passende Kernelmodul mit Hilfe der Listen in »/lib/modules/$ver« zu und laden es. Für weitere Aktionen führt »/sbin/hotplug« alle Programme in »/etc/hotplug.d/« aus. In diese installiert auch Udev einen symbolischen Link »default/10-udev.hotplug« auf »/sbin/ udevsend« – ein Programm, das die Serialisierung der Hotplug-Events übernimmt und anschließend »/sbin/udev« aufruft. |
Für Udev ist ein Kernel 2.6 mit SysFS- und Hotplug- Unterstützung erforderlich. Bei manueller Kernelkonfiguration entsprechen diese beiden Features den folgenden Konfigurationsvariablen:
CONFIG_SYSFS=y CONFIG_HOTPLUG=y
In der Konfigurationsdatei »/etc/udev/udev.conf« finden sich die wichtigsten Variablen, um Udev einzustellen, zum Beispiel das Wurzelverzeichnis und der Ort der Udev-Datenbank:
udev_root="/udev/" udev_db="/udev/.udev.tdb"
Das Hotplug-System ruft im Auftrag des Kernels für jedes neu erkannte Gerät »/sbin/udev« auf. Udev führt die in »/etc/udev/« konfigurierten Aktionen aus und legt so für alle neu registrierten Geräte in »/udev« passende Dateien an. Diese Aktionen zeigt Abbildung 1 für den Fall einer USB-Maus und eines Druckers. Das Hotplug-Paket[4] lädt automatisch Treiber und Firmware. Dabei bleibt »/sbin/hotplug« der Hotplug-Manager, er ruft nach getaner Arbeit als Multiplexer alle in »/etc/hotplug.d« eingetragenen Programme auf. Nach einer Standardinstallation der neusten Hotplug- und Udev-Pakete sollten sie bereits korrekt zusammenspielen (siehe Kasten “Hotplug im Detail”).

Abbildung 2: Initialisiertes Udev-Verzeichnis: Dynamische Gerätedateien und die Datenbank ».udev.tdb«.
Namenskonventionen
Für die Konfiguration bietet Udev zwei Eingriffspunkte: In »/etc/udev/rules.d/« befinden sich Dateien mit Regeln zur Namensvergabe für die Device Nodes, in »/etc/udev/permissions.d« stehen die Zugriffsrechte. Die Regeln, die Udev mitliefert, erzeugen Device Nodes mit den von Linux bereits bekannten Namen – siehe Abbildung 2.
Für die Namensvergabe spezifizieren diese Regeln, welche Variablen zutreffen müssen, und den resultierendem Namen. Ein Eintrag für USB-Drucker lautet beispielsweise:
BUS="usb", KERNEL="lp[0-9]*", NAME="usb/%k"
Wenn das Gerät am Bus »usb« hängt und der interne Kernelname »lp« mit beliebiger Nummer ist, setzt Udev den Namen aus »usb/« und dem Kernelnamen zusammen. So ähnlich sind die meisten Regeln aufgebaut. Allerdings können sie auch externe Programmaufrufe enthalten, die ebenfalls als Bedingung gelten. Nur wenn der Aufruf das gewünschte Ergebnis liefert, führt Udev die anschließend aufgeführten Aktionen aus.
Die Manpage enthält ein Beispiel für IDE-CD-ROMS, es untersucht, ob ein entsprechendes »/proc«-Verzeichnis exis-tiert, in dem das Gerät als CD-ROM ausgegeben ist:
KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="%k", SYMLINK="cdrom%e"
Hierbei gibt Udev für alle Geräte, deren Name mit »hd« beginnt, mit »/bin/cat« den Inhalt der entsprechenden »media«-Datei aus, also zum Beispiel »/proc/ide/hda/media« für das erste IDE-Gerät. Enthält diese Datei den Text »cdrom«, behält Udev die Gerätedatei bei (»NAME=”%k”«), legt aber zusätzlich einen symbolischen Link »cdrom« an. Der Eintrag »%e« spezifiziert die nächste freie Dezimalzahl, falls eine gleichnamige Datei schon vorhanden ist. So entstehen symbolische Links in der folgender Form:
/dev/cdrom -> hdc /dev/cdrom1 -> sr0
Mit Hilfe eindeutiger Geräteseriennummern lassen sich stabile Namen erreichen – unabhängig von der Anschluss- oder Einschaltreihenfolge:
BUS="usb", SYSFS_serial="W090902071012413 30", NAME="lp-kyocera"
Rechtevergabe mit Udev
Die Regeln für die Rechte in »/etc/udev/ permissions.d« bestehen aus einer durch Doppelpunkte getrennten Tabelle mit Namen, Besitzer, Gruppe und den Zugriffsrechte selbst:
usb/lp*:root:lp:0660
Alle Gerätedateien mit Namen »usb/lp*« gehören dem Benutzer »root« und der Gruppe »lp«. Die Zugriffsrechte selbst »0600« sind im Oktalformat angegeben. Beim Systemstart initialisiert Udevstart die Nodes für die ganze im Rechner befindliche Hardware. Es iteriert über die Dateien in »/sys/class« und »/sys/block« und ruft jeweils »udev« auf. Distributionen wie Fedora simulieren beim Start dafür Hotplug-Events.
Es ist recht aufwändig, Udev auf Live- oder Installations-CDs zu verwenden. Die statischen Gerätedateien waren einfach da, während DevFS beim Booten die richtigen Nodes in einem virtuellen Dateisystem erzeugt. Im Fall von Udev muss die initiale RAM-Disk dafür einige Klimmzüge vollbringen.
Fazit
Udev ist ein komplexes System, das aus mehreren zusammenwirkenden Schichten (Hotplug-Skripte, »udevd«-Daemon, Hilfsprogramme für das Erzeugen von Namen) besteht. Einige Subsysteme wie IEEE1394 funktionieren noch nicht befriedigend, weil die entsprechenden Treiber nicht die nötigen SysFS-Informationen exportieren.
Einige DevFS-Kenner werden wohl die Möglichkeit missen, Module erst beim Zugriff auf ein Device Node zu laden. Udev kann dies aufgrund seiner Architektur nicht bieten: Die Kernelentwickler behaupten jedoch, dass dies sowieso unnötig sei und stattdessen die Geräte immer beim Hinzufügen (Hotplug) komplett konfiguriert werden sollten.
Ob die diversen Komponenten in der Praxis reibungslos zusammenspielen und nicht zu Konfigurationsproblemen führen, muss sich erst noch zeigen, wenn es weitere Verbreitung findet. Der aktuelle Stand macht bereits einen soliden Eindruck, Udev wird auch immer öfter auf produktiven Systemen eingesetzt. Aber es befindet sich noch in aktiver Entwicklung und ist somit häufigen Änderungen ausgesetzt. (ofr)
|
Infos |
|---|
|
[1] DevFS: [http://www.atnf.csiro.au/people/rgooch/linux/docs/devfs.html] [2] Udev-FAQ: [http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev-FAQ] [3] Udev and DevFS – The final word: [http://kernel.org/pub/linux/utils/kernel/hotplug/udev_vs_devfs] [4] Udev und Hotplug [http://www.kernel.org/pub/linux/utils/kernel/hotplug/] [5] Eva-Katharina Kunst, Jürgen Quade, “Kern-Technik – SysFS”, Folge 6: Linux-Magazin 01/04 S. 94 |
|
Der Autor |
|---|
|
RenŽ Rebe studiert Technische Informatik an der TFH-Berlin und kennt Linux leider erst seit 1997. Er arbeitet bei verschiedenen GNU-Projekten sowie Sane und GSMP mit. |






