!!! udev

Udev dient seit dem Linux-Kernel 2.6 dazu, alle Geräte des Systems automatisch zu konfigurieren. Dabei ist die Philosophie (im Gegensatz zu früher), daß ein Userspace-Programm (nämlich udev) erfährt, wenn ein Device in das System kommt (beim hochfahren oder wenn z.B. ein USB-Gerät eingesteckt wird). In ''/etc/udev'' gibt es nun umfangreiche Konfigurationsdateien. Dort kann man festlegen, welches Gerät dann wie heissen soll. Udev sorgt dabei automatisch dafür, daß ein bestimmtes Gerät immer unter dem gleichen Namen erreichbar ist. So ist die USB-Kamera immer an derselben Stelle (am besten z.B. an /dev/camera) und nicht zufällig gerade heute mal auf ''/dev/sdc'', weil ich vorher zwei Flashkarten eingelegt habe (wie früher üblich).

Die udev-Weseite findet sich unter http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html.

Hier soll nicht die udev-Dokumentation wiederholt werden. Stattdessen möchte ich hier (mindestens) einen Fallstrick dokumentieren, der mich viel Zeit gekostet hat.

! Netzwerkkarte auf einmal weg

Folgendes ist passiert: Ich habe einen Rechner mit einer internen Netzwerkkarte (forcedeth) installiert. Bei der Debian Etch-Installation wurde diese Karte als "eth0" eingebunden. Bis dahin war ich gar nicht erstaunt. Was ich nicht wusste, ist, daß diese Namensgebung neuerdings von udev gemacht wird und udevs Philosophie bedeutet, daß ein Gerät, das man einmal eingebaut hat, in Zukunft immer unter dem gleichen Namen erreichbar sein soll. Also merkt sich udev in ''etc/udev/rules.d/z25_persistent-net.rules'' diese Karte.

Nun habe ich eine zweite Netzwerkkarte installiert. Das System hat diese (8139too) aus irgendeinem Grund (vor dem udev-Start) als erste und die forcedeth als eth1 installiert. Nun meinte udev, die forcedeth als eth0 einrichten zu müssen. Da eth0 aber schon besetzt war, hat es sich dieses auch gemerkt, die forcedeth umbenannt in __eth1_rename__ und fertig.

Jetzt hatte ich in ''etc/udev/rules.d/z25_persistent-net.rules'' beide Karten als eth0 stehen und in welcher Reihenfolge ich die Module auch lud, ein eth1 bekam ich nicht.

__Fazit:__ Wem also plötzlich eine zweie Netzwerkkarte fehlt, der sollte mal {{ifconfig -a}} machen. Findet man eine {{*_rename}}-Karte, so kann ein Blick in o.g. Datei nicht schaden. -- ThomasBayen

!! Netzwerkkarte unter Xen weg

Unter [XEN] kommt es, wenn man '''udev''' benutzt, ebenfalls dazu, das Devices verschwinden (bzw. einen anderen Namen bekommen). Dies kann man auch mit {{ifconfig -a}} kontrollieren. Dies liegt daran, daß Xen bei jeder Erzeugung einer virtuellen Domain die Mac-Adresse der Netzwerkkarten neu zufällig erzeugt. Damit sieht es von "innen" so aus, als ob bei jedem Starte eine neue Netzwerkkarte zum Einsatz käme. Dies kann man beheben, indem man entweder die Mac-Adresse in der Konfigurationsdatei der Xen-Domain fest vergibt, oder in der Datei ''/etc/udev/rules.d/z45_persistent-net-generator.rules'' folgende Zeile (am besten ganz oben) einfügt:

  SUBSYSTEMS=="xen", GOTO="persistent_net_generator_end"



!! Permissions für Devicedateien setzen

Das Acceleratormodul für [QEmu] nennt sich __kqemu__. Ich möchte dieses Modul z.B. beim Systemstart laden und dann durch einen normalen Benutzer [QEmu] starten. Um das für mehrere Benutzer zu erlauben, kommen diese in eine gemeinsame Gruppe ''qemu''.

Hierzu erzeuge ich eine Datei ''/etc/udev/rules.d/022_qemu.rules'', in der folgendes steht:
{{{
KERNEL=="kqemu",      MODE="0660", GROUP="qemu"
}}}

Und fertig. Die *.rules-Dateien werden alphabetisch abgearbeitet und beim laden des neuen Moduls werden die angegebenen Parameter direkt gesetzt. -- ThomasBayen

# Qemu sollte mit '''major=0''' in ''/etc/modules'' stehen (bzw. vor dem [QEmu]-Start geladen werden) sonst bringt das alles nichts ;)
# einfach in Debian Etch (keine Ahnung, ob das bei Sarge auch geht ;) )
## apt-get install kqemu-source && module-assistant prepare kqemu && module-assistant build kqemu 
## installiere das erzeugte .deb und fertig  -- JensKapitza


!! USB-Drucker fest zuordnen

Ich möchte an einem Computer zwei USB-Drucker anbringen. Das Problem ist, daß diese beim Hochfahren keine feste Reihenfolge bekommen und deshalb jeweils mal lp0 und mal lp1 sind. Habe ich beim Booten einen der Drucker nicht eingeschaltet, schnappt der andere sich sowieso das erste Device "lp0". Theoretisch kann man anhand der Drucker-ID die Drucker in einer udev-Regel unterscheiden. Bei mir war es jedoch noch komplizierter, da ich zwei identische Drucker anschliesse, die anhand der ID nicht unterscheidbar sind. Sie enthalten jedoch unterschiedliches Papier (Listen- und Formulardrucker), weshalb sie auf keinen Fall vertauscht werden dürfen.

Das geht aber mit udev auch: Jede USB-Buchse hat eine eindeutige Bus-ID. Anhand derer kann man die Drucker dann benennen. Die Regeldatei ''/etc/udev/rules.d/024_printer.rules'' sieht dann z.B. so aus:
{{{
BUS="usb", KERNEL="lp[0-9]*", ID="2-1:1.0",  SYMLINK+="usb/liste"
BUS="usb", KERNEL="lp[0-9]*", ID="2-2:1.0",  SYMLINK+="usb/formular"
}}}

Hierdurch werden neben den normalen Devices Symlinks unter den von mir gewünschten Namen angelegt, die ich dann z.B. in CUPS angeben kann, um die Drucker zu benutzen.

Wichtig ist übrigens, daß der angegebene Kernel-Name nicht in einer vorhergehenden Regel umbenannt wurde. Dies geschieht nämlich in meinem Debian Sarge-System in der Datei ''devfs.rules'' (dort wird''lp0'' zu ''usb/lp0''), weshalb meine Datei alphabetisch davor stehen muss. -- ThomasBayen


!! Beispiel

Dies soll ein Beispiel sein, wie man eine völlig neue udev-Regel für ein vorhandenes Device erzeugt, um ein eigenes Skript zu starten.

Ich habe einen Schalter an meinem Sony Vaio, der sowohl WLAn als auch Bluetooth ein- und ausschaltet. Dabei wird beim WLAN wohl nur die Antenne ausgeschaltet, beim Bluetooth aber das ganze (USB-) Gerät abgemeldet. Ich möchte nun mein WLAN entsprechend dieses Schalters hoch- und runterfahren. Da ich nicht direkt ein Event für den Schalter der WLAN-Antenne bekomme, möchte ich nun mein up- und down-Skript starten, wenn das Bluetooth-Device ein- bzw. ausgehangen wird. Hier bescshreibe ich Schritt für SChritt, wie ich vorgegangen bin.

Meine Konfiguration kommt in eine Datei, die z.B. ''rules.d/99-tbayen.rules'' heisst.

Zuerst habe ich aus dem Systemlog die Product- und Vendor-ID meines Gerätes herausgefunden. Dann habe ich folgende Test-Regel geschrieben:

  SUBSYSTEMS=="usb", ATTRS{idProduct}=="3017", ATTRS{idVendor}=="044e", \
      RUN="/usr/bin/logger BLA"

Das erzeugt einen Eintrag im System-Log, wenn die angegebenen Regeln zutreffen. Leider passiert das nur beim ein- aber nicht beim Ausschalten des Gerätes. Die angegebenen "ATTRS" sind die Inhalte der gleichnamigen Dateien im sys-Filesystem, also z.B. der Datei ''/sys/devices/pci0000:00/0000:00:1d.7/usb8/8-6/idProduct''. Offensichtlich sind diese Dateien in dem Moment, wenn das Device entfernt wird und sich undev damit beschäftigt, aber bereits weg (udev läuft wahrscheinlich erst nach dem Entfernen des Kerneltreibers).

Allerdings kennt udev dennoch einige Informationen mehr und schreibt diese in seine Environment-Variablen. Diese habe ich mit folgender Regel ausgegeben

  SUBSYSTEMS=="usb", RUN="/bin/bash -c '/usr/bin/logger `env`'"

und meine Regel dann entsprechend angepasst, um genau die Events zu bekommen, die ich haben will:

  SUBSYSTEMS=="usb", ENV{PRODUCT}=="44e/3017/218", ENV{DEVTYPE}=="usb_device", \
      RUN="/usr/bin/logger BLA"

Nun kann man anhand der Environment-Variable "ACTION" noch die Fälle des Ein- und Ausstöpselns unterscheiden. Meine fertige Regel sah dann so aus:

  SUBSYSTEMS=="usb", \
        ENV{PRODUCT}=="44e/3017/218", ENV{DEVTYPE}=="usb_device", \
        ENV{ACTION}=="add", \
                RUN="/bin/bash -c '/sbin/ifup wlan0 & >/dev/null </dev/null 2>&1'"

  SUBSYSTEMS=="usb", \
        ENV{PRODUCT}=="44e/3017/218", ENV{DEVTYPE}=="usb_device", \
        ENV{ACTION}=="remove", \
                RUN="/bin/bash -c '/sbin/ifdown wlan0 & >/dev/null </dev/null 2>&1''"

Den Umweg über bash und die Umleitungen habe ich gewählt, damit die Skripte im Hintergrund ablaufen, weil ansonsten der ganze udev-Daemon warten muss und das Skript (gerade beim WLAN) lange laufen kann, bis es sich beendet.


!! Symlink zu angelegtem Device erzeugen

Stecke ich mein Nokia N900 (mit [[Maemo]] System) in meinen PC, so werden automatisch mehrere Devices erzeugt, u.a. ein Modem-Device unter ''/dev/ttyACM0''. Hierfür möchte ich gerne einen Symlink haben, der ''/dev/modem'' heisst. Das eigentliche Problem ist, herauszufinden, mit welcher Symlink-Regel man dieses Device findet.

Mit einer Regel wie

  RUN="/bin/bash -c 'export | /usr/bin/logger'"

ergibt sich eine unmenge Geschwafel, wenn man ein Gerät einsteckt, aber dafür stehen alle Umgebungsvariablen im logfile, die man dann benutzen kann, um das Gerät in einer udev-Rule auszuwählen.

Im Ergebnis bedeutet das, ich erzeuge eine neue Datei "/etc/udev/rules.d/99-tbayen.rules", in die eine entsprechende Regel kommt. Je nach Geschmack kann man dabei die major- und minor-Nummer angeben (die vielleicht von anderen Devices auch benutzt wird) oder auch lesbarere
Device-Namen (die dann natürlich beim nächsten Handy nicht mehr passen). Daher hier zwei Varianten:

  SUBSYSTEM=="tty", ENV{MAJOR}="166", ENV{MINOR}=0, SYMLINK+="modem"
  SUBSYSTEM=="tty", ENV{ID_VENDOR}="Nokia", ENV{ID_MODEL}="N900__PC-Suite_Mode_", SYMLINK+="modem"

Möchte man das "Geschwafel" umgehen, kann ein Blick in

  /sys/class/tty/ttyACM0/uevent

bzw. in

  /sys/class/tty/ttyACM0/device/...

nicht schaden. Dort werden die Werte, die in den Environment-Variablen stehen, offensichtlich hergeholt.



!! Udev-Troubleshooting

Udev legt Devicenodes mit den vom Kernel vorgeschlagenen Namen an.

Hier nochmal ein paar von den Befehlen, die bei der Erforschung 
dieses Krams interessant sein könnten:

 udevinfo -q symlink -n /dev/sda

zeigt alle Symlinks zum genannten Device

 udevcontrol log_priority=info

zeigt die Vorgänge im Syslog. Zurückstellen kann man das mit 
"err" statt "info", ausführlicher geht es mit "debug".
"uevent" bezeichnet die Nachrichten vom Kernel ans udev,
"udev" bezeichnet die von udev abgehenden Nachrichten.

Die udev-Konfigurationsdateien kann man kennenlernen, wenn man 
sich die Plattenbehandlung ansieht -- die ist ziemlich genau 
das, wofür udev gedacht ist. Siehe Dateien z.B. in 
__/etc/udev/rules.d__.

! Parameter herausfinden

Um die Parameter für eigene Regeln herauszufinden, habe ich eine Datei ''rules.d/99-tbayen.rules'' mit folgendem Inhalt angelegt:

  SUBSYSTEMS=="usb", RUN="/bin/bash -c '/usr/bin/logger `env`'"

Nun bekomme ich im Systemlog eine ausführliche Auflistung der Systemvariablen, aus denen ich mir dann etwas herauspflücken kann.

! HAL

Um udev zu verstehen muss man nichts über "hal" wissen -- der 
wird entgegen vielen Gerüchten nicht von udev benutzt und ist 
nur ein udev-Nutzniesser. Beim Lesen von Sachen über "hal" 
würde ich gleichzeitig das Programm ''hal-device-manager'' laufen 
lassen (gehört zu gnome), um ein bischen die Realität im 
Rechner mit den Konzepten vergleichen zu können.

--MarkusMonderkamp und W. Spickermann am 08.02.2008

! Laden von Kernelmodulen verhindern

If you pass load_modules=off on your kernel boot line, then udev will skip all the auto-loading business. This is to provide you with a big ripcord to pull if something goes wrong. If udev loads a problematic module that hangs your system or something equally awful, then you can bypass auto-loading with this parameter, then go in and blacklist the offensive module(s).

--- ich habe es nur gelesen 
--- blacklist hat mir gereicht! 

KaiEhlers:
 http://wiki.archlinux.org/index.php/Udev   

Google dochmal nach Kernel Module laden verhindern, G. --JensKapitza


!!Trackbacks

*[Schwabenblog|http://www.schwabenblog.eu/archives/36-XEN-und-udev.html]

----
[{Tag Linux Hardware}]