Udev is het Linux-subsysteem dat uw computer voorziet van apparaatgebeurtenissen. In gewoon Nederlands betekent dit dat het de code is die detecteert wanneer je dingen op je computer hebt aangesloten, zoals een netwerkkaart, externe harde schijven (inclusief USB-sticks), muizen, toetsenborden, joysticks en gamepads, DVD-ROM-stations, enzovoort. Dat maakt het een potentieel nuttig hulpprogramma, en het is voldoende blootgesteld dat een standaardgebruiker het handmatig kan scripten om dingen te doen zoals het uitvoeren van bepaalde taken wanneer een bepaalde harde schijf wordt aangesloten.
Dit artikel leert u hoe u een udev-script kunt maken dat wordt geactiveerd door een udev-gebeurtenis, zoals het aansluiten van een specifieke thumbdrive. Als u eenmaal het proces voor het werken met udev begrijpt, kunt u het gebruiken om allerlei dingen te doen, zoals het laden van een specifiek stuurprogramma wanneer een gamepad wordt aangesloten, of het uitvoeren van een automatische back-up wanneer u uw back-upschijf aansluit.
Een basisscript
De beste manier om met udev te werken is in kleine brokjes. Schrijf niet het hele script van tevoren, maar begin in plaats daarvan met iets dat simpelweg bevestigt dat udev een of andere aangepaste gebeurtenis triggert.
Afhankelijk van uw doel voor uw script, kunt u niet garanderen dat u ooit de resultaten van een script met uw eigen ogen zult zien, dus zorg ervoor dat uw script logt dat het met succes werd geactiveerd. De gebruikelijke plaats voor logbestanden is in de /var directory, maar dat is meestal het domein van de root gebruiker. Gebruik voor het testen /tmp, dat toegankelijk is voor normale gebruikers en meestal wordt opgeschoond bij een reboot.
Open je favoriete tekst editor en voer dit eenvoudige script in:
#!/usr/bin/bash
/usr/bin/date >> /tmp/udev.log
Plaats dit in /usr/local/bin of een andere plaats in het standaard uitvoerbare pad. Noem het trigger.sh en, natuurlijk, maak het uitvoerbaar met chmod +x.
$ sudo mv trigger.sh /usr/local/bin
$ sudo chmod +x /usr/local/bin/trigger.sh
Dit script heeft niets te maken met udev. Wanneer het script wordt uitgevoerd, plaatst het een tijdstempel in het bestand /tmp/udev.log. Test het script zelf:
$ /usr/local/bin/trigger.sh
$ cat /tmp/udev.log
Tue Oct 31 01:05:28 NZDT 2035
De volgende stap is om udev het script te laten triggeren.
Unieke apparaatidentificatie
Om uw script te laten triggeren door een apparaatgebeurtenis, moet udev weten onder welke condities het het script moet aanroepen. In het echte leven kunt u een thumb drive identificeren door zijn kleur, de fabrikant, en het feit dat u hem net in uw computer gestoken hebt. Uw computer heeft echter een andere set criteria nodig.
Udev identificeert apparaten aan de hand van serienummers, fabrikanten, en zelfs vendor ID en product ID nummers. Aangezien dit een vroeg stadium is in het leven van uw udev script, moet u zo breed, niet-specifiek en allesomvattend mogelijk zijn. Met andere woorden, je wilt eerst bijna elke geldige udev gebeurtenis opvangen om je script te triggeren.
Met het udevadm monitor commando, kun je in real time in udev tappen en zien wat het ziet wanneer je verschillende apparaten aansluit. Word root en probeer het.
$ su
# udevadm monitor
De monitor functie drukt ontvangen events af voor:
- UDEV: de event die udev uitzendt na regelverwerking
- KERNEL: de kernel uevent
Met udevadm monitor aan, sluit een thumb drive aan en kijk hoe allerlei informatie op uw scherm wordt gespuwd. Merk op dat het type gebeurtenis een ADD gebeurtenis is. Dat is een goede manier om te identificeren welk type event je wilt.
Het udevadm monitor commando geeft veel goede info, maar je kunt het met mooiere opmaak zien met het commando udevadm info, ervan uitgaande dat je weet waar je thumb drive zich momenteel bevindt in je /dev tree. Als dat niet het geval is, haalt u de stekker uit het stopcontact en steekt u deze er weer in, en voert u onmiddellijk dit commando uit:
$ su -c 'dmesg | tail | fgrep -i sd*'
Als dat commando bijvoorbeeld sdb: sdb1 teruggeeft, weet u dat de kernel uw thumb drive het label sdb heeft gegeven.
Aternatief kunt u het lsblk commando gebruiken om alle drives te zien die aan uw systeem hangen, inclusief hun grootte en partities.
Nu u hebt vastgesteld waar uw drive zich in uw bestandssysteem bevindt, kunt u udev informatie over dat apparaat bekijken met dit commando:
# udevadm info -a -n /dev/sdb | less
Dit retourneert een heleboel informatie. Focus op het eerste blok info voor nu.
Jouw taak is om delen van udev’s rapport over een apparaat eruit te pikken die het meest uniek zijn voor dat apparaat, en dan udev te vertellen om je script te triggeren wanneer die unieke attributen worden gedetecteerd.
Het udevadm info proces rapporteert over een apparaat (opgegeven door het apparaatpad), en “loopt” dan langs de keten van bovenliggende apparaten. Voor elk gevonden apparaat worden alle mogelijke attributen afgedrukt in een sleutel-waarde formaat. U kunt een regel samenstellen die overeenkomt met de attributen van een apparaat plus attributen van een enkel bovenliggend apparaat.
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"
Een udev regel moet een attribuut van een enkel bovenliggend apparaat bevatten.
Parent attributen zijn dingen die een apparaat beschrijven vanaf het meest basale niveau, zoals het is iets dat is aangesloten op een fysieke poort of het is iets met een grootte of dit is een verwijderbaar apparaat.
Omdat het KERNEL label van sdb kan veranderen afhankelijk van hoeveel andere schijven waren aangesloten voordat je die thumb drive inplugde, is dat niet het optimale parent attribuut voor een udev regel. Het werkt echter voor een proof of concept, dus je zou het kunnen gebruiken. Een nog betere kandidaat is het SUBSYSTEM attribuut, dat identificeert dat dit een “block” systeemapparaat is (dat is waarom het lsblk commando het apparaat noemt).
Open een bestand genaamd 80-local.rules in /etc/udev/rules.d en voer deze code in:
SUBSYSTEM=="block", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"
Bewaar het bestand, koppel je test thumb drive los, en reboot.
Wacht, reboot op een Linux machine?
Theoretisch kun je gewoon udevadm control –reload uitvoeren, wat alle regels zou moeten laden, maar in dit stadium van het spel, is het het beste om alle variabelen te elimineren. Udev is al complex genoeg, en u wilt zich niet de hele nacht in bed liggen afvragen of die regel niet werkte vanwege een syntaxisfout of dat u gewoon had moeten herstarten. Dus reboot ongeacht wat uw POSIX trots u vertelt.
Wanneer uw systeem terug online is, schakel dan over naar een tekst console (met Ctl+Alt+F3 of gelijkaardig) en plug uw thumb drive in. Als u een recente kernel draait, zult u waarschijnlijk een hoop uitvoer in uw console zien wanneer u de schijf insteekt. Als u een foutmelding ziet zoals Could not execute /usr/local/bin/trigger.sh, dan bent u waarschijnlijk vergeten om het script uitvoerbaar te maken. Anders, hopelijk is alles wat u ziet een apparaat dat werd aangesloten, het kreeg een soort kernel apparaat toewijzing, enzovoort.
Nu, het moment van de waarheid:
$ cat /tmp/udev.log
Tue Oct 31 01:35:28 NZDT 2035
Als u een zeer recente datum en tijd terug ziet in /tmp/udev.log, dan heeft udev met succes uw script getriggerd.
Refining the rule into something useful
Het probleem met deze regel is dat het erg algemeen is. Het inpluggen van een muis, een thumb drive, of iemand anders thumb drive zal zonder onderscheid je script triggeren. Nu is het tijd om je te concentreren op de exacte thumb drive die je script moet triggeren.
Een manier om dit te doen is met de vendor ID en product ID. Om deze nummers te krijgen, kunt u het lsusb commando gebruiken.
$ 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 dit voorbeeld geeft het 03f0:3307 voor TyCoon Corp. de idVendor en idProduct attributen aan. U kunt deze nummers ook zien in de uitvoer van udevadm info -a -n /dev/sdb | grep vendor, maar ik vind de uitvoer van lsusb een beetje gemakkelijker voor het oog.
U kunt deze attributen nu opnemen in uw regel.
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/thumb.sh"
Test dit (ja, je moet nog steeds rebooten, gewoon om er zeker van te zijn dat je verse reacties van udev krijgt), en het zou hetzelfde moeten werken als voorheen, alleen als je nu bijvoorbeeld een thumb drive aansluit die door een ander bedrijf is gemaakt (dus met een andere idVendor) of een muis of een printer, zal het script niet worden getriggerd.
Blijf nieuwe attributen toevoegen om je verder te concentreren op die ene unieke thumb drive waarvan je wilt dat het script wordt getriggerd. Met behulp van udevadm info -a -n /dev/sdb, kunt u dingen te weten komen zoals de naam van de verkoper, soms een serienummer, of de productnaam, enzovoort.
Voor uw eigen geestelijke gezondheid, zorg ervoor dat u slechts één nieuw attribuut per keer toevoegt. De meeste fouten die ik heb gemaakt (en die andere mensen online hebben zien maken) is om een heleboel attributen in hun udev regel te gooien en zich af te vragen waarom het ding niet meer werkt. Het één voor één testen van attributen is de veiligste manier om er zeker van te zijn dat udev uw apparaat met succes kan identificeren.
Veiligheid
Dit brengt de veiligheidszorgen naar boven van het schrijven van udev regels om automatisch iets te doen wanneer een schijf wordt ingeplugd. Op mijn machines heb ik zelfs auto-mount niet aan staan, en toch stelt dit artikel scripts en regels voor die commando’s uitvoeren enkel door iets aan te sluiten.
Twee dingen om hier in gedachten te houden.
- Focus uw udev regels eens u ze werkend hebt, zodat ze enkel scripts triggeren wanneer u dat echt wil. Het uitvoeren van een script dat blindelings gegevens van of naar uw computer kopieert, is een slecht idee voor het geval iemand die toevallig hetzelfde merk thumb drive bij zich heeft, deze in uw box plugt.
- Schrijf uw udev-regel en scripts niet en vergeet ze. Ik weet op welke computers mijn udev-regels staan, en die dozen zijn meestal mijn persoonlijke computers, niet degene die ik meeneem naar conferenties of in mijn kantoor op het werk heb staan. Hoe “socialer” een computer is, hoe kleiner de kans dat er een udev regel op komt te staan die er mogelijk toe kan leiden dat mijn gegevens op iemand anders zijn apparaat terecht komen of iemand anders zijn gegevens of malware op mijn apparaat.
Met andere woorden, zoals met zoveel van de macht die door een GNU systeem wordt verschaft, is het je taak om op te letten hoe je die macht gebruikt. Als je het misbruikt of niet met respect behandelt, kan het heel goed vreselijk misgaan.
Udev in de echte wereld
Nu je kunt bevestigen dat je script wordt getriggerd door udev, kun je je aandacht richten op de functie van het script. Op dit moment is het nutteloos, het doet niets meer dan het loggen van het feit dat het is uitgevoerd.
Ik gebruik udev om automatische backups van mijn thumb drives te starten. Het idee is dat de master kopieën van mijn actieve documenten op mijn thumb drive staan (omdat het overal mee naar toe gaat en er op elk moment aan gewerkt kan worden), en die master documenten worden geback-upt naar mijn computer elke keer als ik de drive in die machine stop. Met andere woorden, mijn computer is de back-upschijf en mijn productiegegevens zijn mobiel. De broncode is beschikbaar, dus voel je vrij om naar de code van attachup te kijken voor verdere voorbeelden van het beperken van je udev tests.
Omdat ik udev daar het meest voor gebruik, is dat het voorbeeld dat ik hier zal gebruiken, maar udev kan veel andere dingen grijpen, zoals gamepads (dit is handig op systemen die niet zijn ingesteld om de xboxdrv-module te laden wanneer een gamepad is aangesloten) en camera’s en microfoons (handig om ingangen in te stellen wanneer een specifieke microfoon is aangesloten), dus realiseer je dat het goed is voor veel meer dan dit ene voorbeeld.
Een eenvoudige versie van mijn backup-systeem is een proces met twee commando’s:
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", SYMLINK+="safety%n"
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"
De eerste regel detecteert mijn thumb drive met de attributen die al besproken zijn, en wijst de thumb drive vervolgens een symlink toe binnen de apparaatboom. De symlink die wordt toegewezen is safety%n. De %n is een udev macro die verwijst naar het nummer dat de kernel aan het apparaat geeft, zoals sdb1, sdb2, sdb3, enzovoort. Dus %n zou de 1 of de 2 of de 3 zijn.
Dit creëert een symlink in de dev tree, zodat het niet interfereert met het normale proces van het inpluggen van een apparaat. Dit betekent dat als je een desktop omgeving gebruikt die graag auto-mount devices gebruikt, je er geen problemen mee veroorzaakt.
De tweede regel voert het script uit.
Mijn backup script ziet er zo uit:
#!/usr/bin/bash
mount /dev/safety1 /mnt/hd
sleep 2
rsync -az /mnt/hd/ /home/seth/backups/ && umount /dev/safety1
Het script gebruikt de symlink, wat de mogelijkheid vermijdt dat udev de schijf een onverwachte naam geeft (als ik bijvoorbeeld al een thumb drive met de naam DISK in mijn computer heb gestoken, en ik steek mijn andere thumb drive erin die ook DISK heet, dan zal de tweede als DISK_ worden aangeduid, wat mijn script zou verpesten). Het mount safety1 (de eerste partitie van de schijf) op mijn favoriete mount punt van /mnt/hd.
Eenmaal veilig gemount, gebruikt het rsync om een backup te maken van de schijf naar mijn backup map (mijn eigenlijke script gebruikt rdiff-backup, en de jouwe kan elke geautomatiseerde backup oplossing gebruiken die je verkiest).
Udev is jouw dev
Udev is een zeer flexibel systeem en stelt je in staat om regels en functies te definiëren op manieren die weinig andere systemen durven te bieden aan gebruikers. Leer het en gebruik het, en geniet van de kracht van POSIX.
Dit artikel bouwt voort op inhoud van het Slackermedia Handbook, dat is gelicenseerd onder de GNU Free Documentation License 1.3.