Wprowadzenie do Udev: linuksowego podsystemu zarządzania zdarzeniami dotyczącymi urządzeń

Udev to linuksowy podsystem, który dostarcza komputerowi zdarzeń dotyczących urządzeń. W prostym języku angielskim oznacza to, że jest to kod, który wykrywa, kiedy do komputera podłączone są różne rzeczy, takie jak karta sieciowa, zewnętrzne dyski twarde (w tym dyski USB), myszy, klawiatury, joysticki i gamepady, napędy DVD-ROM i tak dalej. To czyni go potencjalnie użytecznym narzędziem i jest na tyle dobrze wyeksponowany, że standardowy użytkownik może go ręcznie oskryptować, aby wykonywał określone zadania, gdy określony dysk twardy jest podłączony.

Ten artykuł uczy, jak utworzyć skrypt udev wywoływany przez pewne zdarzenie udev, takie jak podłączenie określonego dysku miniaturowego. Kiedy już zrozumiesz proces pracy z udev, możesz użyć go do robienia różnych rzeczy, takich jak ładowanie określonego sterownika po podłączeniu gamepada lub wykonywanie automatycznej kopii zapasowej po podłączeniu dysku twardego.

Podstawowy skrypt

Najlepszym sposobem pracy z udev są małe fragmenty. Nie pisz od razu całego skryptu, ale zacznij od czegoś, co po prostu potwierdza, że udev wywołuje jakieś niestandardowe zdarzenie.

Zależnie od celu, jaki chcesz osiągnąć, nie możesz zagwarantować, że kiedykolwiek zobaczysz wyniki działania skryptu na własne oczy, więc upewnij się, że skrypt rejestruje, że został pomyślnie wywołany. Zwykle pliki dziennika znajdują się w katalogu /var, ale jest to głównie domena użytkownika root. Do testów użyj katalogu /tmp, który jest dostępny dla zwykłych użytkowników i zwykle jest czyszczony przy ponownym uruchomieniu systemu.

Otwórz swój ulubiony edytor tekstu i wprowadź ten prosty skrypt:

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

Umieść go w katalogu /usr/local/bin lub w innym miejscu domyślnej ścieżki wykonywania. Nazwij go trigger.sh i, oczywiście, uczyń go wykonywalnym za pomocą chmod +x.

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

Ten skrypt nie ma nic wspólnego z udev. Kiedy się wykonuje, skrypt umieszcza znacznik czasu w pliku /tmp/udev.log. Przetestuj skrypt samodzielnie:

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

Następnym krokiem jest sprawienie, aby udev wyzwalał skrypt.

Unikalna identyfikacja urządzenia

Aby Twój skrypt mógł być wyzwalany przez zdarzenie urządzenia, udev musi wiedzieć, w jakich warunkach powinien wywołać skrypt. W prawdziwym życiu możesz zidentyfikować pendrive po jego kolorze, producencie i fakcie, że właśnie podłączyłeś go do swojego komputera. Twój komputer potrzebuje jednak innego zestawu kryteriów.

Udev identyfikuje urządzenia na podstawie numerów seryjnych, producentów, a nawet numerów ID dostawcy i ID produktu. Ponieważ jest to wczesny etap życia skryptu udev, powinien on być tak szeroki, niespecyficzny i wszechstronny, jak to tylko możliwe. Innymi słowy, chcesz najpierw złapać prawie każde ważne zdarzenie udev, aby wywołać swój skrypt.

Z poleceniem udevadm monitor, możesz podłączyć się do udev w czasie rzeczywistym i zobaczyć, co widzi, gdy podłączasz różne urządzenia. Zostań rootem i spróbuj.

$ su
# udevadm monitor

Funkcja monitora drukuje otrzymane zdarzenia dla:

  • UDEV: zdarzenie, które udev wysyła po przetworzeniu reguły
  • KERNEL: zdarzenie uevent jądra

Z uruchomionym monitorem udevadm podłącz pendrive’a i obserwuj, jak wszystkie rodzaje informacji są wylewane na ekran. Zauważ, że typ zdarzenia to zdarzenie ADD. To dobry sposób na zidentyfikowanie typu zdarzenia, które chcesz uzyskać.

Polecenie udevadm monitor dostarcza wielu dobrych informacji, ale możesz je zobaczyć w ładniejszym formatowaniu za pomocą polecenia udevadm info, zakładając, że wiesz, gdzie aktualnie znajduje się dysk miniaturowy w drzewie /dev. Jeśli nie, odłącz i podłącz z powrotem swój dysk, a następnie natychmiast wydaj to polecenie:

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

Jeśli to polecenie zwróciło sdb: sdb1, na przykład, wiesz, że jądro przypisało twojemu dyskowi etykietę sdb.

Alternatywnie możesz użyć polecenia lsblk, aby zobaczyć wszystkie dyski podłączone do systemu, łącznie z ich rozmiarami i partycjami.

Teraz, gdy ustaliłeś, gdzie twój dysk znajduje się w systemie plików, możesz wyświetlić informacje udev o tym urządzeniu za pomocą tego polecenia:

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

To zwraca wiele informacji. Na razie skup się na pierwszym bloku informacji.

Twoim zadaniem jest wybranie tych części raportu udev o urządzeniu, które są najbardziej unikalne dla tego urządzenia, a następnie powiedz udev, aby uruchomił twój skrypt, gdy te unikalne atrybuty zostaną wykryte.

Proces udevadm info raportuje o urządzeniu (określonym przez ścieżkę urządzenia), a następnie „podąża” w górę łańcucha urządzeń nadrzędnych. Dla każdego znalezionego urządzenia wypisuje wszystkie możliwe atrybuty, używając formatu klucz-wartość. Można skomponować regułę dopasowującą według atrybutów urządzenia plus atrybuty z jednego urządzenia nadrzędnego.

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"

Reguła udev musi zawierać jeden atrybut z jednego urządzenia nadrzędnego.

Atrybuty macierzyste są rzeczami, które opisują urządzenie z najbardziej podstawowego poziomu, takie jak to, że jest to coś, co zostało podłączone do fizycznego portu lub jest to coś z rozmiarem lub jest to urządzenie wymienne.

Ponieważ etykieta KERNEL urządzenia sdb może się zmieniać w zależności od tego, ile innych napędów zostało podłączonych przed podłączeniem tego dysku miniaturowego, nie jest to optymalny atrybut macierzysty dla reguły udev. Jednakże, działa to dla dowodu koncepcji, więc możesz go użyć. Jeszcze lepszym kandydatem jest atrybut SUBSYSTEM, który identyfikuje, że jest to urządzenie systemu „blokowego” (dlatego polecenie lsblk wymienia to urządzenie).

Otwórz plik o nazwie 80-local.rules w /etc/udev/rules.d i wprowadź następujący kod:

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

Zapisz plik, odłącz testowy dysk i uruchom ponownie.

Czekaj, uruchom ponownie na maszynie linuksowej?

Teoretycznie możesz po prostu wydać polecenie udevadm control –reload, które powinno załadować wszystkie reguły, ale na tym etapie gry najlepiej jest wyeliminować wszystkie zmienne. Udev jest wystarczająco skomplikowany i nie chcesz leżeć w łóżku przez całą noc zastanawiając się, czy reguła nie zadziałała z powodu błędu składni, czy może powinieneś był po prostu zrestartować komputer. Więc zrestartuj system niezależnie od tego, co mówi ci twoja POSIX-owa duma.

Kiedy twój system jest z powrotem online, przełącz się na konsolę tekstową (za pomocą Ctl+Alt+F3 lub podobną) i podłącz swój dysk miniaturowy. Jeśli używasz najnowszego jądra, prawdopodobnie zobaczysz w konsoli mnóstwo danych wyjściowych po podłączeniu dysku. Jeśli zobaczysz komunikat o błędzie, taki jak Could not execute /usr/local/bin/trigger.sh, prawdopodobnie zapomniałeś uczynić skrypt wykonywalnym. W przeciwnym razie, miejmy nadzieję, że wszystko co widzisz to to, że urządzenie zostało podłączone, dostało jakieś przypisanie do urządzenia jądra, i tak dalej.

Teraz, chwila prawdy:

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

Jeśli widzisz bardzo aktualną datę i czas zwrócone z /tmp/udev.log, udev pomyślnie uruchomił twój skrypt.

Refiniowanie reguły w coś użytecznego

Problem z tą regułą jest taki, że jest bardzo ogólna. Podłączenie myszy, pendrive’a lub czyjegoś pendrive’a bez wyjątku uruchomi twój skrypt. Teraz jest czas, aby zacząć koncentrować się na dokładnym dysku kciukowym, który chcesz uruchomić swój skrypt.

Jednym ze sposobów, aby to zrobić jest identyfikator dostawcy i identyfikator produktu. Aby uzyskać te numery, można użyć polecenia 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

W tym przykładzie 03f0:3307 przed TyCoon Corp. oznacza atrybuty idVendor i idProduct. Możesz również zobaczyć te numery w wyjściu udevadm info -a -n /dev/sdb | grep vendor, ale uważam, że wyjście lsusb jest nieco łatwiejsze dla oczu.

Możesz teraz uwzględnić te atrybuty w swojej regule.

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

Sprawdź to (tak, nadal powinieneś zrestartować komputer, aby upewnić się, że otrzymujesz świeże reakcje od udev), i powinno to działać tak samo jak poprzednio, tylko teraz, jeśli podłączysz, powiedzmy, dysk miniaturowy wyprodukowany przez inną firmę (dlatego z innym idVendor) lub mysz lub drukarkę, skrypt nie zostanie wyzwolony.

Powtarzaj dodawanie nowych atrybutów, aby jeszcze bardziej skupić się na tym jednym unikalnym dysku miniaturowym, który ma wyzwolić skrypt. Używając udevadm info -a -n /dev/sdb, możesz dowiedzieć się takich rzeczy, jak nazwa sprzedawcy, czasami numer seryjny lub nazwa produktu i tak dalej.

Dla własnego rozsądku, upewnij się, że dodajesz tylko jeden nowy atrybut na raz. Większość błędów, które popełniłem (i widziałem jak inni ludzie online popełniają) to wrzucanie mnóstwa atrybutów do ich reguły udev i zastanawianie się dlaczego rzecz już nie działa. Testowanie atrybutów jeden po drugim jest najbezpieczniejszym sposobem na zapewnienie, że udev może zidentyfikować twoje urządzenie z powodzeniem.

Bezpieczeństwo

Wiąże się to z obawami o bezpieczeństwo pisania reguł udev, które automatycznie robią coś, gdy dysk jest podłączony. Na moich maszynach, nie mam nawet włączonego auto-mount, a jednak ten artykuł proponuje skrypty i reguły, które wykonują polecenia tylko przez to, że coś jest podłączone.

Dwie rzeczy, o których należy pamiętać.

  1. Skoncentruj swoje reguły udev, gdy już je uruchomisz, tak aby wywoływały skrypty tylko wtedy, gdy naprawdę tego chcesz. Wykonywanie skryptu, który ślepo kopiuje dane do lub z twojego komputera jest złym pomysłem w przypadku, gdy każdy, kto ma przy sobie pendrive tej samej marki, podłącza go do twojej skrzynki.
  2. Nie pisz reguł udev i skryptów i nie zapominaj o nich. Wiem, które komputery mają moje reguły udev na nich, a te skrzynki są najczęściej moimi osobistymi komputerami, a nie tymi, które zabieram na konferencje lub mam w biurze w pracy. Im bardziej „społeczny” jest komputer, tym mniej prawdopodobne jest, że znajdzie się na nim reguła udev, która może potencjalnie spowodować, że moje dane znajdą się na czyimś urządzeniu lub czyjeś dane lub złośliwe oprogramowanie na moim urządzeniu.

Innymi słowy, tak jak w przypadku wielu mocy dostarczanych przez system GNU, waszym zadaniem jest uważać na to, jak władacie tą mocą. Jeśli jej nadużyjesz lub nie potraktujesz z szacunkiem, może się to skończyć fatalnie.

Udev w prawdziwym świecie

Teraz, gdy możesz potwierdzić, że twój skrypt jest wywoływany przez udev, możesz zwrócić uwagę na funkcję skryptu. W tej chwili jest on bezużyteczny, nie robiąc nic więcej poza rejestrowaniem faktu, że został wykonany.

Używam udev do wyzwalania automatycznych kopii zapasowych moich dysków miniaturowych. Idea jest taka, że kopie główne moich aktywnych dokumentów znajdują się na moim dysku miniaturowym (ponieważ jest on wszędzie tam gdzie ja i może być w każdej chwili używany), a te kopie główne dokumentów są zapisywane na moim komputerze za każdym razem, gdy podłączam dysk do tego komputera. Innymi słowy, mój komputer jest dyskiem zapasowym, a moje dane produkcyjne są mobilne. Kod źródłowy jest dostępny, więc nie krępuj się spojrzeć na kod attachup dla dalszych przykładów ograniczania twoich testów udev.

Ponieważ to jest to, do czego najczęściej używam udev, jest to przykład, którego użyję tutaj, ale udev może złapać wiele innych rzeczy, takich jak gamepady (jest to przydatne w systemach, które nie są ustawione na ładowanie modułu xboxdrv, gdy gamepad jest podłączony) oraz kamery i mikrofony (przydatne do ustawiania wejść, gdy określony mikrofon jest podłączony), więc zdaj sobie sprawę, że jest to dobre dla o wiele więcej niż ten jeden przykład.

Prosta wersja mojego systemu tworzenia kopii zapasowych to proces składający się z dwóch poleceń:

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

Pierwsza linia wykrywa mój dysk miniaturowy z atrybutami już omówionymi, a następnie przypisuje dyskowi miniaturowemu symlink w drzewie urządzeń. Przypisane symlinkowanie to safety%n. %n jest makrem udev, które odpowiada numerowi nadanemu urządzeniu przez jądro, takiemu jak sdb1, sdb2, sdb3, i tak dalej. Tak więc %n będzie 1, 2 lub 3.

Tworzy to symlink w drzewie dev, więc nie przeszkadza w normalnym procesie podłączania urządzenia. Oznacza to, że jeśli używasz środowiska graficznego, które lubi automatyczny montaż urządzeń, nie będziesz powodował dla niego problemów.

Druga linia uruchamia skrypt.

Mój skrypt kopii zapasowej wygląda tak:

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

Skrypt używa symlinku, co pozwala uniknąć sytuacji, w której udev nada napędowi nieprzewidzianą nazwę (na przykład jeśli mam już podłączony do komputera dysk o nazwie DISK i podłączę inny dysk o tej samej nazwie, drugi będzie miał nazwę DISK_, co udaremni mój skrypt). Montuje safety1 (pierwszą partycję dysku) w preferowanym przeze mnie punkcie montowania /mnt/hd.

Po bezpiecznym zamontowaniu używa rsync do utworzenia kopii zapasowej dysku w moim folderze kopii zapasowych (mój skrypt używa rdiff-backup, a Twój może użyć dowolnego zautomatyzowanego rozwiązania do tworzenia kopii zapasowych, jakie preferujesz).

Udev jest Twoim dev

Udev jest bardzo elastycznym systemem i pozwala definiować reguły i funkcje w sposób, jaki niewiele innych systemów ośmiela się zapewnić użytkownikom. Naucz się go i używaj, i ciesz się potęgą POSIX-a.

Ten artykuł opiera się na zawartości podręcznika Slackermedia Handbook, który jest objęty licencją GNU Free Documentation License 1.3.

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.