Home Corsi Programmazione Linux udev: ecco come Linux gestisce i file in /dev

In evidenza

SMAU a Bologna con Research to Business

SMAU a Bologna con Research to Business

Il 6 e 7 giugno il Roadshow Smau Business torna a far tappa al Padiglione 33 della Fiera di Bologna e...
Gli articolisti del Portale

Gli articolisti del Portale

Abbiamo deciso di dare più visibilità a tutti coloro che hanno pubblicato articoli per noi, questo perché...
SMAU festeggia il suo quinto anno nel NordEst a Padova

SMAU festeggia il suo quinto anno nel NordEst a Padova

Il 18 e 19 aprile al padiglione 5 di Padova Fiere si terrà la prossima tappa di SMAU Business Roadshow. All'evento...
SMAU risale l’Italia e arriva a Roma

SMAU risale l’Italia e arriva a Roma

Il 21 e 22 marzo nella Nuova Fiera di Roma si terrà la prossima tappa di SMAU Business Roadshow. L'evento...

Bandi di Concorso

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Esperto di servizi e tecnologie cloud al Digit PA

Procedura comparativa per il conferimento di un incarico di collaborazione coordinata e continuativa per un profilo senior di “Esperto di servizi e tecnologie cloud”, nell’ambito del progetto europeo “Open Dai” presso l' Ente nazionale per la digitalizzazione della Pubblica Amministrazione...

18 Apr 2012 - Letture:34

Selezione per addetto servizi informatici all'Autorità Portuale di Brindisi

Avviso di selezione pubblica per titoli e prova orale per l’assunzione di n. 1 “addetto ai servizi informatici”, a tempo pieno ed determinato triennale, previo periodo di prova, da inquadrare nell’Area Amministrativa. (Inquadramento al III Livello del C.C.N.L. dei Lavoratori...

12 Feb 2012 - Letture:435

Concorso pubblico per informatico alla Corte dei Conti

E' indetto un concorso pubblico, per   esami,   per   il reclutamento di tre unità di informatici da inquadrare nella III area, fascia retributiva F1, da destinare agli Uffici della Corte dei Conti con sede in Roma. Requisiti: laurea triennale in scienze e...

05 Feb 2012 - Letture:306

Istruttore informatico L.68/1999 al Comune di Potenza

Concorso pubblico, per esami, per la copertura di n. 2 posti di Istruttore Informatico, categoria C, posizione economica C1, a tempo pieno e indeterminato, con riserva assoluta alle categorie dilavoratori di cui all'art. 1 della legge n. 68/1999 (norme per...

21 Gen 2012 - Letture:244

Senior Business Consultant presso Lombardia Informatica

Selezione per figura Senior Business Consultant presso Lombardia Informatica. Il collaboratore dovrà fornire consulenza strategica e di business sulle tematiche verticali della Socio-Sanità. Requisiti di ammissione: Laurea in Ingegneria, Economia e Commercio o Scienze dell’Informazione; Percorsi di formazione professionale in ambito sanitario e socio-sanitario, su...

11 Gen 2012 - Letture:284

Bando progetto TAG (Toscana Area Giovani) per giovani talenti digitali

UPI Toscana ha indetto un avviso pubblico per la selezione di 20 giovani (2 per ciascuna delle 10 province della Toscana), da impiegare come formatori all'interno del Progetto TAG (Toscana Area Giovani). Il bando è finalizzato a valorizzare al meglio i...

03 Gen 2012 - Letture:271

Avviso pubblico per giovani dottori di ricerca per Uffici di Gabinetto

Avviso pubblico per il conferimento di n. 6 incarichi presso gli Uffici di diretta collaborazione del Ministro dell'istruzione dell'università e della ricerca, per soggetti estranei alla pubblica amministrazione. Ambiti di esperienza e Aree di competenza: Nuovi Media: nuove forma di comunicazione tra...

02 Gen 2012 - Letture:217

I più attivi

Dati e punteggi dell'ultimo anno

Giovanna Casamassima Giovanna Casamassima
46 articoli
15,989 punti totali
Rodolfo Giometti Rodolfo Giometti
49 articoli
5,061 punti totali
Vittorio D'Aversa Vittorio D'Aversa
33 articoli
3,425 punti totali
Fabio Bronzini Fabio Bronzini
9 articoli
0,318 punti totali
Fulvio Lucchetti Fulvio Lucchetti
9 articoli
0,275 punti totali

Ci hanno visitato

Oggi:1452
Ieri:2498
Totali (14/04/09):1162299

I nostri numeri

Articoli pubblicati: 552
Iscritti al portale: 766
Iscritti all'Elenco: 184
Iscritti ML Discussioni: 351
Iscritti ML Articoli: 30
Iscritti ML Lavoro: 166
 
udev: ecco come Linux gestisce i file in /dev Stampa E-mail
(1 voto, media 4.00 di 5)
Area Corsi - Programmazione Linux
Scritto da Rodolfo Giometti   
Martedì 20 Aprile 2010 10:17
Articolo letto 2663 volte

Sin dalle prime versioni del kernel 2.6 c'è stata una piccola rivoluzione nella gestione dei dispositivi connessi al sistema e della gestione dei loro driver: un nuovo file system ha visto la luce (sysfs) ed una nuova procedura di identificazione dei device si è imposta (udev).

Vediamo di illustrare brevemente questi concetti focalizzandoci in particolar modo su udev e su come questo funziona.

 

Concetti di base

In un sistema UNIX in generale e Linux in particolare la directory /dev viene usata per contenere tutti quei file che identificano un dispositivo all'interno del sistema. Un disco, la tastiera, il mouse ecc. hanno tutti un riferimento nella directory /dev. Ogni file in questa directory è detto nodo (file node) e può essere di due tipi: char o block.

Riporto di seguito un esempio di file di tipo block (il mio disco primario):

$ ls -l /dev/sda*
brw-rw---- 1 root disk 8, 0 Apr 15 02:45 /dev/sda
brw-rw---- 1 root disk 8, 1 Apr 15 02:45 /dev/sda1
brw-rw---- 1 root disk 8, 2 Apr 15 02:45 /dev/sda2
brw-rw---- 1 root disk 8, 3 Apr 15 02:45 /dev/sda3
brw-rw---- 1 root disk 8, 4 Apr 15 02:45 /dev/sda4

mentre questo è un esempio di dispositivi di tipo char (le porte seriali di default di un qualsiasi PC):

$ ls -l /dev/ttyS*
crw-rw---- 1 root dialout 4, 64 Apr 15 02:45 /dev/ttyS0
crw-rw---- 1 root dialout 4, 65 Apr 15 02:45 /dev/ttyS1
crw-rw---- 1 root dialout 4, 66 Apr 15 02:45 /dev/ttyS2
crw-rw---- 1 root dialout 4, 67 Apr 15 02:45 /dev/ttyS3

I dispositivi di tipo block (o block device) sono tutti quei dispositivi che trasferiscono i dati a blocchi di dimensione fissa; i principali «esponenti» di questa categoria sono gli hard disk e tutti quei dispositivi di memorizzazione di massa. Mentre i dispositivi di tipo char (o char device) sono tutti quei dispositivi che trasferiscono i propri dati come flusso di caratteri senza dimensione fissa e si accedono, di solito, come se fossero dei file (si veda il concetto di «astrazione file» dei sistemi UNIX).

Ogni file node presente nella directory /dev rappresenta quindi un dispositivo di sistema e viene utilizzato dai processi che girano nello userspace per accedere al dispositivo a cui fanno riferimento.

Come ben saprete, in un sistema UNIX (e Linux non fa eccezione) ogni dispositivo è pilotato da un particolare software che prende il nome di driver. Il driver riceve i comandi dai processi dallo userland (processi utente) e li passa al dispositivo a lui associato (in realtà un driver può pilotare anche più di un dispositivo; anzi, in realtà il caso che un driver piloti solo un dispositivo è rarissimo e comunque considerato un cattivo esempio di programmazione). L'anello di collegameno tra il driver (e quindi i dispositivi a lui collegati) e  i processi utente sono appunto i file nella directory /dev.

In parole povere la catena è questa:

processo utente --> file in /dev --> driver --> dispositivo

Il driver, una volta scritto, viene caricato nel kernel del sistema e rimane lì in attesa di comandi. L'operazione di caricamento del driver nel kernel però, non genera anche l'automatica creazione del file node in /dev poiché questa operazione interessa solamente il kernel del sistema e non lo spazio utente! In particolare il kernel non conosce neppure l'esistenza del file node in /dev, lui conosce solo l'identificativo univoco all'interno del sistema per ogni dispositivo (detto major number) e la sua classe di appartenenza (block o char).

Ad esempio, con riferimento alle porte seriali di cui sopra, si ha che la prima porta seriale chiamata /dev/ttyS0 è definita come:

$ ls -l /dev/ttyS0
crw-rw---- 1 root dialout 4, 64 Apr 15 02:45 /dev/ttyS0

quel 4 dopo la parola dialout è il major number del dispositivo e che identifica, all'interno del sistema, i dispositivi seriali, il 66 e invece il minor number che, all'interno dei dispositivi seriali,
identifica la prima porta seriale (il nimor number e gestito in maniera diversa da driver a driver). Il tipo del file node viene invece specificato dalla prima lettera che si legge ion cima ai permessi di accesso, quella c infatti identifica il file node di tipo char.

Come riprova andiamo a vedere nel file /proc/devices, dove si ha l'elenco di tutti i major number definiti nel sistema, se quello che abbiamo detto corrisponde:

$ awk '$1 == 4' /proc/devices
4 /dev/vc/0
4 tty
4 ttyS

Sì, proprio come avevamo detto: il major number 4 raggruppa non solo le porte seriali ma tutta la classe dei terminali (seriali e non).

E' facile allora capire come i file node in /dev siamo importanti per collegare lo spazio utente con i dispositivi del sistema.

Il vecchio metodo

In passato, nei kernel 2.4 e precedenti, per creare questi file node si utilizzavano due tecniche principali:

  • o si utilizzava una directory /dev statica dove si definivano tutti i possibili file node di ogni possbile dispositivo collegabile al sistema, oppure
  • si utilizzava devfs, un file system virtuale gestito dal kernel stesso che doveva provvedere a creare questi file node ogni volta che un nuovo driver veniva caricato nel sistema.

La prima soluzione era quella più semplice ma che portava ad avere una directory /dev piuttosto grande e, in percentuale, poco utilizzata a causa dell'enorme numero di possibili dispositivi collegabili; la seconda soluzione, invece, cercava di risolvere gli inconvenenti della prima ma con pochi risultati a causa della enorme complessità e di non pochi problemi di robustezza.

Ma col kernel 2.6 le cose sono cambiate...

Il nuovo metodo

Nel kernel 2.6, appunto, Linux acquista un nuovo file system: il sysfs, un file sistem virtuale dove ogni dispositivo del sistema è rappresentato da una directory e da dei file (chiamati attributi). Il sysfs è visitabile nella directory solitamente nella /sys ed è parte integrante del nuovo modello di device di Linux: ogni dispositivo ha associato una struttura struct device che lo identifica univocamente, ogni driver quindi ha a che fare con essa e la usa per comunicare al kernel le operazioni notevoli da fare sul dispositivo stesso: inserimento, rimozione, ecc..

Grazie a questi nuovi concetti sono stati allora definiti gli eventi di nucleo, eventi notevoli, cioè, definiti all'interno del sistema e che descrivono una azione ben precisa su di un ben precisono dispositivo. Se, ad esempio, una chiavetta USB viene inserita nel sistema, una volta che il controller USB host l'ha identificata viene subito creato una nuova struttura struct device che mantiene ed identifica il dispositivo chiavetta USB. Una volta fatto questo, poiché il dispositivo è stato aggiunto nel sistema, viene anche generato un evento inserimento del dispositivo chiavetta USB; questo evento viene quindi catturato da udev.

udev: cosa fa e cosa è

Il programma udev non è altro che un normale processo utenete che sta in attesa degli eventi di sistema e, a seconda di una serie di regole, esegue determinate azioni. Ogni qual volta un evento viene catturato lui analizza le regole specificate per esso (solitamente dei file nella diectory /etc/udev/rules.d) e quindi crea il file node necessario; non solo, è anche in grado di eseguire programmi sul dispositivo stesso e molto altro!

La presenza di queste regole rende udev molto versatile ed in particolare, considerando che possiano lanciare anche programmi esterni, ci permette di:

  • rinominare un dispositivo a piacere (dargli quindi un nome diverso dallo standard);
  • creare dei nomi persisteni per i dispositivi (ad ogni dispositivo un nome sempe uguale e mai varibile a seconda della configurazione del sistema);
  • decidere i permessi di accesso ai dispositivi in maniera dinamica;
  • eseguire applicazioni spefiche quando un dispositivo viene aggiunto o rimosso dal sistema (si pensi ad esempio alla possibilità di far visualizzare automaticamente il contenuto di una chiavetta USB dopo che questa è stata collegata al sistema).

Le regole

Come vedremo, le regole di udev sono molto potenti e quindi possono essere anche molto complicate, ma una volta capito come funzionano, ed usandole intelligentemente, si scopre che non sono poi così difficili da capire. Le regole di udev sono contenute in uno o più file, all'interno della directory /etc/udev/rules.d, esso infatti analizza tutti i file presenti nella directory in ordine alfabetico ed ogni volta che trova una corrispondenza esegue l'azione associata.

Una regola, all'interno del file, sta tutta su una linea, quindi non si può spezzare su più linee (non si hanno caratteri speciali per questo), mentre una linea che inizia con # identifica un commento.

La sintassi poi è semplice: una serie di parole chiave separate da virgole:

KERNEL=="hda", NAME="disco_ide"

Questa regola possiede un confronto (segno ==) ed una assegamento (segno =) e dice ad udev che ogni volta che viene agiunto un dispositivo che il kernel chiama hda (il primo disco IDE) lui deve rinominarlo in disco_ide e creare il nodo di conseguenza. Se scrivessi invece:

KERNEL=="hda", DRIVER="ide-disk", NAME="disco_ide", SYMLINK+="disco_spare"

direi ad udev di fare la stessa cosa di prima ma se, e solo se, il driver che gestisce il dispositivo hda è ide-disk (in pratica escludo, ad esempio, i cdrom) ed inoltre gli dico di creare anche un link simbolico al file /dev/disco_ide in modo tale che una applicazione possa accedere al disco aprendo il file /dev/disco_spare.

Le parole chiavi principali di una regola sono (si veda il manuale per la lista esaustiva):

  • KERNEL: che identifica il nome che il kernel dà ad un dispositivo.
  • SUBSYSTEM: che identifica un sottosistema di appartenenza di un dispositivo.
  • DRIVER: che identifica il nome del driver che gestisce un dispositivo.
  • ATTR: che identifica un attibuto di un dispositivo (definito nel sysfs).

Mentre, i principali assegamenti che si possono fare sono (si veda il manuale per la lista esaustiva):

  • NAME: che identifica il nome con cui va chiamato il dispositivo.
  • SYMLINK: che identifica una lista di possibili alias del dispositivo (si noti il carattere += nell'assegnazione dell'esempio sopra dice di aggiungere il nome alla lista dei possibili link simbolici, non di assegnarlo univocamente).
  • RUN: che identifica il programma da lanciare sul dispositivo per compiere specifiche azioni su di esso.

Nei confronti di ogni parola chiave il confronto (match) viene fatto carattere per carattere ma si possono usare anche delle wildcard:

  • Con * si identificano tutti i caratteri, zero o piu volte.
  • Con ? si identificano tutti i caratteri ma una volta sola.
  • Con [] si identificano solo i caratteri racchiusi nelle parentesi (si possono specificare degli intervalli usando il segno -).

Mentre, negli assegnamenti si possono usare dei caratteri speciali:

  • Con %k si specifica il nome che il kernel dà al dispositivo.
  • Con %n si specifica il kernel number, cioe un numero che il kernel assegna al device e che può assumere significati diversi (ad esempio per un disco esso rappresenta il numero della partizione rilevata).

Ad esempio:

KERNEL="fd[0-9]*", NAME="floppy/%n", SYMLINK+="%k"

dice ad udev di rinominare tutti i dispositivi il cui nome inizia per fd seguito da un carattere numerico tra 0 e 9 e quindi da altri caratteri in /dev/floppy/numero, dove numero identifica se è il primo floppy, il secondo e così via; inoltre si richiede anche la creazione di un link simbolico a questi nuovi nomi utilizzando il nome di default scelto dal kernel (magari per mantenere la compatibilità con la vecchia convenzione).

Trovare le informazioni nel sysfs

Come detto più volte, udev si appoggia su sysfs ed  è quindi molto importante sapere come è possibile andare a cercare dentro di esso tutte quelle informazioni che ci possono servire per creare le nostre regole.

Ad esempio, se volessimo creare una regola per creare un nodo particolare, e ben definito, per una nostra chiavetta USB, in modo tale che ogni volta che questa viene inserita venga sempre individuata all'interno del sistema con uno stesso nome (indipendentemente dalla configurazione dello stesso), possiamo procedere come segue.

Prima di tutto colleguamo la nostra chiavetta al sistema e poi vediamo dove viene mappata. Nei log di sistema vedo:

scsi 1:0:0:0: Direct-Access     Generic  STORAGE DEVICE   1.04 PQ: 0 ANSI: 0
sd 1:0:0:0: [sda] 256000 512-byte logical blocks: (131 MB/125 MiB)
sd 1:0:0:0: [sda] Write Protect is off
sd 1:0:0:0: [sda] Mode Sense: 02 00 00 00
sd 1:0:0:0: [sda] Assuming drive cache: write through
sd 1:0:0:0: [sda] Assuming drive cache: write through
sda: sda1
sd 1:0:0:0: [sda] Assuming drive cache: write through
sd 1:0:0:0: [sda] Attached SCSI removable disk

Quindi la chiavetta è mappata nel nodo /dev/sda e la prima partizione è /dev/sda1, per sapere allora dove sta la directory corrispondente nel sysfs uso:

# udevinfo -q path -n /dev/sda1
/block/sda/sda1

quindi:

# ls /sys/block/sda/sda1
alignment_offset  discard_alignment  inflight    size   stat      uevent

dev               holders            partition   start  subsystem

Ora per avere la lista di tutti gli attributi uso:

# udevinfo -a -p /sys/block/sda/sda1/
Udevinfo 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 '/block/sda/sda1':
KERNEL=="sda1"
SUBSYSTEM=="block"
DRIVER==""
ATTR{partition}=="1"
ATTR{start}=="32"
ATTR{size}=="255968"
ATTR{alignment_offset}=="0"
ATTR{discard_alignment}=="4294950912"
ATTR{stat}=="      29      128     1256     1550        0        0        0        0        0      920     1550"
ATTR{inflight}=="       0        0"

looking at parent device '/block/sda':
KERNELS=="sda"
SUBSYSTEMS=="block"
DRIVERS==""
ATTRS{range}=="16"
ATTRS{ext_range}=="256"
ATTRS{removable}=="1"
ATTRS{ro}=="0"
ATTRS{size}=="256000"
ATTRS{alignment_offset}=="0"
ATTRS{discard_alignment}=="0"
ATTRS{capability}=="53"
ATTRS{stat}=="      34      140     1392     1650        0        0        0        0        0      990     1650"
ATTRS{inflight}=="       0        0"

looking at parent device '/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1/target1:0:0/1:0:0:0':
KERNELS=="1:0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{device_blocked}=="0"
ATTRS{type}=="0"
ATTRS{scsi_level}=="0"
ATTRS{vendor}=="Generic "
ATTRS{model}=="STORAGE DEVICE  "
ATTRS{rev}=="1.04"
ATTRS{state}=="running"
ATTRS{timeout}=="30"
ATTRS{iocounterbits}=="32"
ATTRS{iorequest_cnt}=="0x1d4"
ATTRS{iodone_cnt}=="0x1d4"
ATTRS{ioerr_cnt}=="0x1"
ATTRS{modalias}=="scsi:t-0x00"
ATTRS{evt_media_change}=="0"
ATTRS{queue_depth}=="1"
ATTRS{queue_type}=="none"
ATTRS{max_sectors}=="240"

looking at parent device '/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1/target1:0:0':
KERNELS=="target1:0:0"
SUBSYSTEMS==""
DRIVERS==""

looking at parent device '/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1':
KERNELS=="host1"
SUBSYSTEMS==""
DRIVERS==""

looking at parent device '/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0':
KERNELS=="1-1.3:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="usb-storage"
ATTRS{bInterfaceNumber}=="00"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bNumEndpoints}=="02"
ATTRS{bInterfaceClass}=="08"
ATTRS{bInterfaceSubClass}=="06"
ATTRS{bInterfaceProtocol}=="50"
ATTRS{modalias}=="usb:v0781p7100d0104dc00dsc00dp00ic08isc06ip50"
ATTRS{supports_autosuspend}=="0"
ATTRS{interface}=="Bulk-Only"

looking at parent device '/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3':
KERNELS=="1-1.3"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{configuration}==""
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bmAttributes}=="80"
ATTRS{bMaxPower}=="100mA"
ATTRS{urbnum}=="1101"
ATTRS{idVendor}=="0781"
ATTRS{idProduct}=="7100"
ATTRS{bcdDevice}=="0104"
ATTRS{bDeviceClass}=="00"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bNumConfigurations}=="1"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{speed}=="12"
ATTRS{busnum}=="1"
ATTRS{devnum}=="4"
ATTRS{devpath}=="1.3"
ATTRS{version}==" 2.00"
ATTRS{maxchild}=="0"
ATTRS{quirks}=="0x0"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{authorized}=="1"
ATTRS{manufacturer}=="SanDisk Corporation "
ATTRS{product}=="Cruzer Mini "
ATTRS{serial}=="000315435"

looking at parent device '/devices/platform/pxa27x-ohci/usb1/1-1':
KERNELS=="1-1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{configuration}==""
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bmAttributes}=="e0"
ATTRS{bMaxPower}==" 80mA"
ATTRS{urbnum}=="65"
ATTRS{idVendor}=="04b4"
ATTRS{idProduct}=="6560"
ATTRS{bcdDevice}=="9415"
ATTRS{bDeviceClass}=="09"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bNumConfigurations}=="1"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{speed}=="12"
ATTRS{busnum}=="1"
ATTRS{devnum}=="2"
ATTRS{devpath}=="1"
ATTRS{version}==" 1.10"
ATTRS{maxchild}=="4"
ATTRS{quirks}=="0x0"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{authorized}=="1"
ATTRS{manufacturer}=="Cypress Semiconductor"
ATTRS{product}=="UniHub(four port)"
ATTRS{serial}=="DEF1105C8184"

looking at parent device '/devices/platform/pxa27x-ohci/usb1':
KERNELS=="usb1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{configuration}==""
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bmAttributes}=="e0"
ATTRS{bMaxPower}=="  0mA"
ATTRS{urbnum}=="37"
ATTRS{idVendor}=="1d6b"
ATTRS{idProduct}=="0001"
ATTRS{bcdDevice}=="0206"
ATTRS{bDeviceClass}=="09"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bNumConfigurations}=="1"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{speed}=="12"
ATTRS{busnum}=="1"
ATTRS{devnum}=="1"
ATTRS{devpath}=="0"
ATTRS{version}==" 1.10"
ATTRS{maxchild}=="3"
ATTRS{quirks}=="0x0"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{authorized}=="1"
ATTRS{manufacturer}=="Linux 2.6.34-rc1-01016-gf11f317-dirty ohci_hcd"
ATTRS{product}=="PXA27x OHCI"
ATTRS{serial}=="pxa27x"
ATTRS{authorized_default}=="1"

looking at parent device '/devices/platform/pxa27x-ohci':
KERNELS=="pxa27x-ohci"
SUBSYSTEMS=="platform"
DRIVERS=="pxa27x-ohci"
ATTRS{modalias}=="platform:pxa27x-ohci"

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

A questo punto direi che è molto facile proseguire, per identificare la mia chiavetta posso infatti usare una parola chiave del dispositivo:

SUBSYSTEM=="block"

e gli attributi di un suo padre (parent) e cioè il vendor ID e il product ID del dispositivo USB che implementa la chiavetta (le parole chiavi dei dispositivi padre si identificano come quelli del dispositivo ma agiungendo una S finale):

ATTRS{idVendor}=="04b4"

ATTRS{idProduct}=="6560"

La regola perciò diventa:

SUBSYSTEM=="block", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="6560", NAME="mykey%n", GROUP="disk"

in questo modo posso essere sicuro che quando accederò il nodo /dev/mykey1 accederò senza dubbio alla mia chiavetta e non ad un altro disposiivo USB, magari con stesso vendor ID e product ID ma che non supporti un disco.

Per provare quanto detto mettiamo la regola in un file nella directory /etc/udev/rules.d come segue:

# cat /etc/udev/rules.d/99-test.rules
SUBSYSTEM=="block", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="6560", NAME="mykey%n", GROUP="disk"

e poi rilanciamo udev (se abbiamo attivato la funzionalita inotify questo non è necessario); poi inseriamo la chiavetta di nuovo ed ecco che abbiamo i due nodi come richiesto:

# ls -l /dev/my_key*
brw-rw---- 1 root disk 8, 0 Apr 19 16:51 /dev/my_key
brw-rw---- 1 root disk 8, 1 Apr 19 16:51 /dev/my_key1

Eseguire programmi

Abbiamo detto che l'assegnazione RUN permette di eseguire programmi su di un dispositivo, questo permette una notevole versatilita nella gestione dei dispositivi.

Una volta assegnato a RUN il nome completo di un programma, questo viene esguito per ogni evento che soddisfa la regola, e lo fa ricevendo i dati di ingresso dall'environment che gli passa udev.

Come esempio vediamo questo semplice programmino che manda nei file di log il suo environment:

# cat /usr/local/bin/dump_env
#!/bin/bash

( echo "--- dumping environment - begin -----------------------------------------------" ; env ; echo "--- dumping environment - end -------------------------------------------------" ) | logger

E' subito chiaro che se lo utilizziamo in una regola del tipo:

SUBSYSTEM=="block", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="6560", RUN="/usr/local/bin/dump_env"

e lo aggiungiamo al file /etc/udev/rules.d/99-test.rules di prima avremo che, ogni volta che si inserisce la nostra chiavetta, questo verrà eseguito ed invierà il suo environment nei file di log. Se si usa il comando tail per tenere d'occhio i file di log, si può vedere che dopo un inserimento si ottiene:

# tail -f /var/log/syslog
Apr 19 17:13:00 debian logger: --- dumping environment - begin -----------------------------------------------
Apr 19 17:13:00 debian logger: PHYSDEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host6/target6:0:0/6:0:0:0
Apr 19 17:13:00 debian logger: ID_MODEL=STORAGE_DEVICE
Apr 19 17:13:00 debian logger: ID_REVISION=1.04
Apr 19 17:13:00 debian logger: DEVTYPE=disk
Apr 19 17:13:00 debian logger: ID_BUS=usb
Apr 19 17:13:00 debian logger: SUBSYSTEM=block
Apr 19 17:13:00 debian logger: ID_SERIAL=Generic_STORAGE_DEVICE_000315435-0:0
Apr 19 17:13:00 debian logger: DEVPATH=/block/sda
Apr 19 17:13:00 debian logger: MINOR=0
Apr 19 17:13:00 debian logger: ACTION=add
Apr 19 17:13:00 debian logger: PWD=/
Apr 19 17:13:00 debian logger: UDEV_LOG=3
Apr 19 17:13:00 debian logger: MAJOR=8
Apr 19 17:13:00 debian logger: DEVLINKS=/dev/block/8:0 /dev/disk/by-id/usb-Generic_STORAGE_DEVICE_000315435-0:0 /dev/disk/by-path/platform-pxa27x-ohci-usb-0:1.3:1.0-scsi-0:0:0:0
Apr 19 17:13:00 debian logger: UDEVD_EVENT=1
Apr 19 17:13:00 debian logger: DEVNAME=/dev/mykey
Apr 19 17:13:00 debian logger: SHLVL=1
Apr 19 17:13:00 debian logger: PHYSDEVDRIVER=sd
Apr 19 17:13:00 debian logger: ID_TYPE=disk
Apr 19 17:13:00 debian logger: ID_INSTANCE=0:0
Apr 19 17:13:00 debian logger: ID_VENDOR=Generic
Apr 19 17:13:00 debian logger: ID_SERIAL_SHORT=000315435
Apr 19 17:13:00 debian logger: PHYSDEVBUS=scsi
Apr 19 17:13:00 debian logger: ID_PATH=platform-pxa27x-ohci-usb-0:1.3:1.0-scsi-0:0:0:0
Apr 19 17:13:00 debian logger: SEQNUM=1904
Apr 19 17:13:00 debian logger: _=/usr/bin/env
Apr 19 17:13:00 debian logger: --- dumping environment - end -------------------------------------------------
Apr 19 17:13:00 debian logger: --- dumping environment - begin -----------------------------------------------
Apr 19 17:13:00 debian logger: PHYSDEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host6/target6:0:0/6:0:0:0
Apr 19 17:13:00 debian logger: ID_MODEL=STORAGE_DEVICE
Apr 19 17:13:00 debian logger: ID_REVISION=1.04
Apr 19 17:13:00 debian logger: DEVTYPE=partition
Apr 19 17:13:00 debian logger: ID_FS_LABEL_SAFE=ZYPAD
Apr 19 17:13:00 debian logger: ID_FS_LABEL=ZYPAD
Apr 19 17:13:00 debian logger: ID_BUS=usb
Apr 19 17:13:00 debian logger: ID_FS_LABEL_ENC=ZYPAD
Apr 19 17:13:00 debian logger: SUBSYSTEM=block
Apr 19 17:13:00 debian logger: ID_SERIAL=Generic_STORAGE_DEVICE_000315435-0:0
Apr 19 17:13:00 debian logger: ID_FS_UUID=34AB-8496
Apr 19 17:13:00 debian logger: DEVPATH=/block/sda/sda1
Apr 19 17:13:00 debian logger: ID_FS_VERSION=FAT16
Apr 19 17:13:00 debian logger: MINOR=1
Apr 19 17:13:00 debian logger: ACTION=add
Apr 19 17:13:00 debian logger: PWD=/
Apr 19 17:13:00 debian logger: UDEV_LOG=3
Apr 19 17:13:00 debian logger: ID_FS_TYPE=vfat
Apr 19 17:13:00 debian logger: MAJOR=8
Apr 19 17:13:00 debian logger: DEVLINKS=/dev/block/8:1 /dev/disk/by-id/usb-Generic_STORAGE_DEVICE_000315435-0:0-part1 /dev/disk/by-path/platform-pxa27x-ohci-usb-0:1.3:1.0-scsi-0:0:0:0-part1 /dev/disk/by-uuid/34AB-8496 /dev/disk/by-label/ZYPAD
Apr 19 17:13:00 debian logger: UDEVD_EVENT=1
Apr 19 17:13:00 debian logger: DEVNAME=/dev/mykey1
Apr 19 17:13:00 debian logger: SHLVL=1
Apr 19 17:13:00 debian logger: ID_FS_USAGE=filesystem
Apr 19 17:13:00 debian logger: PHYSDEVDRIVER=sd
Apr 19 17:13:00 debian logger: ID_TYPE=disk
Apr 19 17:13:00 debian logger: ID_FS_UUID_ENC=34AB-8496
Apr 19 17:13:00 debian logger: ID_INSTANCE=0:0
Apr 19 17:13:00 debian logger: ID_VENDOR=Generic
Apr 19 17:13:00 debian logger: ID_SERIAL_SHORT=000315435
Apr 19 17:13:00 debian logger: PHYSDEVBUS=scsi
Apr 19 17:13:00 debian logger: ID_PATH=platform-pxa27x-ohci-usb-0:1.3:1.0-scsi-0:0:0:0
Apr 19 17:13:00 debian logger: SEQNUM=1905
Apr 19 17:13:00 debian logger: _=/usr/bin/env
Apr 19 17:13:00 debian logger: --- dumping environment - end -------------------------------------------------

da questo output si possono trarre ulteriori informazioni utili ad affinare le regole e/o avere una lista completa delle variabili di environment che il nostro programma si può aspettare.

Monitorare gli eventi

Durante la scrittura delle regole è importante poter verificare quello che udev vede e cosa no, in particolare è comodo poter vedere gli eventi del kernel man mano che questi arrivano, e per farlo si può usare il tool udevadm come segue:

# udevadm monitor --kernel --environment
udevmonitor will print the received events for:
UEVENT the kernel uevent

In questo modo, quando inserisco la mia chiavetta, ho in output:

UEVENT[1271698507.951940] add      /devices/platform/pxa27x-ohci/usb1/1-1/1-1.3 (usb)
ACTION=add
DEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3
SUBSYSTEM=usb
MAJOR=189
MINOR=3
DEVNAME=bus/usb/001/004
DEVTYPE=usb_device
PHYSDEVBUS=usb
DEVICE=/proc/bus/usb/001/004
PRODUCT=781/7100/104
TYPE=0/0/0
BUSNUM=001
DEVNUM=004
SEQNUM=1792

UEVENT[1271698507.995788] add      /devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0 (usb)
ACTION=add
DEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0
SUBSYSTEM=usb
DEVTYPE=usb_interface
PHYSDEVBUS=usb
DEVICE=/proc/bus/usb/001/004
PRODUCT=781/7100/104
TYPE=0/0/0
INTERFACE=8/6/80
MODALIAS=usb:v0781p7100d0104dc00dsc00dp00ic08isc06ip50
SEQNUM=1793

UEVENT[1271698508.011382] add      /class/scsi_host/host1 (scsi_host)
ACTION=add
DEVPATH=/class/scsi_host/host1
SUBSYSTEM=scsi_host
PHYSDEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0
PHYSDEVBUS=usb
PHYSDEVDRIVER=usb-storage
SEQNUM=1794

UEVENT[1271698509.038852] add      /devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1/target1:0:0/1:0:0:0 (scsi)
ACTION=add
DEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1/target1:0:0/1:0:0:0
SUBSYSTEM=scsi
DEVTYPE=scsi_device
PHYSDEVBUS=scsi
MODALIAS=scsi:t-0x00
SEQNUM=1795

UEVENT[1271698509.039264] add      /class/scsi_disk/1:0:0:0 (scsi_disk)
ACTION=add
DEVPATH=/class/scsi_disk/1:0:0:0
SUBSYSTEM=scsi_disk
PHYSDEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1/target1:0:0/1:0:0:0
PHYSDEVBUS=scsi
PHYSDEVDRIVER=sd
SEQNUM=1796

UEVENT[1271698509.039457] add      /class/scsi_device/1:0:0:0 (scsi_device)
ACTION=add
DEVPATH=/class/scsi_device/1:0:0:0
SUBSYSTEM=scsi_device
PHYSDEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1/target1:0:0/1:0:0:0
PHYSDEVBUS=scsi
PHYSDEVDRIVER=sd
SEQNUM=1797

UEVENT[1271698509.344458] change   /devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1/target1:0:0/1:0:0:0 (scsi)
ACTION=change
DEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1/target1:0:0/1:0:0:0
SUBSYSTEM=scsi
SDEV_MEDIA_CHANGE=1
DEVTYPE=scsi_device
DRIVER=sd
PHYSDEVBUS=scsi
PHYSDEVDRIVER=sd
MODALIAS=scsi:t-0x00
SEQNUM=1798

UEVENT[1271698509.390284] add      /block/sda (block)
ACTION=add
DEVPATH=/block/sda
SUBSYSTEM=block
MAJOR=8
MINOR=0
DEVNAME=sda
DEVTYPE=disk
PHYSDEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1/target1:0:0/1:0:0:0
PHYSDEVBUS=scsi
PHYSDEVDRIVER=sd
SEQNUM=1799

UEVENT[1271698509.390736] add      /block/sda/sda1 (block)
ACTION=add
DEVPATH=/block/sda/sda1
SUBSYSTEM=block
MAJOR=8
MINOR=1
DEVNAME=sda1
DEVTYPE=partition
PHYSDEVPATH=/devices/platform/pxa27x-ohci/usb1/1-1/1-1.3/1-1.3:1.0/host1/target1:0:0/1:0:0:0
PHYSDEVBUS=scsi
PHYSDEVDRIVER=sd
SEQNUM=1800

UEVENT[1271698509.390977] add      /class/bdi/8:0 (bdi)
ACTION=add
DEVPATH=/class/bdi/8:0
SUBSYSTEM=bdi
SEQNUM=1801

da cui posso trarre altre utili informazioni per perfezionare le mie regole.

 


Questa dispensa del corso Programmazione Linux è opera di Rodolfo Giometti (Copyright © 2010) ed è rilasciata dall'autore «as is» (così com'è) e distribuita sotto licenza Creative Commons Attribuzione – Condividi allo stesso modo 2.5 Italia.

 
 

In primo piano

Simons Voss: un mondo senza chiavi

Simons Voss: un mondo senza chiavi

Il sistema di gestione e di controllo degli accessi 3060 si presenta come un’alternativa con enormi vantaggi...
Pubblicità mirata dei prodotti

Pubblicità mirata dei prodotti

Hai un prodotto o un servizio da pubblicizzare? Fallo su consulenti-ict.it! Pubblicizzare un prodotto...
Recensioni sul Portale

Recensioni sul Portale

Hai un prodotto hardware/software o un libro riguardante uno dei temi dell'ICT? Vuoi farlo conoscere...

Offerte di lavoro

Visualizza Topic »

Eventi

Non ci sono eventi in programma
Maggio 2012
D L M M G V S
29 30 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 1 2
Giugno 2012
D L M M G V S
27 28 29 30 31 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

Sondaggi

busyCaricamento Sondaggio...