neděle 3. dubna 2011

Vlastní akce po připojení zařízení - udev

udev umožňuje dynamickou správu připojených zařízení. Běží v systému jako démon a čeká na události, které generuje sám mocný kernel při připojení a odpojení zařízení. Připojíte externí USB disk a udev pro něj vytvoří přípojný bod(y) v systémovém adresáři /dev a tím zpřístupní systému. Po odpojení opět přístupový bod(y) zlikviduje. To, že se v Ubuntu po připojení USB disku připojí souborové systémy do aresáře /media a otevře okno Nautila, je už práce Gnome, jiná uživatelská prostředí si to samozřejmě řeší individuálně, ale udev je základ.


udev se řídí systémem pravidel, jimiž můžete měnit názvy výchozích přípojných bodů, definovat si jejich fixní jména pro konkrétní zařízení, a to i na základě výsledku nějakého programu, měnit jejich práva a vlastnictví a spouštět externí skripty při vytvoření, či smazání přípojného bodu zařízení. Z toho vyplývá, že si můžete napsat pravidla, která budou například automaticky zálohovat data po připojení konkrétního externího disku, nebo vás bude udev informovat o tom, že jste nějaké zařízení k systému připojili, nebo naopak odpijili, protože Ubuntu samo nijak vidtelně, ani slyšitelně, o takových událostech neinformuje (ačkoli v plánech pro Notify-OSD to od začátku je).

Předem doporučuji k prostudování obsah následujících odkazů, které umožní pochopit, o čem tu vlastně píšu:
a trochu česky:

Pravidla se v Ubuntu ukládají do adresářů /etc/udev/rules.d/ a především do /lib/udev/rules.d/. Jméno každého souboru pravidel musí mít příponu .rules a spouští se v pořadí podle abecedy. Standardně jména souborů začínají dvoumístným číslem, kde nižší číslo znamená přednost. Základní pravidla pro udev má Ubuntu v souboru /lib/udev/rules.d/50-udev-default.rules, který určitě stojí za studium. Tento soubor je zbytečné upravovat, neboť při aktualizaci systému mohou být vaše změny kdykoliv přepsány. Pokud tato pravidla chcete upravovat, je dobré váš vlastní soubor pravidel pojmenovat tak, aby se parsoval dříve.
Každé pravidlo se skládá z párových klíčů, které se oddělují čárkou. Pravidla obsahují testovací páry klíčů, na jejichž základě se provádějí konkrétní akce, klíči přiřazovacími. K určení pravidel pro konkrétní zařízení se vám může hodit především příkaz udevadm, který zprostředkuje například výpis parametrů a vlastností připojení konkrétního zařízení, které můžete použít. Třeba disku /dev/sda:

udevadm info -a -n /dev/sda

Příkaz vypíše vlastnosti definovaného zařízení a následně i jeho rodičů (nadřazených zařízení). Z něho se dají vyčíst potřebné parametry pro podmínky ve vašich pravidlech pro toto zařízení. Můžete udev a jeho zdroj také monitorovat a zjistit, co při připojení, či odpojení zařízení děje. Můžete monitorovat, jaké události generuje kernel:

udevadm monitor --kernel

Můžete monitorovat vlastnosti zařízení:

udevadm monitor --property

Samozřejmě odkážu na manuál (man udevadm), kde jsou všechny možnosti vypsané.

Pro názornost ukázka. Vytvořil jsem si v /etc/udev/rules.d/ soubor 10-gdh.rules , ve kterém jsem určil, že externí disky se budou po připojení i odpojení hlásit pomocí notifikačního systému a ještě přehrají zvuk. Pravidla vypadají takto:

KERNEL=="sd??*", ACTION=="add", ATTRS{idProduct}=="5014", RUN+="/bin/su gdh -c 'DISPLAY=:0.0 /usr/bin/notify-send -i gtk-info udev Memory\ card\ attached:\ %k; mplayer -volume 35 /usr/share/sounds/gnome/default/alerts/drip.ogg"

KERNEL=="sd??*", ACTION=="remove", ATTRS{idProduct}=="5014", RUN+="/bin/su gdh -c 'DISPLAY=:0.0 /usr/bin/notify-send -i gtk-info udev Memory\ card\ removed:\ %k; mplayer -volume 35 /usr/share/sounds/gnome/default/alerts/drip.ogg'"

KERNEL=="sd?", ACTION=="add", RUN+="/bin/su gdh -c 'DISPLAY=:0.0 /usr/bin/notify-send -i gtk-info udev Drive\ attached:\ %k; mplayer -volume 35 /usr/share/sounds/gnome/default/alerts/drip.ogg'"

KERNEL=="sd?", ACTION=="remove", RUN+="/bin/su gdh -c 'DISPLAY=:0.0 /usr/bin/notify-send -i gtk-info udev Drive\ removed:\ %k; mplayer -volume 35 /usr/share/sounds/gnome/default/alerts/drip.ogg'"

Pravidla umožňují použití regulárních výrazů i formátovacích značek. Otazník značí jakýkoliv znak, hvězdička jakýkoliv znak v libovolném množství, včetně nulového, hranaté závorky libovolný znak z výčtu uvnitř závorek a podporovány jsou i rozsahy. Výše použitý řetězec %k vloží celý aktuální název zařízení daný kernelem, %n pouze číslo zařízení. V příkladu jsou čtyři sady pravidel, dvě pro připojení disku, dvě pro odpojení. Druhá dvě pravidla se týkají připojení a odpojení celých disků, které generují přípojný bod ve tvaru /dev/sdx. První dvě pravidla používají v podmínce i atributy (ATTRS) pro detekci trvale připojené čtečky karet. V tomto případě se totiž vytvoří přípojné body pro jednotlivé sloty čtečky již při startu počítače a pokud do ní zasunete kartu, pouze se vytvoří přípojné body pro diskové oddíly na kartě, podle vzoru /dev/sdxy. Toto dělení vyplývá z logiky, že pokud připojím externí pevný disk se čtyřmi oddíly, rozhodně není potřeba, aby se při připojení, nebo odpojení hlásil každý oddíl zvlášť. Zajímá mě odpojení a připojení celého zařízení. V případě vestavěné čtečky karet je ale situace jiná, chci, aby se hlásily jednotlivé karty. Proto pomocí atributu (ATTRS) čtečku detekuji podle identifikačního čísla ({idProduct}=="5014") a v případě vložení, nebo vyjmutí karty, hlásím jednotlivé oddíly na kartě, stejně tam běžně víc oddílů není. Klíčem RUN určuji, co se má při splnění podmínky spustit, zde je i při volání systémových programů nutné definovat celou cestu. V případě volání notifikačního systému (nutno mít nainstalován balík libnotify-bin) se projeví bug tohoto programu, který neumožňuje spouštění po rootem. Proto mám v pravidlech volání notify-send pod uživatelem gdh a samozřejmě je nutné pro grafické programy definovat displej, na kterém se má aplikace zobrazit. MPlayer pak ke každé události přehraje systémový zvuk se sníženou hlasitostí.
Pravidla udev toho umožňují mnohem více, je například možné v souboru definovat pomocí klíče LABEL="$label" místa, na které můžete  klíčem GOTO="$label" skákat a podmínit tak aplikaci dalších pravidel při splnění, či nesplnění pravidel předchozích. Problematika pravidel je trochu komplikovanější a když si řeknete "prostě přehrauju zvuk při připojení jakéhokoliv zařízení do USB portu", nestačí dát do pravidla test SUBSYSTEM=="usb", protože při připojení/odpojení zařízení se generuje událostí celá řada a většina by odpovídala této podmínce.


Důležitá poznámka: Je třeba si uvědomit, že takto zapsaná pravidla se aplikují i při bootu systému, takže to, co jsem tu ukázal je třeba ošetřit, protože jinak vám to bude boot pěkně zpomalovat nesmyslnými akcemi. 

Snad tento článek budu postupem času doplňovat a kultivovat, zatím je to jen takový tip pro vlastní studium. Velmi solidní info je, jako obvykle, na wiki Archu:
https://wiki.archlinux.org/index.php/Udev

2 komentáře:

  1. Mohlo by to být trochu přehlednější, ale jinak houšť a větší kapky, informací v češtině k tomuto tématu je minimum.

    Mně osobně nejvíc pomáhá příkaz *udevadm test *, který nanečisto vyzkouší a vypíše, co by se stalo, kdyby bylo dané zařízení připojeno. Je pak lépe vidět, které pravidlo bylo použito a proč.

    OdpovědětSmazat
  2. Já to snad brzy doplním, jak jsem slíbil, nedokonalost díla si uvědomuju. Chtěl jsem vystavit alespoň něco, ať mám větší motivaci to dopsat :)
    Díky, že mě kontroluješ :)

    OdpovědětSmazat

Zkuste prosím při komentováni používat místo volby Anonymní volbu Název/adresa URL, kde vyplníte nějakou přezdívku, adresu zadávat nemusíte. Vědět, které příspěvky jsou od jednoho člověka, je fajn. Díky.

Pokud by se vám náhodou odeslaný komentář na stránce nezobrazil, vytáhnu ho z koše hned jak si toho všimnu. I Google spam filter se občas sekne.