Udev je subsystém Linuxu, který dodává počítači události zařízení. Zjednodušeně řečeno to znamená, že je to kód, který zjišťuje, kdy máte k počítači připojené věci, jako je síťová karta, externí pevné disky (včetně USB flash disků), myši, klávesnice, joysticky a gamepady, mechaniky DVD-ROM atd. To z něj činí potenciálně užitečný nástroj, který je dostatečně exponovaný na to, aby ho běžný uživatel mohl ručně skriptovat, například aby prováděl určité úlohy, když je připojen určitý pevný disk.
Tento článek vás naučí, jak vytvořit skript udev spouštěný nějakou událostí udev, například připojením určitého pevného disku. Jakmile pochopíte postup práce s udev, můžete jej použít k nejrůznějším činnostem, například k načtení určitého ovladače po připojení gamepadu nebo k provedení automatického zálohování po připojení zálohovacího disku.
Základní skript
Nejlépe se s udev pracuje po malých částech. Nepište celý skript předem, ale raději začněte něčím, co jednoduše potvrdí, že udev spustí nějakou vlastní událost.
V závislosti na cíli vašeho skriptu nemůžete zaručit, že někdy uvidíte výsledky skriptu na vlastní oči, takže se ujistěte, že váš skript zaznamená, že byl úspěšně spuštěn. Obvyklé místo pro logovací soubory je v adresáři /var, ale ten je většinou doménou uživatele root. Pro testování použijte /tmp, který je přístupný běžným uživatelům a obvykle se vyčistí při restartu.
Otevřete svůj oblíbený textový editor a zadejte tento jednoduchý skript:
#!/usr/bin/bash
/usr/bin/date >> /tmp/udev.log
Umístěte jej do /usr/local/bin nebo na jiné podobné místo ve výchozí cestě ke spustitelnému souboru. Nazvěte jej trigger.sh a samozřejmě jej proveďte pomocí chmod +x.
$ sudo mv trigger.sh /usr/local/bin
$ sudo chmod +x /usr/local/bin/trigger.sh
Tento skript nemá nic společného s udev. Po spuštění skript umístí časovou značku do souboru /tmp/udev.log. Vyzkoušejte si skript sami:
$ /usr/local/bin/trigger.sh
$ cat /tmp/udev.log
Tue Oct 31 01:05:28 NZDT 2035
Dalším krokem je přimět udev, aby skript spustil.
Unikátní identifikace zařízení
Aby mohl být váš skript spuštěn událostí na zařízení, musí udev vědět, za jakých podmínek má skript zavolat. V reálném životě můžete identifikovat flash disk podle jeho barvy, výrobce a skutečnosti, že jste ho právě připojili k počítači. Váš počítač však potřebuje jinou sadu kritérií.
Udev identifikuje zařízení podle sériových čísel, výrobců a dokonce i podle čísel ID výrobce a ID produktu. Vzhledem k tomu, že se jedná o počátek životnosti vašeho skriptu udev, buďte co nejširší, nekonkrétní a všezahrnující. Jinými slovy, chcete nejprve zachytit téměř jakoukoli platnou událost udev, která spustí váš skript.
Pomocí příkazu udevadm monitor se můžete napojit na udev v reálném čase a sledovat, co vidí po připojení různých zařízení. Staňte se rootem a vyzkoušejte to.
$ su
# udevadm monitor
Funkce monitor vypíše přijaté události pro:
- UDEV: událost, kterou udev vyšle po zpracování pravidla
- KERNEL: událost jádra uevent
Se spuštěným udevadm monitor připojte flash disk a sledujte, jak se na obrazovce objeví nejrůznější informace. Všimněte si, že typem události je událost ADD. To je dobrý způsob, jak určit, jaký typ události chcete.
Příkaz udevadm monitor poskytuje spoustu dobrých informací, ale můžete si je prohlédnout s hezčím formátováním pomocí příkazu udevadm info, za předpokladu, že víte, kde se váš flash disk právě nachází ve stromu /dev. Pokud ne, odpojte a znovu připojte flash disk a poté ihned zadejte tento příkaz:
$ su -c 'dmesg | tail | fgrep -i sd*'
Pokud tento příkaz vrátil například sdb: sdb1, víte, že jádro přiřadilo vašemu flash disku označení sdb.
Případně můžete použít příkaz lsblk, který zobrazí všechny jednotky připojené k systému, včetně jejich velikosti a oddílů.
Teď, když jste zjistili, kde se vaše jednotka v souborovém systému nachází, můžete zobrazit informace o tomto zařízení pomocí příkazu udev:
# udevadm info -a -n /dev/sdb | less
Tento příkaz vrátí mnoho informací. Prozatím se soustřeďte na první blok informací.
Vaším úkolem je vybrat z hlášení udev o zařízení ty části, které jsou pro dané zařízení nejvíce unikátní, a pak říct udev, aby spustil váš skript, když tyto unikátní atributy zjistí.
Proces udevadm info podá zprávu o zařízení (zadané cestou k zařízení) a pak „projde“ řetězcem nadřazených zařízení. Pro každé nalezené zařízení vypíše všechny možné atributy pomocí formátu klíč-hodnota. Pravidlo můžete sestavit tak, aby odpovídalo podle atributů zařízení plus atributů z jednoho jediného nadřazeného zařízení.
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"
Pravidlo udev musí obsahovat jeden atribut z jednoho jediného nadřazeného zařízení.
Atributy nadřazeného zařízení jsou věci, které popisují zařízení z té nejzákladnější úrovně, například že je to něco, co bylo zapojeno do fyzického portu, nebo že je to něco s velikostí, nebo že se jedná o vyměnitelné zařízení.
Protože se označení KERNEL sdb může měnit v závislosti na tom, kolik dalších disků bylo zapojeno před zapojením této flashky, není to optimální atribut nadřazeného zařízení pro pravidlo udev. Pro ověření konceptu to však funguje, takže to můžete použít. Ještě lepším kandidátem je atribut SUBSYSTEM, který identifikuje, že se jedná o „blokové“ systémové zařízení (proto příkaz lsblk zařízení vypíše).
Otevřete soubor 80-local.rules v /etc/udev/rules.d a zadejte tento kód:
SUBSYSTEM=="block", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"
Soubor uložte, odpojte testovací flash disk a restartujte počítač.
Počkat, restartovat počítač s Linuxem?
Teoreticky můžete jen vydat příkaz udevadm control –reload, který by měl načíst všechna pravidla, ale v této fázi hry je nejlepší eliminovat všechny proměnné. Udev je dost složitý a nechcete přece ležet celou noc v posteli a přemýšlet, jestli to pravidlo nefungovalo kvůli syntaktické chybě, nebo jestli jste měli jen restartovat počítač. Takže restartujte bez ohledu na to, co vám říká vaše pýcha POSIX.
Když je systém opět online, přepněte se do textové konzole (pomocí Ctl+Alt+F3 nebo podobně) a připojte flash disk. Pokud používáte nejnovější jádro, pravděpodobně se vám po připojení jednotky zobrazí v konzoli hromada výstupů. Pokud se zobrazí chybové hlášení typu Nelze spustit /usr/local/bin/trigger.sh, pravděpodobně jste zapomněli skript spustit. Jinak snad vidíte jen to, že zařízení bylo připojeno, dostalo nějaké přiřazení zařízení jádra a tak dále.
Teď okamžik pravdy:
$ cat /tmp/udev.log
Tue Oct 31 01:35:28 NZDT 2035
Pokud vidíte velmi aktuální datum a čas vrácené z /tmp/udev.log, udev úspěšně spustil váš skript.
Zpřesnění pravidla na něco užitečného
Problém tohoto pravidla je, že je velmi obecné. Připojení myši, flash disku nebo cizího flash disku nevybíravě spustí váš skript. Nyní je čas začít se soustředit na konkrétní flash disk, který má váš skript spustit.
Jedním ze způsobů, jak to udělat, je pomocí ID výrobce a ID produktu. Pro získání těchto čísel můžete použít příkaz lsusb.
$ 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
V tomto příkladu označuje 03f0:3307 před TyCoon Corp. atributy idVendor a idProduct. Tato čísla můžete vidět také ve výstupu příkazu udevadm info -a -n /dev/sdb | grep vendor, ale výstup příkazu lsusb mi přijde o něco jednodušší na pohled.
Nyní můžete tyto atributy zahrnout do svého pravidla.
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/thumb.sh"
Vyzkoušejte to (ano, měli byste ještě restartovat počítač, jen abyste se ujistili, že dostáváte čerstvé reakce od udev) a mělo by to fungovat stejně jako předtím, jen pokud nyní připojíte například flash disk vyrobený jinou společností (tedy s jiným idVendor) nebo myš či tiskárnu, skript se nespustí.
Pokračujte v přidávání nových atributů, abyste se dále zaměřili na ten jediný flash disk, který chcete, aby spustil váš skript. Pomocí udevadm info -a -n /dev/sdb můžete zjistit například jméno dodavatele, někdy sériové číslo nebo název produktu a podobně.
Pro svůj vlastní rozum nezapomeňte přidávat vždy jen jeden nový atribut. Většina chyb, které jsem udělal (a viděl jsem je dělat i u jiných lidí na internetu), spočívá v tom, že do svého pravidla udev naházeli hromadu atributů a pak se divili, proč to přestalo fungovat. Testování atributů jeden po druhém je nejbezpečnější způsob, jak zajistit, aby udev úspěšně identifikoval vaše zařízení.
Bezpečnost
To přináší obavy o bezpečnost při psaní pravidel udev, která mají automaticky něco udělat, když je disk připojen. Na svých počítačích nemám zapnuté ani automatické připojování, a přesto tento článek navrhuje skripty a pravidla, která spouštějí příkazy jen na základě toho, že je něco připojeno.
Dvě věci, které je zde třeba mít na paměti.
- Zaměřte se na pravidla udev, jakmile je zprovozníte, aby spouštěla skripty jen tehdy, když to opravdu chcete. Spouštění skriptů, které slepě kopírují data do počítače nebo z počítače, je špatný nápad pro případ, že by někdo, kdo má náhodou u sebe flash disk stejné značky, jej připojil k vašemu boxu.
- Nepište pravidla udev a skripty a nezapomeňte na ně. Vím, na kterých počítačích jsou moje pravidla udev, a tyto krabice jsou nejčastěji moje osobní počítače, ne ty, které si vozím na konference nebo mám v kanceláři v práci. Čím více je počítač „společenský“, tím menší je pravděpodobnost, že na něm bude pravidlo udev, které by mohlo potenciálně vést k tomu, že se moje data dostanou do cizího zařízení nebo cizí data či malware do mého zařízení.
Jinými slovy, stejně jako u mnoha jiných pravomocí poskytovaných systémem GNU je vaším úkolem dávat pozor na to, jak s touto pravomocí nakládáte. Pokud ji zneužijete nebo se k ní nebudete chovat s respektem, může se to velmi dobře zvrtnout.
Udev v reálném světě
Teď, když můžete potvrdit, že váš skript je spouštěn pomocí udev, můžete obrátit pozornost k funkci skriptu. Právě teď je k ničemu, nedělá nic jiného, než že zaznamenává skutečnost, že byl spuštěn.
Používám udev ke spouštění automatického zálohování svých flash disků. Myšlenka je taková, že hlavní kopie mých aktivních dokumentů jsou na mé flashce (protože ji mám všude s sebou a mohu na ní kdykoli pracovat) a tyto hlavní dokumenty se zálohují do mého počítače pokaždé, když k němu flashku připojím. Jinými slovy, můj počítač je záložní disk a moje produkční data jsou mobilní. Zdrojový kód je k dispozici, takže neváhejte a podívejte se na kód attachupu pro další příklady omezování testů udev.
Protože to je to, k čemu používám udev nejčastěji, je to příklad, který zde použiji, ale udev může uchopit spoustu dalších věcí, například gamepady (to je užitečné na systémech, které nejsou nastaveny tak, aby načítaly modul xboxdrv, když je připojen gamepad) a kamery a mikrofony (užitečné pro nastavení vstupů, když je připojen konkrétní mikrofon), takže si uvědomte, že je to dobré pro mnohem více věcí než tento jeden příklad.
Jednoduchá verze mého zálohovacího systému je proces o dvou příkazech:
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", SYMLINK+="safety%n"
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"
První řádek detekuje můj flash disk s již diskutovanými atributy a poté přiřadí flash disku symlink v rámci stromu zařízení. Symlink, který přiřadí, je safety%n. %n je makro udev, které se přeloží na libovolné číslo, které jádro zařízení přidělí, například sdb1, sdb2, sdb3 atd. Takže %n bude 1 nebo 2 nebo 3.
Vytvoří symlink ve stromu dev, takže nezasahuje do normálního procesu připojování zařízení. To znamená, že pokud používáte desktopové prostředí, které rádo automaticky připojuje zařízení, nebudete mu způsobovat problémy.
Druhý řádek spustí skript.
Můj zálohovací skript vypadá takto:
#!/usr/bin/bash
mount /dev/safety1 /mnt/hd
sleep 2
rsync -az /mnt/hd/ /home/seth/backups/ && umount /dev/safety1
Skript používá symlink, čímž se vyhýbá možnosti, že by udev pojmenoval disk nějak neočekávaně (například pokud už mám v počítači připojený flash disk s názvem DISK a připojím druhý flash disk, který se také jmenuje DISK, druhý bude označen jako DISK_, což by můj skript zmařilo). Připojí safety1 (první oddíl disku) na mnou preferovaný přípojný bod /mnt/hd.
Po bezpečném připojení použije rsync k zálohování disku do mé záložní složky (můj skutečný skript používá rdiff-backup a váš může použít jakékoli automatizované zálohovací řešení, které preferujete).
Udev je váš dev
Udev je velmi flexibilní systém a umožňuje definovat pravidla a funkce způsobem, který si málokterý jiný systém troufne uživatelům poskytnout. Naučte se ho, používejte ho a užívejte si sílu systému POSIX.
Tento článek vychází z obsahu příručky Slackermedia Handbook, která je licencována pod licencí GNU Free Documentation License 1.3.
.