udev - gestione dinamica dei dispositivi in Linux

udev è un rimpiazzo per il Device File System (DevFS) a partire dalla serie 2.6 del ?kernel Linux. Permette di identificare dinamicamente i dispositivi in base alle loro proprietà, come ID del produttore e ID di device. udev viene eseguito in spazio utente (a differenza di devfs che girava in spazio kernel).

udev permette l'uso di regole che specificano quale nome venga assegnato ad un dato dispositivo, indipendentemente dalla porta a cui è collegato. Per esempio è possibile avere una regola per montare sempre un disco fisso che produttore "iRiver" e codice di dispositivo "ABC" come {/dev/iriver}. Questa assegnazione costante dei nomi di device garantisce che script che dipendono dall'esistenza di un particolare device non smettano di funzionare.

Introduzione

Il sistema udev è composto da alcuni servizi kernel e dal demone udevd. Il kernel informa il demone udevd quando accadono determinati eventi; il demone udevd è configurato per rispondere ad eventi con le corrispondenti azioni. Le informazioni sugli eventi arrivano dal kernel, le azioni avvengono in spazio utente. Le risposte agli eventi sono configurabili con "regole".

La funzionalità udev in spazio utente è implementata da systemd-udevd.service. Il suo file di configurazione è in /etc/udev/udev.conf. I file delle regole (che consistono in ulteriori configurazioni per udev) vengono presi da /run/udev/rules.d, /etc/udev/rules.d o /lib/udev/rules.d. I pacchetti installano regole in /lib/udev/rules.d), mentre le posizioni /etc e /run forniscono una funzionalità con cui l'amministratore scavalca il comportamento di una regola fornita da un pacchetto. Se un file con lo stesso nome è presente in più di una di queste directory, allora vengono ignorati. I file presenti vengono analizzati in ordine alfabetico, a patto che il nome termini con ".rules". Quando il file di configurazione o i file delle regole vengono modificati deve essere usato il programma udevadm per dire a systemd-udevd di ricaricare le regole (vedere più avanti).

udev è stato creato per rispondere ad eventi di connessioni a caldo. Molta documentazione parla della creazione di device in risposta all'apparizione di nuovi device. Ma udev è molto più generico; può eseguire comandi arbitrari in spazio utente in risposta all'apparizione di un nuovo device, o a qualsiasi altro evento riceva dal kernel.

I momenti in cui udevd è attivo sono:

  1. all'avvio; analizza tutti i file di configurazione e i file di regole e crea un database di regole in memoria;
  2. quando avviene un evento; controlla nel suo database delle regole ed effettua l'azione appropriata.

Regole

Regole per le regole:

  1. le regole devono essere ciascuna su un'unica riga (le righe possono essere spezzate con \ immediatamente prima del ritorno a capo)
  2. le regole consistono di "corrispondenze" ed "azioni"
  3. le corrispondenze e le azioni sono compostd da triplette "chiave" "operatore" "valore"
  4. le corrispondenze contengono l'operatore == o !=
  5. le azioni contengono l'operatore = (assegnazione)
  6. le corrispondenze controllano uno o più attributi dell'evento per vedere se l'azione verrà effettuata;
  7. le azioni specificano ciò che accadrà
  8. esempio di corrispondenza: BUS=="usb"

  9. esempio di azione: NAME="mydev"

  10. esempio di regola:

    KERNEL=="sd*[0-9]|dasd*[0-9]", ENV{ID_SERIAL}=="?*", \
            SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n"
  11. tutte le regole che fanno corrispondenza verranno eseguite
  12. le regole che vengono prima hanno precedenza sulle regole successive: quindi mettere le proprie personalizzazioni tra i primi file in rules.d
  13. le azioni come key="value" sovrascrivono le altre
  14. le azioni come key+="value" si aggiungono alle azioni che vengono eseguite, es. SYMLINK+="foo" significa "oltre a qualsiasi altro collegamento simbolico che viene creato per questo evento, crearne anche uno chiamato foo"

Insiemi di regole

Regole per gli insiemi di regole:

  1. Tutte le regole sono in un unico grande spazio delle regole, anche se sono suddivise in vari file
  2. L'unica organizzazione nello spazio delle regole è data dalla possibilità di impostare etichette e quindi di saltare un gruppo di regole al momento della "ricerca delle corrispondenze con questo evento nelle regole" saltando in avanti con un'azione GOTO

  3. Esiste un altro tipo di regole chiamata etichette, ad esempio LABEL="persistent_storage_end", vengono usate da regole normali che hanno azioni "GOTO", ad esempio:

    ACTION!="add", GOTO="persistent_storage_end"
    Notare che in questa regola, il termine ACTION è un attributo di un evento e viene usato come condizione per decidere se deve scattare l'azione GOTO
  4. È bene limitare i salti GOTO all'interno di uno stesso file (o ci si dovrà preoccupare in caso di riordino dei file)
  5. Non saltare indietro ad un'etichetta (l'autore non ha provato a farlo, ma immagina che la cosa risulterebbe in un ciclo infinito. Forse il codice di udev controlla che ciò non avvenga, ma se, nel caso migliore, la cosa è ignorata, perché farla?)
  6. Si possono impostare variabili nello spazio ENV di ambiente in regole e fare riferimento ad esse nelle regole successive
  7. Esiste la funzione per la creazione di regole dinamiche (esempio: vedere z45_persistent-net-generator.rules)

Liste nere

Liste nere per i moduli del kernel

Nomi di device persistenti

In questo esempio, si vuole fare in modo che la scheda 3G ottenga un nome costante.

1. Inserire la "scheda" (o il dispositivo)

2. Eseguire il comando seguente, sul device appropriato:

$ udevadm info --name=/dev/ttyS1 --attribute-walk

udevadm si avvia sul device specificato da devpath e poi si muove verso l'alto lungo la catena di device genitori. Stampa per ogni device trovato tutti i possibili attributi nel formato delle chiavi delle regole di udev. Una regola per una corrispondenza può essere composta dagli attributi del device e dagli attributi di un solo device genitore.

  looking at device '/class/tty/ttyS1':
    KERNEL=="ttyS1"
    SUBSYSTEM=="tty"
    DRIVER==""
    ATTR{dev}=="4:65"

  looking at parent device '/devices/pci0000:00/0000:00:1e.0/0000:15:00.0/0.0':
    KERNELS=="0.0"
    SUBSYSTEMS=="pcmcia"
    DRIVERS=="serial_cs"
    ATTRS{modalias}=="pcmcia:m00A4c1AAFf02fn00pfn00pa32607776pbD9E73B13pcAF9C4D7Fpd00000000"
    ATTRS{prod_id3}=="NRM6831"
    ATTRS{prod_id2}=="Merlin UMTS Modem"
    ATTRS{prod_id1}=="Novatel Wireless"
    ATTRS{card_id}=="0x1aaf"
    ATTRS{manf_id}=="0x00a4"
    ATTRS{func_id}=="0x02"
    ATTRS{pm_state}=="on"
    ATTRS{function}=="0x00"

  looking at parent device '/devices/pci0000:00/0000:00:1e.0/0000:15:00.0':
    KERNELS=="0000:15:00.0"
    SUBSYSTEMS=="pci"
    DRIVERS=="yenta_cardbus"
    ATTRS{msi_bus}=="1"
    ATTRS{broken_parity_status}=="0"
    ATTRS{enable}=="2"
    ATTRS{numa_node}=="0"
    ATTRS{modalias}=="pci:v00001180d00000476sv000017AAsd000020C6bc06sc07i00"
    ATTRS{local_cpus}=="00000003"
    ATTRS{irq}=="16"
    ATTRS{class}=="0x060700"
    ATTRS{subsystem_device}=="0x20c6"
    ATTRS{subsystem_vendor}=="0x17aa"
    ATTRS{device}=="0x0476"
    ATTRS{vendor}=="0x1180"

  looking at parent device '/devices/pci0000:00/0000:00:1e.0':
    KERNELS=="0000:00:1e.0"
    SUBSYSTEMS=="pci"
    DRIVERS==""
    ATTRS{msi_bus}=="1"
    ATTRS{broken_parity_status}=="0"
    ATTRS{enable}=="1"
    ATTRS{numa_node}=="0"
    ATTRS{modalias}=="pci:v00008086d00002448sv00000000sd00000000bc06sc04i01"
    ATTRS{local_cpus}=="00000003"
    ATTRS{irq}=="0"
    ATTRS{class}=="0x060401"
    ATTRS{subsystem_device}=="0x0000"
    ATTRS{subsystem_vendor}=="0x0000"
    ATTRS{device}=="0x2448"
    ATTRS{vendor}=="0x8086"

  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""
    ATTRS{uevent}==""

3. Creare un file in /etc/udev/rules.d, tipicamente chiamato z21_persistent-local.rules.

ATTRS{prod_id2}=="Merlin UMTS Modem", ATTRS{prod_id1}=="Novatel Wireless", SYMLINK+="MerlinUMTS"
## Alternatively we could use :
# ATTRS{card_id}=="0x1aaf", ATTRS{manf_id}=="0x00a4", SYMLINK+="MerlinUMTS"

4. Forzare la riesecuzione degli script (o riavviare ;)

udevadm control --reload-rules
udevadm test -a -p $(udevadm info -q path -n /dev/ttyS1)

Un esempio più dettagliato scritto da semu5 su comp.os.linux.questions. Esiste anche una guida su come Scrivere regole udev.

Riferimenti


CategorySystemAdministration | CategoryBootProcess | CategoryHardware