Zapuszczając się w coraz to i głębsze warstwy systemu podczas dążenia do zbadania jak on tak naprawdę działa, zacząłem się stykać z regułami udeva -- tymi, które zwykle się umieszcza w katalogu /etc/udev/rules.d/ . Jako, że nazbierało mi się już ich kilka, zaistniała potrzeba zbadania tego co ten katalog zawiera. Na dobrą sprawę nigdy się nad tym nie zastanawiałem, jedynie kopiowałem rozwiązanie ze stronki i wklejałem do odpowiedniego pliku i jeśli takie rozwiązanie działało, to odznaczałem problem jako rozwiązany.

Zwykle takich reguł się nie potrzebuje, temu praktycznie niewielu ludzi w ogóle się orientuje jak ogarnąć tego całego udeva. Są przypadki kiedy przepisanie nazw urządzeń czy wykonanie określonych akcji po podłączeniu jakiegoś urządzenia do komputera jest wielce niezbędne i nie ma innej opcji jak tylko zrozumieć co udev tak naprawdę robi.

Za królika doświadczalnego będzie robił mój pendrak weteran, który posiada 3 partycje, z których jedna jest zaszyfrowana. Spróbujemy przy pomocy udeva wejść w interakcję z tym pendrivem, oraz wykonać pod jego adresem szereg akcji pisząc kilka regułek dla tego konkretnego urządzenia.

Pliki reguł

Na samym początku przyjrzyjmy się nieco katalogowi /etc/udev/rules.d/ -- zawiera on pliki zaczynające się od numerka od 00 do 99 . Na końcu każdego pliku musi być także .rules . Przykładowy plik wygląda zatem tak: 70-persistent-net.rules . Pliki są wczytywane jeden po drugim, te z niższymi numerkami jako pierwsze.

Same regułki wyglądają mniej więcej tak:

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:e0:4c:75:03:09", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"

Reguły również są parsowane jedna po drugiej (od góry do dołu w pliku) i jeśli udev znajdzie jakąś pasującą regułę dla urządzenia, to nie zatrzymuje się na niej. Dzięki temu można precyzować wiele reguł i zostaną one wszystkie zaaplikowane dla dopasowanego urządzenia.

Reguła składa się z grubsza z dwóch części. Pierwsza z nich ma za zadanie dopasowanie urządzenia, druga zaś ma to urządzenie odpowiednio dostosować. Jak odróżnić zatem te części od siebie? Parametry, na podstawie których urządzenie jest dopasowywane można poznać po znaku == . Pojedynczy znak = przypisuje konkretne wartości dla dopasowanego urządzenia, odpowiednio je zmieniając.

Pozyskiwanie informacji o urządzeniu

Nasuwa się zatem pytanie -- skąd brać te atrybuty, na których to podstawie urządzenie ma być dopasowane? Do tego celu służy narzędzie udevadm. Posiada ono kilka parametrów i jeszcze więcej opcji ale jeśli chodzi o szukanie informacji na temat urządzenia, to do tego celu służy udevadm info. Poniżej info na temat mojego pendrive:

# udevadm info --name /dev/sdb --attribute-walk

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18/target18:0:0/18:0:0:0/block/sdb':
    KERNEL=="sdb"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{ro}=="0"
    ATTR{size}=="30299520"
    ATTR{stat}=="     253        0     2024      808        0        0        0        0        0      708      808"
    ATTR{range}=="16"
    ATTR{discard_alignment}=="0"
    ATTR{events}=="media_change"
    ATTR{ext_range}=="256"
    ATTR{events_poll_msecs}=="3000"
    ATTR{alignment_offset}=="0"
    ATTR{inflight}=="       0        0"
    ATTR{removable}=="1"
    ATTR{capability}=="51"
    ATTR{events_async}==""

  looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18/target18:0:0/18:0:0:0':
    KERNELS=="18:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{rev}=="PMAP"
    ATTRS{type}=="0"
    ATTRS{scsi_level}=="0"
    ATTRS{model}=="DT 101 G2       "
    ATTRS{state}=="running"
    ATTRS{queue_type}=="none"
    ATTRS{iodone_cnt}=="0x12d"
    ATTRS{iorequest_cnt}=="0x12d"
    ATTRS{device_busy}=="0"
    ATTRS{evt_capacity_change_reported}=="0"
    ATTRS{timeout}=="30"
    ATTRS{evt_media_change}=="0"
    ATTRS{max_sectors}=="240"
    ATTRS{ioerr_cnt}=="0x2"
    ATTRS{queue_depth}=="1"
    ATTRS{vendor}=="Kingston"
    ATTRS{evt_soft_threshold_reached}=="0"
    ATTRS{device_blocked}=="0"
    ATTRS{evt_mode_parameter_change_reported}=="0"
    ATTRS{evt_lun_change_reported}=="0"
    ATTRS{evt_inquiry_change_reported}=="0"
    ATTRS{iocounterbits}=="32"
    ATTRS{eh_timeout}=="10"

  looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18/target18:0:0':
    KERNELS=="target18:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18':
    KERNELS=="host18"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0':
    KERNELS=="4-5:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb-storage"
    ATTRS{bInterfaceClass}=="08"
    ATTRS{bInterfaceSubClass}=="06"
    ATTRS{bInterfaceProtocol}=="50"
    ATTRS{bNumEndpoints}=="02"
    ATTRS{supports_autosuspend}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceNumber}=="00"

  looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5':
    KERNELS=="4-5"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{devpath}=="5"
    ATTRS{idVendor}=="0951"
    ATTRS{speed}=="480"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{busnum}=="4"
    ATTRS{devnum}=="20"
    ATTRS{configuration}==""
    ATTRS{bMaxPower}=="200mA"
    ATTRS{authorized}=="1"
    ATTRS{bmAttributes}=="80"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{maxchild}=="0"
    ATTRS{bcdDevice}=="0100"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{serial}=="001CC0EC34A2BB318709004B"
    ATTRS{version}==" 2.00"
    ATTRS{urbnum}=="889"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="Kingston"
    ATTRS{removable}=="unknown"
    ATTRS{idProduct}=="1642"
    ATTRS{bDeviceClass}=="00"
    ATTRS{product}=="DT 101 G2"

  looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4':
    KERNELS=="usb4"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{devpath}=="0"
    ATTRS{idVendor}=="1d6b"
    ATTRS{speed}=="480"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{authorized_default}=="1"
    ATTRS{busnum}=="4"
    ATTRS{devnum}=="1"
    ATTRS{configuration}==""
    ATTRS{bMaxPower}=="0mA"
    ATTRS{authorized}=="1"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{maxchild}=="8"
    ATTRS{bcdDevice}=="0313"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{serial}=="0000:00:1d.7"
    ATTRS{version}==" 2.00"
    ATTRS{urbnum}=="521"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="Linux 3.13-1-amd64 ehci_hcd"
    ATTRS{removable}=="unknown"
    ATTRS{idProduct}=="0002"
    ATTRS{bDeviceClass}=="09"
    ATTRS{product}=="EHCI Host Controller"

  looking at parent device '/devices/pci0000:00/0000:00:1d.7':
    KERNELS=="0000:00:1d.7"
    SUBSYSTEMS=="pci"
    DRIVERS=="ehci-pci"
    ATTRS{irq}=="23"
    ATTRS{subsystem_vendor}=="0x1458"
    ATTRS{broken_parity_status}=="0"
    ATTRS{class}=="0x0c0320"
    ATTRS{companion}==""
    ATTRS{enabled}=="1"
    ATTRS{consistent_dma_mask_bits}=="32"
    ATTRS{dma_mask_bits}=="32"
    ATTRS{local_cpus}=="00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000003"
    ATTRS{device}=="0x27cc"
    ATTRS{uframe_periodic_max}=="100"
    ATTRS{msi_bus}==""
    ATTRS{local_cpulist}=="0-1"
    ATTRS{vendor}=="0x8086"
    ATTRS{subsystem_device}=="0x5006"
    ATTRS{numa_node}=="-1"
    ATTRS{d3cold_allowed}=="1"

  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""

Generalnie te parametry można bezpośrednio kopiować do pliku reguł. Są one oddzielone od siebie przecinkami. Dodatkowo dla większej przejrzystości i czytelności reguły, linie mogą być łamane przy pomocy znaku \ .

Poza suchymi parametrami, które można wykorzystać jedynie w plikach reguł udeva, istnieją jeszcze zmienne środowiskowe, które są uzupełniane i eksportowane tuż po podłączeniu urządzenia. W przypadku gdy przy wykryciu danego zasobu potrzeba jest uruchomienia jakiegoś skryptu, te zmienne mogą okazać się wielce użyteczne, bo będą widoczne dla tego skryptu. Jeśli interesują nas te zmienne, możemy skorzystać z udevadm info --name /dev/sdb by je podejrzeć:

# udevadm info --name /dev/sdb
P: /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18/target18:0:0/18:0:0:0/block/sdb
N: sdb
S: disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0
S: disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0
E: DEVLINKS=/dev/disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0 /dev/disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0
E: DEVNAME=/dev/sdb
E: DEVPATH=/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18/target18:0:0/18:0:0:0/block/sdb
E: DEVTYPE=disk
E: ID_BUS=usb
E: ID_INSTANCE=0:0
E: ID_MODEL=DT_101_G2
E: ID_MODEL_ENC=DT\x20101\x20G2\x20\x20\x20\x20\x20\x20\x20
E: ID_MODEL_ID=1642
E: ID_PART_TABLE_TYPE=dos
E: ID_PATH=pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0
E: ID_PATH_TAG=pci-0000_00_1d_7-usb-0_5_1_0-scsi-0_0_0_0
E: ID_REVISION=PMAP
E: ID_SERIAL=Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0
E: ID_SERIAL_SHORT=001CC0EC34A2BB318709004B
E: ID_TYPE=disk
E: ID_USB_DRIVER=usb-storage
E: ID_USB_INTERFACES=:080650:
E: ID_USB_INTERFACE_NUM=00
E: ID_VENDOR=Kingston
E: ID_VENDOR_ENC=Kingston
E: ID_VENDOR_ID=0951
E: MAJOR=8
E: MINOR=16
E: SUBSYSTEM=block
E: USEC_INITIALIZED=284488623

Te zmienne również można wykorzystać w plikach reguł.

Składnia reguł

Jeszcze parę słów o znakach wykorzystywanych w plikach reguł. Wiemy już po co nam == oraz = ale spotkamy się z szeregiem innych "krzaków" i wypadało by również wiedzieć co one oznaczają. I tak np. przeciwieństwem == jest != . Jeśli reguła ma przyjąć kilka wartości, kolejne z nich przypisujemy przez +=. Z kolei jeśli po danej wartości już nie spodziewamy się by jakieś dalsze zmiany dla urządzenia zachodziły, przypisujemy tę wartość przy pomocy := .

Dodatkowo można również używać maski, czyli znaków, pod którymi mogą kryć się inne znaki. I tak * oznacza dowolny znak powtórzony 0 lub więcej razy. Z kolei zaś ? oznacza dowolny znak powtórzony tylko jeden raz. I mamy jeszcze możliwość sprecyzowania znaków przy pomocy [ ] . Jeśli chcemy użyć zakresu od "a" do "z", precyzujemy go w taki sposób: [a-z] . Można również wyłączyć określone znaki przy dopasowaniu za pomocą !, przykładowo bez "a-c": [!a-c] .

Możemy również skorzystać z krótkich nazw oferowanych przez udev przy podłączaniu urządzenia:

%r, $root -- katalog urządzeń, domyślnie /dev
%p, $devpath -- wartość DEVPATH
%k, $kernel -- wartość KERNEL
%n, $number -- numer urządzenia, dla sda3 to 3
%N, $tempnode -- tymczasowa nazwa pliku urządzenia
%M, $major -- większy numer urządzenia
%m, $minor -- mniejszy numer urządzenia
%s{attribute}, $attr{attribute} -- wartość atrybutu sysfs
%E{variable}, $attr{variable} -- wartość zmiennej środowiskowej
%c, $result -- wartość PROGRAM
%% -- znak %
$$ -- znak $

Omówienie reguł na przykładzie

Jak wspomniałem na wstępie, będziemy operować na pendrive, który ma 3 partycje, w tym też jedną zaszyfrowaną. Załóżmy, że chcemy aby partycje tego konkretnego urządzenia były montowane po jego podłączeniu. W przypadku zaszyfrowanej partycji, dodatkowo trzeba ją pierw odszyfrować. Jest tylko jeden problem, nazwy urządzenia (te widoczne w katalogu /dev/) się zmieniają. Jasne, że istnieją inne drogi by osiągnąć to co chcemy, np. można użyć UUID ale my tutaj skupimy się na rozwiązaniu tej kwestii przez udev, co ma też i swoje zalety, bo UUID może ulec zmianie, a numer seryjny urządzenia raczej jest nieco trwalszy.

Tworzymy zatem plik /etc/udev/rules.d/99-local.rules i dopisujemy tam regułki:

KERNEL=="sd?3", ACTION=="add", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \
    SYMLINK+="pen%n", \
    RUN+="/usr/bin/udevil mount /dev/pen%n /mnt/dane"

KERNEL=="sd?1", ACTION=="add", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \
    SYMLINK+="pen%n", \
    RUN+="/usr/bin/udevil mount /dev/pen%n /mnt/debian"

KERNEL=="sd?2", ACTION=="add", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \
    SYMLINK+="pen%n", \
    RUN+="/sbin/cryptsetup luksOpen /dev/pen%n pen%n --key-file=/home/morfik/Desktop/pen2.key", \
    RUN+="/usr/bin/udevil mount /dev/mapper/pen%n /mnt/szyfr"
KERNEL=="sd?2", ACTION=="remove", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \
    RUN+="/sbin/cryptsetup luksClose pen%n"

Co zatem mówią nam powyższe reguły?

Pierwsza z nich: jeśli urządzenie zostanie zarejestrowane z nazwą sd?3 przez kernel (znak ? oznacza dowolny znak, czyli sda3, sdb3, etc) oraz zmienna środowiskowa numeru seryjnego urządzenia to 001CC0EC34A2BB318709004B , udev ma utworzyć link do tego urządzenia (pen3, bo %n odpowiada 3) i zamontować urządzenie przez ten link w katalogu /mnt/dane . Pozycja z ACTION informuje udev, by tę regułę zaaplikował tylko przy podłączaniu urządzenia.

Druga reguła jest praktycznie taka sama co pierwsza, z tym, że numerki partycji się zmieniły.

Trzecia reguła różni się dodatkową linijką RUN, która odszyfrowuje kontener

Ostatnia reguła ma na celu zamknąć kontener, na wypadek gdyby ten nie został zamknięty ręcznie, np. w wyniku zbyt wczesnego wyciągnięcia pendrive, bo pierw trzeba odmontować partycję, a potem zamknąć kontener. W przypadku gdy jednak odmontujemy zasób i wyciągniemy pendriva, system dalej będzie widział otwarty kontener. Niby nic się nie powinno dziać w takim przypadku, ale gdy ponownie wsadzimy pendrive do portu USB, zostanie wykryty jako sdc, a nie sdb.

Udev i udevil

Jak widać w powyższych regułach został zastosowany udevil, nie zwykły mount, czy pmount. Ma on przewagę nad pozostałymi, bo potrafi precyzować kto może jakie urządzenia gdzie montować. I w tym przypadku może i root zamontował tego pendrive w podkatalogach /mnt ale użytkownik może bez problemu je odmontować i to nie każdy użytkownik tylko ten, któremu na to pozwolono.

Jeśli nie mamy zainstalowanego pakietu udevil w systemie, to koniecznie doinstalujmy go. Można oczywiście użyć innego systemu montowania ale ja tutaj skupię się tylko na udevilu.

Udevil posiada pliki konfiguracyjne w katalogu /etc/udevil/ i domyślnie jest tam jeden plik -- udevil.conf . Jest to konfiguracja systemowa określająca co gdzie może być montowane. Można tam utworzyć plik z konfiguracją per user. Ten plik musi posiadać nazwę podobną do tej: udevil-user-morfik.conf . Można zrobić kopię konfiguracji systemowej i pozmieniać tylko odpowiednie linijki. W tym przypadku zostały zmienione następujące wpisy:

allowed_media_dirs = /media/$USER, /media, /run/media/$USER, /mnt
allowed_devices = /dev/*, /dev/mapper/pen*
allowed_internal_devices = /dev/mapper/pen*

Krótko pisząc, zostało tam dopisane urządzenie /dev/mapper/pen* (można by zamiast * dać 2), bo jest ono wykrywane jako urządzenie wewnętrzne, a nie jako zewnętrzne, jak w przypadku pozostałych dwóch odszyfrowanych partycji na pendrive, przez co tylko root mógłby takie urządzenie zamontować, chyba, że zezwoli się na zamontowanie tego urządzenia komuś innemu i to właśnie zrobiliśmy w tym przypadku. Jak można również zobaczyć w pierwszej linijce, mamy tam katalogi, w których można montować zasoby. W przypadku mount możemy co prawda montować wszystko gdzie chcemy ale potrzebne są uprawnienia roota, z kolei w przypadku pmount możemy montować w katalogu /media/ jako zwykli użytkownicy, a udevil daje nam możliwość wybrania sobie co, gdzie i jak montować i temu deklasuje konkurencję.

Wywoływanie skryptów

Jeśli z jakichś powodów nie chcemy używać wielu linijek z "RUN" w konfiguracji reguł udeva, możemy sprecyzować do wykonania skrypt. Wtedy reguła dla zamontowania pen2 zmieni postać, np. na taką:

KERNEL=="sd?2", ACTION=="add", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \
    SYMLINK+="pen%n", \
    RUN+="/home/morfik/Desktop/mount.sh open"
KERNEL=="sd?2", ACTION=="remove", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \
    RUN+="/home/morfik/Desktop/mount.sh close"

A skrypt może wyglądać np. tak:

#!/bin/bash

open () {
    cryptsetup luksOpen /dev/pen2 pen2 --key-file=/home/morfik/Desktop/pen2.key && udevil mount /dev/mapper/pen2 /mnt/szyfr
}

close () {
    cryptsetup luksClose pen2
}

case "$1" in
    open)
        open
    ;;
    close)
        close
    ;;   
    *)
        echo "Usage: mount.sh {open|close}"
        exit 1
    ;;       
esac

exit 0

Jeśli posiadamy na pendrive 3 partycje (lub przynajmniej więcej niż 1) i nie są one zaszyfrowane, możemy uprościć reguły samego montowania do postaci:

KERNEL=="sd??", ACTION=="add", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \
    SYMLINK+="pen%n", \
    RUN+="/usr/bin/udevil mount /dev/pen%n /mnt/%E{ID_FS_LABEL_ENC}"

Powyższa regułka mówi, że przy dodawaniu urządzenia o numerze seryjnym 001CC0EC34A2BB318709004B, zostanie utworzony link do każdej z jego partycji, w tym przypadku pen1, pen2, pen3, oraz każda partycja zostanie zamontowana w katalogu /mnt/ w oparciu o jej etykietę -- %E{ID_FS_LABEL_ENC} .

Testowanie reguł

W przypadku gdy jakaś reguła nam nie działa i nie możemy dociec o co tak naprawdę chodzi, możemy przetestować taką regułę i zobaczyć co zostanie wypisane na konsoli. Partycja druga na pendrive jest opisana za pomocą:

# udevadm info --name /dev/sdb2
P: /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host26/target26:0:0/26:0:0:0/block/sdb/sdb2
...

Teraz testujemy reguły dla tego urządzenia:

# udevadm test /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host26/target26:0:0/26:0:0:0/block/sdb/sdb2
calling: test
version 204
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.

=== trie on-disk ===
tool version:          204
file size:         5729797 bytes
header size             80 bytes
strings            1262125 bytes
nodes              4467592 bytes
load module index
read rules file: /lib/udev/rules.d/42-usb-hid-pm.rules
read rules file: /lib/udev/rules.d/50-firmware.rules
read rules file: /lib/udev/rules.d/50-udev-default.rules
read rules file: /lib/udev/rules.d/55-dm.rules
read rules file: /lib/udev/rules.d/56-lvm.rules
read rules file: /lib/udev/rules.d/60-cdrom_id.rules
read rules file: /lib/udev/rules.d/60-fuse.rules
read rules file: /lib/udev/rules.d/60-gnupg.rules
read rules file: /lib/udev/rules.d/60-libfreenect0.2.rules
read rules file: /lib/udev/rules.d/60-libgphoto2-6.rules
read rules file: /lib/udev/rules.d/60-libpisock9.rules
read rules file: /lib/udev/rules.d/60-libsane.rules
read rules file: /lib/udev/rules.d/60-nvidia-kernel-common.rules
read rules file: /lib/udev/rules.d/60-pcmcia.rules
read rules file: /lib/udev/rules.d/60-persistent-alsa.rules
read rules file: /lib/udev/rules.d/60-persistent-input.rules
read rules file: /lib/udev/rules.d/60-persistent-serial.rules
read rules file: /lib/udev/rules.d/60-persistent-storage-dm.rules
read rules file: /lib/udev/rules.d/60-persistent-storage-tape.rules
read rules file: /lib/udev/rules.d/60-persistent-storage.rules
read rules file: /lib/udev/rules.d/60-persistent-v4l.rules
read rules file: /lib/udev/rules.d/60-virtualbox-dkms.rules
read rules file: /lib/udev/rules.d/60-virtualbox.rules
read rules file: /lib/udev/rules.d/61-accelerometer.rules
read rules file: /etc/udev/rules.d/61-removable-storage-polling.rules
read rules file: /lib/udev/rules.d/64-btrfs.rules
read rules file: /lib/udev/rules.d/64-xorg-xkb.rules
read rules file: /lib/udev/rules.d/69-cd-sensors.rules
IMPORT found builtin 'usb_id --export %p', replacing /lib/udev/rules.d/69-cd-sensors.rules:89
read rules file: /lib/udev/rules.d/69-libmtp.rules
read rules file: /lib/udev/rules.d/69-lvm-metad.rules
read rules file: /lib/udev/rules.d/69-xorg-vmmouse.rules
read rules file: /lib/udev/rules.d/70-btrfs.rules
read rules file: /etc/udev/rules.d/70-persistent-cd.rules
read rules file: /etc/udev/rules.d/70-persistent-net.rules
read rules file: /lib/udev/rules.d/70-power-switch.rules
read rules file: /lib/udev/rules.d/70-udev-acl.rules
read rules file: /etc/udev/rules.d/70-zram.rules
read rules file: /lib/udev/rules.d/75-cd-aliases-generator.rules
read rules file: /lib/udev/rules.d/75-net-description.rules
read rules file: /lib/udev/rules.d/75-persistent-net-generator.rules
read rules file: /lib/udev/rules.d/75-probe_mtd.rules
read rules file: /lib/udev/rules.d/75-tty-description.rules
read rules file: /lib/udev/rules.d/78-sound-card.rules
read rules file: /lib/udev/rules.d/80-btrfs-lvm.rules
read rules file: /lib/udev/rules.d/80-drivers.rules
read rules file: /lib/udev/rules.d/80-net-name-slot.rules
read rules file: /lib/udev/rules.d/80-networking.rules
read rules file: /lib/udev/rules.d/85-hdparm.rules
read rules file: /lib/udev/rules.d/85-hwclock.rules
read rules file: /lib/udev/rules.d/90-alsa-restore.rules
read rules file: /lib/udev/rules.d/90-pulseaudio.rules
read rules file: /lib/udev/rules.d/91-permissions.rules
read rules file: /lib/udev/rules.d/95-cd-devices.rules
read rules file: /lib/udev/rules.d/95-keyboard-force-release.rules
read rules file: /etc/udev/rules.d/95-keymap-media-keyboard-elite.rules
read rules file: /lib/udev/rules.d/95-keymap.rules
read rules file: /lib/udev/rules.d/95-udev-late.rules
read rules file: /lib/udev/rules.d/97-bluetooth-hid2hci.rules
read rules file: /etc/udev/rules.d/99-local.rules
rules contain 393216 bytes tokens (32768 * 12 bytes), 31439 bytes strings
27771 strings (226797 bytes), 24689 de-duplicated (198441 bytes), 3083 trie nodes used
LINK 'disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0-part2' /lib/udev/rules.d/60-persistent-storage.rules:110
LINK 'disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0-part2' /lib/udev/rules.d/60-persistent-storage.rules:132
IMPORT '/sbin/blkid -o udev -p /dev/sdb2' /lib/udev/rules.d/60-persistent-storage.rules:151
starting '/sbin/blkid -o udev -p /dev/sdb2'
'/sbin/blkid -o udev -p /dev/sdb2' [2404] exit with return code 0
LINK 'disk/by-uuid/90ec6f73-8fdb-4c8d-aebd-cadd0f51b412' /lib/udev/rules.d/60-persistent-storage.rules:158
RUN '/etc/init.d/hdparm hotplug' /lib/udev/rules.d/85-hdparm.rules:1
GROUP 6 /lib/udev/rules.d/91-permissions.rules:4
GROUP 25 /lib/udev/rules.d/91-permissions.rules:5
GROUP 25 /lib/udev/rules.d/91-permissions.rules:9
LINK 'pen2' /etc/udev/rules.d/99-local.rules:16
RUN '/sbin/cryptsetup luksOpen /dev/pen%n pen%n --key-file=/home/morfik/Desktop/pen2.key' /etc/udev/rules.d/99-local.rules:16
RUN '/usr/bin/udevil mount /dev/mapper/pen%n /mnt/szyfr' /etc/udev/rules.d/99-local.rules:16
handling device node '/dev/sdb2', devnum=b8:18, mode=0660, uid=0, gid=25
preserve permissions /dev/sdb2, 060660, uid=0, gid=25
preserve already existing symlink '/dev/block/8:18' to '../sdb2'
found 'b8:18' claiming '/run/udev/links/\x2fdisk\x2fby-id\x2fusb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0-part2'
creating link '/dev/disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0-part2' to '/dev/sdb2'
preserve already existing symlink '/dev/disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0-part2' to '../../sdb2'
found 'b8:18' claiming '/run/udev/links/\x2fdisk\x2fby-path\x2fpci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0-part2'
creating link '/dev/disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0-part2' to '/dev/sdb2'
preserve already existing symlink '/dev/disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0-part2' to '../../sdb2'
found 'b8:18' claiming '/run/udev/links/\x2fdisk\x2fby-uuid\x2f90ec6f73-8fdb-4c8d-aebd-cadd0f51b412'
creating link '/dev/disk/by-uuid/90ec6f73-8fdb-4c8d-aebd-cadd0f51b412' to '/dev/sdb2'
preserve already existing symlink '/dev/disk/by-uuid/90ec6f73-8fdb-4c8d-aebd-cadd0f51b412' to '../../sdb2'
found 'b8:18' claiming '/run/udev/links/\x2fpen2'
creating link '/dev/pen2' to '/dev/sdb2'
preserve already existing symlink '/dev/pen2' to 'sdb2'
.ID_FS_TYPE_NEW=crypto_LUKS
ACTION=add
DEVLINKS=/dev/disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0-part2 /dev/disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0-part2 /dev/disk/by-uuid/90ec6f73-8fdb-4c8d-aebd-cadd0f51b412 /dev/pen2
DEVNAME=/dev/sdb2
DEVPATH=/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host26/target26:0:0/26:0:0:0/block/sdb/sdb2
DEVTYPE=partition
ID_BUS=usb
ID_FS_TYPE=crypto_LUKS
ID_FS_USAGE=crypto
ID_FS_UUID=90ec6f73-8fdb-4c8d-aebd-cadd0f51b412
ID_FS_UUID_ENC=90ec6f73-8fdb-4c8d-aebd-cadd0f51b412
ID_FS_VERSION=1
ID_INSTANCE=0:0
ID_MODEL=DT_101_G2
ID_MODEL_ENC=DT\x20101\x20G2\x20\x20\x20\x20\x20\x20\x20
ID_MODEL_ID=1642
ID_PART_ENTRY_DISK=8:16
ID_PART_ENTRY_NUMBER=2
ID_PART_ENTRY_OFFSET=6293504
ID_PART_ENTRY_SCHEME=dos
ID_PART_ENTRY_SIZE=4194304
ID_PART_ENTRY_TYPE=0x83
ID_PART_TABLE_TYPE=dos
ID_PATH=pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0
ID_PATH_TAG=pci-0000_00_1d_7-usb-0_5_1_0-scsi-0_0_0_0
ID_REVISION=PMAP
ID_SERIAL=Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0
ID_SERIAL_SHORT=001CC0EC34A2BB318709004B
ID_TYPE=disk
ID_USB_DRIVER=usb-storage
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=Kingston
ID_VENDOR_ENC=Kingston
ID_VENDOR_ID=0951
MAJOR=8
MINOR=18
SUBSYSTEM=block
USEC_INITIALIZED=150393548
run: '/etc/init.d/hdparm hotplug'
run: '/sbin/cryptsetup luksOpen /dev/pen2 pen2 --key-file=/home/morfik/Desktop/pen2.key'
run: '/usr/bin/udevil mount /dev/mapper/pen2 /mnt/szyfr'
unload module index

Dobrze jest prześledzić linijki zawierające, w tym przypadku, plik reguł /etc/udev/rules.d/99-local.rules i sprawdzić czy polecenia, które chcemy wykonać nie zawierają czasem jakiejś literówki. Należy też prześledzić log pod kątem dopasowania reguły do urządzenia.

Dodatkowe informacje

W przypadku gdy zmieniamy reguły trzeba je ponownie załadować by udev mógł być świadom zmian. Można to zrobić przez:

# udevadm control --reload

Nazw urządzeń w kernelu nie można zmienić. W manualu jest tylko informacja, że "The name of a device node cannot be changed by udev, only additional symlinks can be created". Więc jeśli chcemy by urządzenie było dostępne pod inną nazwą trzeba tworzyć do niego linki, tak jak w przykładach powyżej.

Udev posiada także monitor zdarzeń i potrafi w czasie rzeczywistym wypisywać informacje na temat podłączanych/odłączanych urządzeń na konsoli. Można go wywołać przez:

$ udevadm monitor

Można mu także sprecyzować dodatkowe opcje w zależności od tego jakie informacje nam są potrzebne. Przykładowy log monitora wygląda jak poniżej:

# udevadm monitor
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

KERNEL[19007.937212] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5 (usb)
KERNEL[19007.937343] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0 (usb)
KERNEL[19007.938339] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28 (scsi)
KERNEL[19007.938370] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/scsi_host/host28 (scsi_host)
UDEV  [19008.068405] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5 (usb)
UDEV  [19008.107014] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0 (usb)
UDEV  [19008.107501] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28 (scsi)
UDEV  [19008.107726] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/scsi_host/host28 (scsi_host)
KERNEL[19009.029324] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0 (scsi)
KERNEL[19009.029366] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0 (scsi)
KERNEL[19009.029618] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_disk/28:0:0:0 (scsi_disk)
KERNEL[19009.029649] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_device/28:0:0:0 (scsi_device)
UDEV  [19009.030458] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0 (scsi)
KERNEL[19009.030483] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_generic/sg1 (scsi_generic)
KERNEL[19009.030505] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/bsg/28:0:0:0 (bsg)
UDEV  [19009.036115] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0 (scsi)
UDEV  [19009.036155] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_disk/28:0:0:0 (scsi_disk)
UDEV  [19009.036178] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/bsg/28:0:0:0 (bsg)
UDEV  [19009.037390] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_generic/sg1 (scsi_generic)
UDEV  [19009.040637] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_device/28:0:0:0 (scsi_device)
KERNEL[19009.569827] add      /devices/virtual/bdi/8:16 (bdi)
UDEV  [19009.570568] add      /devices/virtual/bdi/8:16 (bdi)
KERNEL[19009.591083] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb (block)
KERNEL[19009.591114] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb1 (block)
KERNEL[19009.591136] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb2 (block)
KERNEL[19009.591157] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb3 (block)
UDEV  [19010.248771] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb (block)
UDEV  [19010.343415] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb3 (block)
UDEV  [19010.397643] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb1 (block)
KERNEL[19011.151289] add      /devices/virtual/bdi/254:10 (bdi)
KERNEL[19011.156149] add      /devices/virtual/block/dm-10 (block)
UDEV  [19011.156181] add      /devices/virtual/bdi/254:10 (bdi)
UDEV  [19011.156265] add      /devices/virtual/block/dm-10 (block)
KERNEL[19011.157713] change   /devices/virtual/block/dm-10 (block)
KERNEL[19011.157742] change   /devices/virtual/block/dm-10 (block)
UDEV  [19011.158529] change   /devices/virtual/block/dm-10 (block)
UDEV  [19011.167694] change   /devices/virtual/block/dm-10 (block)
KERNEL[19011.182633] remove   /devices/virtual/block/dm-10 (block)
KERNEL[19011.183922] remove   /devices/virtual/bdi/254:10 (bdi)
KERNEL[19011.184066] remove   /devices/virtual/block/dm-10 (block)
UDEV  [19011.184377] remove   /devices/virtual/bdi/254:10 (bdi)
UDEV  [19011.197199] remove   /devices/virtual/block/dm-10 (block)
UDEV  [19011.197446] remove   /devices/virtual/block/dm-10 (block)
KERNEL[19011.483240] add      /devices/virtual/bdi/254:10 (bdi)
KERNEL[19011.484219] add      /devices/virtual/block/dm-10 (block)
UDEV  [19011.484242] add      /devices/virtual/bdi/254:10 (bdi)
UDEV  [19011.484269] add      /devices/virtual/block/dm-10 (block)
KERNEL[19011.484998] change   /devices/virtual/block/dm-10 (block)
UDEV  [19011.562665] change   /devices/virtual/block/dm-10 (block)
UDEV  [19011.608092] add      /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb2 (block)

Jeśli interesują nas tylko zdarzenia kernela (te zaczynające się od KERNEL), możemy sprecyzować --kernel przy wywoływaniu monitora. Można także mieć wgląda do zdarzeń udeva przez podanie parametru --udev .