Az Udev a Linux alrendszere, amely a számítógépet eszközeseményekkel látja el. Egyszerűbben fogalmazva ez azt jelenti, hogy ez az a kód, amely érzékeli, ha a számítógépedhez olyan dolgokat csatlakoztatsz, mint a hálózati kártya, külső merevlemezek (beleértve az USB pendrive-okat), egerek, billentyűzetek, joystickok és gamepadek, DVD-ROM meghajtók és így tovább. Ez egy potenciálisan hasznos segédprogrammá teszi, és elég jól látható ahhoz, hogy egy átlagos felhasználó manuálisan szkriptet készítsen, hogy például bizonyos feladatokat hajtson végre, amikor egy bizonyos merevlemezt csatlakoztat.
Ez a cikk megtanítja, hogyan hozzon létre egy udev szkriptet, amelyet valamilyen udev esemény, például egy adott pendrive csatlakoztatása indít el. Ha egyszer megértette az udevvel való munka folyamatát, akkor mindenféle dolgokra használhatja, például egy adott meghajtó betöltésére, amikor egy gamepadot csatlakoztat, vagy automatikus biztonsági mentés végrehajtására, amikor csatlakoztatja a mentési meghajtót.
Egy alapvető szkript
Az udevvel való munka legjobb módja, ha kis darabokban dolgozik. Ne írja meg a teljes szkriptet előre, hanem kezdje valamivel, ami egyszerűen csak megerősíti, hogy az udev kivált valamilyen egyéni eseményt.
A szkript céljaitól függően nem garantálhatja, hogy valaha is saját szemével fogja látni a szkript eredményét, ezért győződjön meg róla, hogy a szkriptje naplózza, hogy sikeresen kiváltotta. A naplófájlok szokásos helye a /var könyvtárban van, de ez többnyire a root felhasználó területe. Teszteléshez használd a /tmp könyvtárat, amely a normál felhasználók számára is elérhető, és általában újraindításkor kiürül.
Nyisd meg a kedvenc szövegszerkesztődet, és írd be ezt az egyszerű szkriptet:
#!/usr/bin/bash
/usr/bin/date >> /tmp/udev.log
Tedd ezt a /usr/local/bin könyvtárba vagy más hasonló helyre az alapértelmezett futtatási útvonalban. Nevezd trigger.sh-nak, és természetesen a chmod +x segítségével tedd végrehajthatóvá.
$ sudo mv trigger.sh /usr/local/bin
$ sudo chmod +x /usr/local/bin/trigger.sh
Ez a szkriptnek semmi köze az udevhez. Amikor végrehajtódik, a szkript elhelyez egy időbélyeget a /tmp/udev.log fájlban. Tesztelje maga a szkriptet:
$ /usr/local/bin/trigger.sh
$ cat /tmp/udev.log
Tue Oct 31 01:05:28 NZDT 2035
A következő lépés, hogy az udev elindítsa a szkriptet.
Egyedi eszközazonosítás
Az udevnek tudnia kell, hogy milyen feltételek mellett kell meghívnia a szkriptet, hogy a szkriptet egy eszköz eseménye indítsa el. A való életben egy pendrive-ot a színe, a gyártója és az alapján tudsz azonosítani, hogy épp most csatlakoztattad a számítógépedhez. A számítógépének azonban más kritériumokra van szüksége.
Az udev az eszközöket sorozatszámok, gyártók, sőt, a vendor ID és a product ID számok alapján azonosítja. Mivel ez még az udev szkript életének korai szakaszában van, legyen minél szélesebb körű, nem specifikus és mindenre kiterjedő. Más szóval, először szinte bármilyen érvényes udev eseményt el akarsz kapni, hogy elindíthasd a szkriptedet.
Az udevadm monitor paranccsal valós időben rácsatlakozhatsz az udev-re, és láthatod, hogy mit lát, amikor különböző eszközöket csatlakoztatsz. Legyen root, és próbálja ki.
$ su
# udevadm monitor
A monitor funkció kiírja a kapott eseményeket:
- UDEV: az udev által a szabály feldolgozása után küldött esemény
- KERNEL: a kernel ueventje
Az udevadm monitor futásával csatlakoztasson egy pendrive-ot, és figyelje, ahogy mindenféle információ kiömlik a képernyőjére. Vegyük észre, hogy az esemény típusa ADD esemény. Ez egy jó módja annak, hogy azonosítsuk, milyen típusú eseményt szeretnénk.
Az udevadm monitor parancs sok jó információt szolgáltat, de szebb formázással az udevadm info paranccsal láthatjuk ezeket, feltéve, hogy tudjuk, hol található jelenleg a pendrive a /dev fában. Ha nem, akkor húzd ki és dugd vissza a pendrive-ot, majd azonnal add ki ezt a parancsot:
$ su -c 'dmesg | tail | fgrep -i sd*'
Ha ez a parancs például sdb: sdb1-et adna vissza, akkor tudod, hogy a kernel a pendrive-odhoz az sdb címkét rendelte.
Alternatívaként az lsblk paranccsal megtekintheti a rendszeréhez csatlakoztatott összes meghajtót, beleértve azok méretét és partícióit.
Most, hogy megállapította, hol található a meghajtó a fájlrendszerben, ezzel a paranccsal megtekintheti az eszközre vonatkozó udev információkat:
# udevadm info -a -n /dev/sdb | less
Ez rengeteg információt ad vissza. Most az első információs blokkra koncentrálj.
A te feladatod az, hogy kiválogasd az udev jelentéséből azokat a részeket, amelyek a leginkább jellemzőek az adott eszközre, majd szólj az udevnek, hogy indítsa el a szkriptedet, amikor ezeket az egyedi attribútumokat észleli.
Az udevadm info folyamat jelentést készít egy eszközről (az eszköz elérési útvonalával megadva), majd “felfelé sétál” a szülőeszközök láncolatában. Minden megtalált eszközhöz kiírja az összes lehetséges attribútumot kulcs-érték formátumban. Összeállíthat olyan szabályt, amely az eszköz attribútumai és egyetlen szülőeszköz attribútumai szerint egyezik meg.
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"
Az udev-szabálynak egyetlen szülőeszköz attribútumát kell tartalmaznia.
A szülői attribútumok olyan dolgok, amelyek a legalapvetőbb szinten írják le az eszközt, például, hogy ez valami, ami egy fizikai portba van bedugva, vagy ez valami, aminek van mérete, vagy ez egy cserélhető eszköz.
Mivel az sdb KERNEL címkéje változhat attól függően, hogy hány más meghajtó volt bedugva, mielőtt bedugta azt a pendrive-ot, ez nem az optimális szülői attribútum egy udev szabályhoz. A koncepció bizonyítására azonban működik, így használhatod. Még jobb jelölt a SUBSYSTEM attribútum, amely azonosítja, hogy ez egy “blokkos” rendszereszköz (ezért listázza az eszközt az lsblk parancs).
Nyissa meg a 80-local.rules nevű fájlt az /etc/udev/rules állományban.d és írd be ezt a kódot:
SUBSYSTEM=="block", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"
Mentsd el a fájlt, húzd ki a teszt pendrive-ot és indítsd újra.
Várj, újraindítás egy Linux gépen?
elméletileg egyszerűen kiadhatod az udevadm control –reload parancsot, aminek be kellene töltenie az összes szabályt, de a játék ezen szakaszában a legjobb, ha minden változót kizársz. Az Udev elég összetett, és nem akarsz egész éjjel az ágyban feküdni és azon gondolkodni, hogy vajon az a szabály nem működött-e egy szintaktikai hiba miatt, vagy csak újra kellett volna indítanod. Tehát indítsd újra, függetlenül attól, hogy mit mond a POSIX büszkeséged.
Amikor a rendszered újra online, válts egy szöveges konzolra (Ctl+Alt+F3 vagy hasonlóval), és dugd be a pendrive-ot. Ha egy újabb kernelt futtatsz, akkor valószínűleg egy csomó kimenetet fogsz látni a konzolodban, amikor bedugod a meghajtót. Ha olyan hibaüzenetet lát, mint például: Could not execute /usr/local/bin/trigger.sh, akkor valószínűleg elfelejtette futtathatóvá tenni a szkriptet. Egyébként remélhetőleg csak annyit látsz, hogy egy eszköz be lett dugva, kapott valamilyen kernel eszköz hozzárendelést, és így tovább.
Most, az igazság pillanata:
$ cat /tmp/udev.log
Tue Oct 31 01:35:28 NZDT 2035
Ha a /tmp/udev.log-ból egy nagyon friss dátumot és időt látsz vissza, akkor az udev sikeresen elindította a szkriptedet.
A szabály finomítása valami hasznosra
A szabály problémája az, hogy nagyon általános. Egy egér, egy pendrive vagy valaki más pendrive csatlakoztatása válogatás nélkül kiváltja a szkriptedet. Itt az ideje, hogy elkezdjünk pontosan arra a pendrive-ra összpontosítani, amelyikkel a szkriptet ki akarjuk váltani.
Egyik módja ennek a gyártó azonosítója és a termék azonosítója. Ezekhez a számokhoz az lsusb parancsot használhatja.
$ 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
Ebben a példában a TyCoon Corp. előtti 03f0:3307 jelöli az idVendor és az idProduct attribútumokat. Ezeket a számokat az udevadm info -a -n /dev/sdb | grep vendor kimenetén is láthatja, de az lsusb kimenetét egy kicsit könnyebbnek találom a szemnek.
Az attribútumokat most már felveheti a szabályába.
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/thumb.sh"
Teszteld ezt (igen, még mindig újra kell indítanod, csak hogy biztos legyél benne, hogy friss reakciókat kapsz az udev-től), és ugyanúgy kell működnie, mint korábban, csak most már, ha bedugsz mondjuk egy másik cég által gyártott pendrive-ot (ezért más idVendorral) vagy egy egeret vagy egy nyomtatót, a szkript nem fog elindulni.
Folyamatosan adj hozzá új attribútumokat, hogy még jobban koncentrálj arra az egy egyedi pendrive-ra, amit a szkripted indítani akarsz. Az udevadm info -a -n /dev/sdb segítségével olyan dolgokat tudhat meg, mint a gyártó neve, néha egy sorozatszám, vagy a termék neve, és így tovább.
A saját józanságod érdekében ügyelj arra, hogy egyszerre csak egy új attribútumot adj hozzá. A legtöbb hiba, amit elkövettem (és láttam, hogy mások is elkövették az interneten), hogy egy csomó attribútumot dobtak az udev szabályukba, és csodálkoztak, hogy a dolog már nem működik. Az attribútumok egyenkénti tesztelése a legbiztosabb módja annak, hogy az udev sikeresen azonosítani tudja az eszközt.
Biztonság
Ez felveti az udev szabályok írásának biztonsági aggályait, hogy automatikusan csináljanak valamit, amikor egy meghajtót csatlakoztatnak. Az én gépeimen még az automatikus csatlakoztatás sincs bekapcsolva, és ez a cikk mégis olyan szkripteket és szabályokat javasol, amelyek parancsokat hajtanak végre pusztán attól, hogy valami be van dugva.
Két dolgot kell itt szem előtt tartanod.
- Fókuszáld az udev szabályaidat, ha már működnek, hogy csak akkor indítsanak el szkripteket, amikor valóban akarod. Egy olyan szkript végrehajtása, amely vakon másol adatokat a számítógépedre vagy a számítógépedről, rossz ötlet abban az esetben, ha bárki, aki történetesen ugyanolyan márkájú pendrive-ot tart magánál, bedugja azt a dobozodba.
- Ne írd meg az udev szabályaidat és szkriptjeidet, majd felejtsd el őket. Tudom, hogy mely számítógépeken vannak az udev-szabályaim, és ezek a dobozok leggyakrabban a személyes számítógépeim, nem pedig azok, amelyeket konferenciákra viszek magammal, vagy amelyek a munkahelyi irodámban vannak. Minél “szociálisabb” egy számítógép, annál kisebb a valószínűsége, hogy olyan udev-szabály kerül rá, amely potenciálisan azt eredményezheti, hogy az én adataim valaki más eszközén, vagy valaki más adatai vagy rosszindulatú programok az én eszközömön landolnak.
Más szóval, mint a GNU rendszer által biztosított hatalom nagy része esetében, a te dolgod, hogy odafigyelj arra, hogyan használod ezt a hatalmat. Ha visszaélsz vele, vagy nem bánsz vele tisztelettel, akkor könnyen lehet, hogy szörnyen rosszul sül el.
Udev a való világban
Most, hogy megerősítheted, hogy a szkriptedet az udev indítja, a figyelmed a szkript működésére fordíthatod. Jelenleg haszontalan, nem tesz mást, mint naplózza a végrehajtás tényét.
Az udevet arra használom, hogy automatikus mentéseket indítsak el a pendrive-okról. Az ötlet az, hogy az aktív dokumentumaim mesterpéldányai a pendrive-on vannak (mivel mindenhova megyek vele, és bármikor dolgozhatok rajta), és ezek a mesterdokumentumok minden alkalommal biztonsági mentést kapnak a számítógépemre, amikor a meghajtót a géphez csatlakoztatom. Más szóval, a számítógépem a biztonsági meghajtó, a termelési adataim pedig a mobil. A forráskód elérhető, így nyugodtan nézze meg az attachup kódját további példákért az udev tesztek korlátozására.
Mivel én erre használom az udevet a legtöbbet, itt ezt a példát fogom használni, de az udev sok más dolgot is meg tud ragadni, például gamepadokat (ez hasznos olyan rendszereken, amelyek nincsenek beállítva, hogy betöltik az xboxdrv modult, amikor egy gamepad csatlakozik), kamerákat és mikrofonokat (hasznos bemenetek beállításához, amikor egy adott mikrofon csatlakozik), szóval vedd észre, hogy sokkal többre jó, mint ez az egy példa.
A mentési rendszerem egyszerű változata egy kétparancsos folyamat:
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", SYMLINK+="safety%n"
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"
Az első sor felismeri a pendrive-omat a már tárgyalt attribútumokkal, majd hozzárendel a pendrive-hoz egy symlinket az eszközfán belül. A hozzárendelt symlink a safety%n. A %n egy udev makró, amely feloldódik arra a számra, amelyet a kernel ad az eszköznek, például sdb1, sdb2, sdb3 és így tovább. Tehát a %n lenne az 1 vagy a 2 vagy a 3.
Ez egy symlinket hoz létre a dev fában, így nem zavarja az eszköz csatlakoztatásának normál folyamatát. Ez azt jelenti, hogy ha olyan asztali környezetet használsz, amely szereti az eszközök automatikus csatolását, akkor nem fogsz neki problémát okozni.
A második sor futtatja a szkriptet.
Az én mentési szkriptem így néz ki:
#!/usr/bin/bash
mount /dev/safety1 /mnt/hd
sleep 2
rsync -az /mnt/hd/ /home/seth/backups/ && umount /dev/safety1
A szkript a symlinket használja, amivel elkerülhető, hogy az udev valami váratlanul nevezze el a meghajtót (például ha már van egy DISK nevű pendrive a számítógépembe dugva, és bedugom a másik, szintén DISK nevű pendrive-ot, akkor a másodiknak a DISK_ feliratot fogja adni, ami meghiúsítaná a szkriptemet). A safety1-et (a meghajtó első partícióját) az általam preferált /mnt/hd csatolási pontra csatolja.
A biztonságos csatolás után rsync segítségével biztonsági mentést készít a meghajtóról a biztonsági mentési mappámba (az én aktuális szkriptem az rdiff-backup-ot használja, a tiéd pedig bármilyen automatizált biztonsági mentési megoldást használhat).
Udev a dev
Az Udev egy nagyon rugalmas rendszer, és lehetővé teszi, hogy olyan szabályokat és funkciókat határozz meg, amelyeket kevés más rendszer mer a felhasználók számára biztosítani. Tanuld meg és használd, és élvezd a POSIX erejét.
Ez a cikk a Slackermedia Handbook tartalmára épül, amely a GNU Free Documentation License 1.3 licenc alatt áll.