Eine Einführung in Udev: Das Linux-Subsystem zur Verwaltung von Geräteereignissen

Udev ist das Linux-Subsystem, das Ihren Computer mit Geräteereignissen versorgt. Im Klartext bedeutet das, dass es der Code ist, der erkennt, wenn Sie etwas an Ihren Computer angeschlossen haben, wie z. B. eine Netzwerkkarte, externe Festplatten (einschließlich USB-Sticks), Mäuse, Tastaturen, Joysticks und Gamepads, DVD-ROM-Laufwerke und so weiter. Das macht es zu einem potenziell nützlichen Dienstprogramm, und es ist gut genug bekannt, dass ein normaler Benutzer es manuell mit einem Skript versehen kann, um bestimmte Aufgaben auszuführen, wenn eine bestimmte Festplatte angeschlossen wird.

In diesem Artikel lernen Sie, wie Sie ein udev-Skript erstellen, das durch ein udev-Ereignis ausgelöst wird, z. B. durch das Einstecken eines bestimmten USB-Laufwerks. Sobald Sie den Prozess für die Arbeit mit udev verstanden haben, können Sie damit alle möglichen Dinge tun, wie z.B. einen bestimmten Treiber laden, wenn ein Gamepad angeschlossen wird, oder ein automatisches Backup durchführen, wenn Sie Ihr Backup-Laufwerk anschließen.

Ein grundlegendes Skript

Der beste Weg, mit udev zu arbeiten, ist in kleinen Stücken. Schreiben Sie nicht das gesamte Skript im Voraus, sondern beginnen Sie mit etwas, das lediglich bestätigt, dass udev ein benutzerdefiniertes Ereignis auslöst.

Abhängig von Ihrem Ziel für Ihr Skript können Sie nicht garantieren, dass Sie die Ergebnisse eines Skripts jemals mit eigenen Augen sehen werden, also stellen Sie sicher, dass Ihr Skript protokolliert, dass es erfolgreich ausgelöst wurde. Der übliche Ort für Protokolldateien ist das Verzeichnis /var, aber das ist meist die Domäne des Root-Benutzers. Zum Testen verwenden Sie /tmp, auf das normale Benutzer zugreifen können und das in der Regel bei einem Neustart gelöscht wird.

Öffnen Sie Ihren bevorzugten Texteditor und geben Sie dieses einfache Skript ein:

#!/usr/bin/bash
/usr/bin/date >> /tmp/udev.log

Plazieren Sie es in /usr/local/bin oder an einem anderen Ort im Standardausführungspfad. Nennen Sie es trigger.sh und machen Sie es natürlich mit chmod +x ausführbar.

$ sudo mv trigger.sh /usr/local/bin
$ sudo chmod +x /usr/local/bin/trigger.sh

Dieses Skript hat nichts mit udev zu tun. Wenn es ausgeführt wird, legt das Skript einen Zeitstempel in der Datei /tmp/udev.log ab. Testen Sie das Skript selbst:

$ /usr/local/bin/trigger.sh
$ cat /tmp/udev.log
Tue Oct 31 01:05:28 NZDT 2035

Der nächste Schritt besteht darin, udev dazu zu bringen, das Skript auszulösen.

Einzige Geräteidentifikation

Damit Ihr Skript durch ein Geräteereignis ausgelöst werden kann, muss udev wissen, unter welchen Bedingungen es das Skript aufrufen soll. Im wirklichen Leben können Sie einen USB-Stick anhand seiner Farbe, des Herstellers und der Tatsache, dass Sie ihn gerade in Ihren Computer gesteckt haben, identifizieren. Ihr Computer benötigt jedoch eine andere Reihe von Kriterien.

Udev identifiziert Geräte anhand von Seriennummern, Herstellern und sogar Hersteller- und Produkt-ID-Nummern. Da Ihr udev-Skript noch in den Kinderschuhen steckt, sollten Sie die Kriterien so umfassend, unspezifisch und allumfassend wie möglich gestalten. Mit anderen Worten, Sie wollen zunächst fast jedes gültige udev-Ereignis abfangen, um Ihr Skript auszulösen.

Mit dem Befehl udevadm monitor können Sie udev in Echtzeit anzapfen und sehen, was es sieht, wenn Sie verschiedene Geräte einstecken. Werden Sie root und probieren Sie es aus.

$ su
# udevadm monitor

Die monitor-Funktion druckt empfangene Ereignisse für:

  • UDEV: das Ereignis, das udev nach der Regelverarbeitung aussendet
  • KERNEL: das Kernel-ue-Ereignis

Wenn udevadm monitor läuft, schließen Sie ein Laufwerk an und beobachten Sie, wie alle möglichen Informationen auf Ihren Bildschirm gespuckt werden. Beachten Sie, dass die Art des Ereignisses ein ADD-Ereignis ist. Das ist ein guter Weg, um herauszufinden, welche Art von Ereignis Sie wollen.

Der Befehl udevadm monitor liefert eine Menge guter Informationen, aber Sie können sie mit dem Befehl udevadm info in einer schöneren Formatierung sehen, vorausgesetzt, Sie wissen, wo sich Ihr Thumb-Laufwerk derzeit in Ihrem /dev-Baum befindet. Wenn nicht, ziehen Sie das Laufwerk ab und schließen Sie es wieder an, und geben Sie dann sofort diesen Befehl ein:

$ su -c 'dmesg | tail | fgrep -i sd*'

Wenn dieser Befehl beispielsweise sdb: sdb1 zurückgibt, wissen Sie, dass der Kernel Ihrem Laufwerk das Label sdb zugewiesen hat.

Alternativ können Sie den Befehl lsblk verwenden, um alle an Ihr System angeschlossenen Laufwerke einschließlich ihrer Größe und Partitionen anzuzeigen.

Nachdem Sie nun festgestellt haben, wo sich Ihr Laufwerk in Ihrem Dateisystem befindet, können Sie mit diesem Befehl udev-Informationen über dieses Gerät anzeigen:

# udevadm info -a -n /dev/sdb | less

Dieser Befehl liefert eine Menge Informationen. Konzentrieren Sie sich zunächst auf den ersten Informationsblock.

Ihre Aufgabe ist es, die Teile des udev-Berichts über ein Gerät herauszufiltern, die für dieses Gerät am eindeutigsten sind, und dann udev anzuweisen, Ihr Skript auszulösen, wenn diese eindeutigen Attribute entdeckt werden.

Der udevadm info-Prozess berichtet über ein Gerät (angegeben durch den Gerätepfad) und „wandert“ dann die Kette der übergeordneten Geräte hinauf. Für jedes gefundene Gerät gibt er alle möglichen Attribute in einem Schlüssel-Wert-Format aus. Sie können eine Regel so zusammenstellen, dass sie die Attribute eines Geräts und die Attribute eines einzelnen übergeordneten Geräts berücksichtigt.

looking at device '/devices/000:000/blah/blah//block/sdb':
KERNEL=="sdb"
SUBSYSTEM=="block"
DRIVER==""
ATTR{ro}=="0"
ATTR{size}=="125722368"
ATTR{stat}==" 2765 1537 5393"
ATTR{range}=="16"
ATTR{discard\_alignment}=="0"
ATTR{removable}=="1"
ATTR{blah}=="blah"

Eine udev-Regel muss ein Attribut eines einzelnen übergeordneten Geräts enthalten.

Elternattribute sind Dinge, die ein Gerät auf der grundlegendsten Ebene beschreiben, wie zum Beispiel, dass es etwas ist, das in einen physischen Anschluss eingesteckt wurde, oder dass es etwas mit einer bestimmten Größe ist, oder dass es sich um ein Wechseldatenträger handelt.

Da die KERNEL-Bezeichnung von sdb sich ändern kann, je nachdem, wie viele andere Laufwerke eingesteckt waren, bevor man dieses Daumenlaufwerk eingesteckt hat, ist das nicht das optimale Elternattribut für eine udev-Regel. Für einen Proof of Concept funktioniert es jedoch, so dass Sie es verwenden könnten. Ein noch besserer Kandidat ist das SUBSYSTEM-Attribut, das kennzeichnet, dass es sich um ein „Block“-Systemgerät handelt (weshalb der Befehl lsblk das Gerät auflistet).

Öffnen Sie eine Datei namens 80-local.rules in /etc/udev/rules.d und geben Sie folgenden Code ein:

SUBSYSTEM=="block", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

Speichern Sie die Datei, ziehen Sie das Testlaufwerk ab und booten Sie neu.

Warten Sie, booten Sie auf einem Linux-Rechner neu?

Theoretisch können Sie einfach udevadm control –reload eingeben, was alle Regeln laden sollte, aber in diesem Stadium des Spiels ist es am besten, alle Variablen zu eliminieren. Udev ist schon komplex genug, und Sie wollen nicht die ganze Nacht im Bett liegen und sich fragen, ob diese Regel wegen eines Syntaxfehlers nicht funktioniert hat oder ob Sie einfach hätten neu booten sollen. Starten Sie also neu, egal was Ihr POSIX-Stolz Ihnen sagt.

Wenn Ihr System wieder online ist, wechseln Sie zu einer Textkonsole (mit Ctl+Alt+F3 oder ähnlich) und schließen Sie Ihr Laufwerk an. Wenn Sie einen aktuellen Kernel verwenden, werden Sie wahrscheinlich eine Reihe von Ausgaben in der Konsole sehen, wenn Sie das Laufwerk einstecken. Wenn Sie eine Fehlermeldung wie Could not execute /usr/local/bin/trigger.sh sehen, haben Sie wahrscheinlich vergessen, das Skript ausführbar zu machen. Andernfalls sehen Sie hoffentlich nur, dass ein Gerät eingesteckt wurde, dass es eine Art von Kernel-Gerätezuweisung erhalten hat und so weiter.

Jetzt kommt der Moment der Wahrheit:

$ cat /tmp/udev.log
Tue Oct 31 01:35:28 NZDT 2035

Wenn Sie ein sehr aktuelles Datum und eine Uhrzeit in /tmp/udev.log sehen, hat udev Ihr Skript erfolgreich ausgelöst.

Verfeinern der Regel zu etwas Nützlichem

Das Problem mit dieser Regel ist, dass sie sehr allgemein ist. Das Einstecken einer Maus, eines USB-Sticks oder des USB-Sticks einer anderen Person löst Ihr Skript wahllos aus. Jetzt ist es an der Zeit, sich genau auf das Laufwerk zu konzentrieren, das Ihr Skript auslösen soll.

Eine Möglichkeit, dies zu tun, ist die Hersteller-ID und die Produkt-ID. Um diese Nummern zu erhalten, können Sie den Befehl lsusb verwenden.

$ lsusb
Bus 001 Device 002: ID 8087:0024 Slacker Corp. Hub
Bus 002 Device 002: ID 8087:0024 Slacker Corp. Hub
Bus 003 Device 005: ID 03f0:3307 TyCoon Corp.
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 hub
Bus 001 Device 003: ID 13d3:5165 SBo Networks

In diesem Beispiel steht die 03f0:3307 vor TyCoon Corp. für die Attribute idVendor und idProduct. Sie können diese Zahlen auch in der Ausgabe von udevadm info -a -n /dev/sdb | grep vendor sehen, aber ich finde die Ausgabe von lsusb etwas übersichtlicher.

Sie können diese Attribute nun in Ihre Regel aufnehmen.

SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/thumb.sh"

Testen Sie dies (ja, Sie sollten immer noch einen Neustart durchführen, nur um sicherzugehen, dass Sie frische Reaktionen von udev erhalten), und es sollte genauso funktionieren wie vorher, nur dass jetzt, wenn Sie z.B. ein Thumb-Laufwerk anschließen, das von einer anderen Firma hergestellt wurde (daher mit einem anderen idVendor) oder eine Maus oder einen Drucker, das Skript nicht ausgelöst wird.

Fügen Sie immer wieder neue Attribute hinzu, um sich weiter auf das eine einzigartige Thumb-Laufwerk zu konzentrieren, das Ihr Skript auslösen soll. Mit udevadm info -a -n /dev/sdb können Sie Dinge wie den Herstellernamen, manchmal eine Seriennummer oder den Produktnamen usw. herausfinden.

Für Ihre eigene Vernunft sollten Sie jeweils nur ein neues Attribut hinzufügen. Die meisten Fehler, die ich gemacht habe (und die ich auch bei anderen Online-Nutzern gesehen habe), bestehen darin, eine Reihe von Attributen in ihre udev-Regel zu packen und sich dann zu wundern, warum das Ding nicht mehr funktioniert. Ein Attribut nach dem anderen zu testen ist der sicherste Weg, um sicherzustellen, dass udev Ihr Gerät erfolgreich identifizieren kann.

Sicherheit

Dies bringt die Sicherheitsbedenken beim Schreiben von udev-Regeln zum Ausdruck, die automatisch etwas tun, wenn ein Laufwerk eingesteckt wird. Auf meinen Rechnern habe ich nicht einmal Auto-Mount aktiviert, und dennoch schlägt dieser Artikel Skripte und Regeln vor, die Befehle ausführen, nur weil etwas angeschlossen ist.

Zwei Dinge sind hier zu beachten.

  1. Fokussieren Sie Ihre udev-Regeln, sobald Sie sie zum Laufen gebracht haben, so dass sie Skripte nur dann auslösen, wenn Sie es wirklich wollen. Die Ausführung eines Skripts, das blind Daten auf oder von Ihrem Computer kopiert, ist eine schlechte Idee, falls jemand, der zufällig die gleiche Marke eines USB-Sticks bei sich hat, diesen in Ihre Box einsteckt.
  2. Schreiben Sie Ihre udev-Regeln und Skripte nicht und vergessen Sie sie. Ich weiß, auf welchen Computern meine udev-Regeln installiert sind, und das sind meistens meine privaten Computer, nicht die, die ich zu Konferenzen mitnehme oder in meinem Büro bei der Arbeit habe. Je „sozialer“ ein Computer ist, desto unwahrscheinlicher ist es, dass er eine udev-Regel bekommt, die möglicherweise dazu führt, dass meine Daten auf dem Gerät eines anderen landen oder dass Daten oder Malware eines anderen auf meinem Gerät landen.

Mit anderen Worten, wie bei so viel Macht, die ein GNU-System bietet, ist es Ihre Aufgabe, darauf zu achten, wie Sie diese Macht ausüben. Wenn Sie sie mißbrauchen oder sie nicht mit Respekt behandeln, könnte das sehr wohl schrecklich schiefgehen.

Udev in der realen Welt

Nun, da Sie bestätigen können, daß Ihr Skript von udev ausgelöst wird, können Sie Ihre Aufmerksamkeit auf die Funktion des Skripts richten. Im Moment ist es nutzlos, da es nichts weiter tut, als die Tatsache zu protokollieren, dass es ausgeführt wurde.

Ich verwende udev, um automatische Backups meiner Thumbdrives auszulösen. Die Idee ist, dass sich die Master-Kopien meiner aktiven Dokumente auf meinem USB-Stick befinden (da ich ihn überallhin mitnehme und er jederzeit bearbeitet werden könnte), und dass diese Master-Dokumente jedes Mal auf meinem Computer gesichert werden, wenn ich den Stick an diesen Rechner anschließe. Mit anderen Worten: Mein Computer ist das Backup-Laufwerk und meine Produktionsdaten sind mobil. Der Quellcode ist verfügbar, also schauen Sie sich den Code von attachup an, um weitere Beispiele für die Einschränkung Ihrer udev-Tests zu erhalten.

Da ich udev am häufigsten dafür verwende, ist es das Beispiel, das ich hier verwende, aber udev kann viele andere Dinge erfassen, wie Gamepads (dies ist nützlich auf Systemen, die nicht so eingestellt sind, dass das xboxdrv-Modul geladen wird, wenn ein Gamepad angeschlossen ist) und Kameras und Mikrofone (nützlich, um Eingänge zu setzen, wenn ein bestimmtes Mikrofon angeschlossen ist), so dass es für viel mehr als dieses eine Beispiel gut ist.

Eine einfache Version meines Sicherungssystems besteht aus zwei Befehlen:

SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", SYMLINK+="safety%n"
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

Die erste Zeile erkennt mein Thumb-Laufwerk mit den bereits besprochenen Attributen und weist dem Thumb-Laufwerk dann einen Symlink innerhalb des Gerätebaums zu. Der Symlink, der zugewiesen wird, ist safety%n. Das %n ist ein udev-Makro, das sich in eine beliebige Nummer auflöst, die der Kernel dem Gerät zuweist, z.B. sdb1, sdb2, sdb3 und so weiter. %n wäre also die 1 oder die 2 oder die 3.

Dies erzeugt einen Symlink im Dev-Baum, so dass es den normalen Prozess des Anschließens eines Geräts nicht beeinträchtigt. Das bedeutet, dass Sie, wenn Sie eine Desktop-Umgebung verwenden, die Geräte automatisch einbindet, keine Probleme verursachen werden.

Die zweite Zeile führt das Skript aus.

Mein Backup-Skript sieht so aus:

#!/usr/bin/bash
mount /dev/safety1 /mnt/hd
sleep 2
rsync -az /mnt/hd/ /home/seth/backups/ && umount /dev/safety1

Das Skript verwendet den Symlink, der verhindert, dass udev dem Laufwerk einen unerwarteten Namen gibt (wenn ich zum Beispiel ein Laufwerk mit dem Namen DISK bereits an meinen Computer angeschlossen habe und ich mein anderes Laufwerk mit dem Namen DISK anschließe, wird das zweite Laufwerk mit DISK_ bezeichnet, was mein Skript durchkreuzen würde). Es hängt safety1 (die erste Partition des Laufwerks) an meinem bevorzugten Einhängepunkt /mnt/hd ein.

Nach dem sicheren Einhängen verwendet es rsync, um das Laufwerk in meinem Backup-Ordner zu sichern (mein aktuelles Skript verwendet rdiff-backup, und Ihr Skript kann eine beliebige automatisierte Backup-Lösung verwenden).

Udev ist Ihr dev

Udev ist ein sehr flexibles System und ermöglicht es Ihnen, Regeln und Funktionen auf eine Art und Weise zu definieren, die nur wenige andere Systeme den Benutzern bieten. Lernen Sie es und benutzen Sie es, und genießen Sie die Macht von POSIX.

Dieser Artikel basiert auf Inhalten aus dem Slackermedia-Handbuch, das unter der GNU Free Documentation License 1.3 lizenziert ist.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.