Udev è il sottosistema Linux che fornisce al tuo computer gli eventi dei dispositivi. In parole povere, ciò significa che è il codice che rileva quando hai cose collegate al tuo computer, come una scheda di rete, dischi rigidi esterni (comprese le chiavette USB), mouse, tastiere, joystick e gamepad, unità DVD-ROM, e così via. Questo lo rende un’utilità potenzialmente utile, ed è abbastanza esposto che un utente standard può eseguire manualmente uno script per fare cose come eseguire certi compiti quando un certo disco rigido viene inserito.
Questo articolo vi insegna come creare uno script udev innescato da qualche evento udev, come l’inserimento di una specifica unità thumb. Una volta compreso il processo per lavorare con udev, potete usarlo per fare ogni sorta di cose, come caricare un driver specifico quando viene collegato un gamepad, o eseguire un backup automatico quando collegate la vostra unità di backup.
Uno script di base
Il modo migliore per lavorare con udev è in piccoli pezzi. Non scrivete l’intero script in anticipo, ma piuttosto iniziate con qualcosa che semplicemente confermi che udev inneschi qualche evento personalizzato.
In base all’obiettivo del vostro script, non potete garantire che vedrete mai i risultati di uno script con i vostri occhi, quindi assicuratevi che il vostro script registri che è stato attivato con successo. Il posto usuale per i file di log è nella directory /var, ma questo è per lo più il dominio dell’utente root. Per i test, usate /tmp, che è accessibile agli utenti normali e di solito viene ripulito con un riavvio.
Aprite il vostro editor di testo preferito e inserite questo semplice script:
#!/usr/bin/bash
/usr/bin/date >> /tmp/udev.log
Posizionatelo in /usr/local/bin o in un posto simile nel percorso eseguibile di default. Chiamatelo trigger.sh e, naturalmente, rendetelo eseguibile con chmod +x.
$ sudo mv trigger.sh /usr/local/bin
$ sudo chmod +x /usr/local/bin/trigger.sh
Questo script non ha nulla a che fare con udev. Quando viene eseguito, lo script mette un timestamp nel file /tmp/udev.log. Testate voi stessi lo script:
$ /usr/local/bin/trigger.sh
$ cat /tmp/udev.log
Tue Oct 31 01:05:28 NZDT 2035
Il prossimo passo è far sì che udev attivi lo script.
Identificazione del dispositivo
Per far sì che il vostro script sia attivato da un evento del dispositivo, udev deve sapere in quali condizioni dovrebbe chiamare lo script. Nella vita reale, potete identificare una chiavetta USB dal suo colore, dal produttore e dal fatto che l’avete appena inserita nel vostro computer. Il vostro computer, tuttavia, ha bisogno di un diverso insieme di criteri.
Udev identifica i dispositivi in base ai numeri di serie, ai produttori e anche ai numeri ID del venditore e ID del prodotto. Dato che questo è l’inizio della vita del tuo script udev, sii il più ampio, non specifico e onnicomprensivo possibile. In altre parole, volete prima catturare quasi ogni evento udev valido per innescare il vostro script.
Con il comando udevadm monitor, potete entrare in udev in tempo reale e vedere cosa vede quando collegate diversi dispositivi. Diventa root e prova.
$ su
# udevadm monitor
La funzione monitor stampa gli eventi ricevuti per:
- UDEV: l’evento che udev invia dopo l’elaborazione delle regole
- KERNEL: il kernel uevent
Con udevadm monitor in esecuzione, inserisci una chiavetta USB e guarda come tutti i tipi di informazioni vengono riversati sul tuo schermo. Notate che il tipo di evento è un evento ADD. Questo è un buon modo per identificare il tipo di evento che volete.
Il comando udevadm monitor fornisce molte buone informazioni, ma potete vederle con una formattazione più carina con il comando udevadm info, assumendo che sappiate dove si trova attualmente la vostra chiavetta nell’albero /dev. In caso contrario, scollegate e ricollegate la vostra chiavetta, poi date immediatamente questo comando:
$ su -c 'dmesg | tail | fgrep -i sd*'
Se il comando restituisce sdb: sdb1, per esempio, sapete che il kernel ha assegnato alla vostra chiavetta l’etichetta sdb.
In alternativa, potete usare il comando lsblk per vedere tutte le unità collegate al vostro sistema, incluse le loro dimensioni e partizioni.
Ora che avete stabilito dove si trova la vostra unità nel filesystem, potete vedere le informazioni di udev su quel dispositivo con questo comando:
# udevadm info -a -n /dev/sdb | less
Ci sono molte informazioni. Concentratevi sul primo blocco di informazioni per ora.
Il vostro compito è quello di scegliere le parti del rapporto di udev su un dispositivo che sono più uniche per quel dispositivo, poi dite a udev di attivare il vostro script quando questi attributi unici vengono rilevati.
Il processo informativo di udevadm riporta su un dispositivo (specificato dal percorso del dispositivo), poi “cammina” su per la catena dei dispositivi genitori. Per ogni dispositivo trovato, stampa tutti i possibili attributi usando un formato chiave-valore. È possibile comporre una regola per corrispondere in base agli attributi di un dispositivo più gli attributi di un singolo dispositivo padre.
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"
Una regola udev deve contenere un attributo di un singolo dispositivo padre.
Gli attributi padre sono cose che descrivono un dispositivo dal livello più elementare, come ad esempio è qualcosa che è stato inserito in una porta fisica o è qualcosa con una dimensione o questo è un dispositivo rimovibile.
Siccome l’etichetta KERNEL di sdb può cambiare a seconda di quante altre unità sono state inserite prima di inserire quella chiavetta, questo non è l’attributo padre ottimale per una regola udev. Tuttavia, funziona per una prova di concetto, quindi potreste usarlo. Un candidato ancora migliore è l’attributo SUBSYSTEM, che identifica che questo è un dispositivo di sistema “a blocchi” (che è il motivo per cui il comando lsblk elenca il dispositivo).
Apri un file chiamato 80-local.rules in /etc/udev/rules.d e inserite questo codice:
SUBSYSTEM=="block", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"
Salvate il file, scollegate la vostra chiavetta di prova e riavviate.
Aspettate, riavviare su una macchina Linux?
Teoricamente, potete semplicemente lanciare udevadm control –reload, che dovrebbe caricare tutte le regole, ma a questo punto del gioco, è meglio eliminare tutte le variabili. Udev è già abbastanza complesso, e non volete stare a letto tutta la notte a chiedervi se quella regola non ha funzionato a causa di un errore di sintassi o se avreste dovuto semplicemente riavviare. Quindi riavviate indipendentemente da ciò che vi dice il vostro orgoglio POSIX.
Quando il vostro sistema è di nuovo online, passate a una console di testo (con Ctl+Alt+F3 o simili) e inserite la vostra chiavetta. Se state eseguendo un kernel recente, probabilmente vedrete un sacco di output nella vostra console quando inserite la chiavetta. Se vedete un messaggio di errore del tipo Could not execute /usr/local/bin/trigger.sh, probabilmente avete dimenticato di rendere lo script eseguibile. Altrimenti, si spera che tutto ciò che si vede è che un dispositivo è stato inserito, ha ottenuto un qualche tipo di assegnazione del dispositivo del kernel, e così via.
Ora, il momento della verità:
$ cat /tmp/udev.log
Tue Oct 31 01:35:28 NZDT 2035
Se vedete una data e un’ora molto recenti riportate da /tmp/udev.log, udev ha attivato con successo il vostro script.
Raffinare la regola in qualcosa di utile
Il problema con questa regola è che è molto generica. Collegare un mouse, una chiavetta, o la chiavetta di qualcun altro attiverà indiscriminatamente il vostro script. Ora è il momento di iniziare a concentrarsi sull’esatta chiavetta che vuoi far scattare il tuo script.
Un modo per farlo è con l’ID del fornitore e l’ID del prodotto. Per ottenere questi numeri, potete usare il comando 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
In questo esempio, lo 03f0:3307 prima di TyCoon Corp. denota gli attributi idVendor e idProduct. Puoi anche vedere questi numeri nell’output di udevadm info -a -n /dev/sdb | grep vendor, ma trovo che l’output di lsusb sia un po’ più facile da vedere.
Ora puoi includere questi attributi nella tua regola.
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/thumb.sh"
Testate questo (sì, dovreste ancora riavviare, solo per essere sicuri di ottenere reazioni fresche da udev), e dovrebbe funzionare come prima, solo che ora se inserite, per esempio, una chiavetta prodotta da una società diversa (quindi con un idVendor diverso) o un mouse o una stampante, lo script non verrà attivato.
Continuate ad aggiungere nuovi attributi per concentrarvi ulteriormente su quell’unica chiavetta che volete far partire lo script. Usando udevadm info -a -n /dev/sdb, potete scoprire cose come il nome del venditore, a volte un numero di serie, o il nome del prodotto, e così via.
Per la vostra sanità mentale, assicuratevi di aggiungere solo un nuovo attributo alla volta. La maggior parte degli errori che ho fatto (e che ho visto fare da altre persone online) è di buttare un mucchio di attributi nella loro regola udev e chiedersi perché la cosa non funziona più. Testare gli attributi uno per uno è il modo più sicuro per assicurarsi che udev possa identificare il vostro dispositivo con successo.
Sicurezza
Questo porta alle preoccupazioni sulla sicurezza di scrivere regole udev per fare automaticamente qualcosa quando un’unità viene inserita. Sulle mie macchine, non ho nemmeno l’auto-mount attivato, eppure questo articolo propone script e regole che eseguono comandi semplicemente avendo qualcosa collegato.
Due cose da tenere a mente qui.
- Focalizzate le vostre regole udev una volta che le avete in funzione in modo che attivino gli script solo quando lo volete veramente. Eseguire uno script che copia ciecamente i dati da o verso il tuo computer è una cattiva idea nel caso in cui chiunque abbia la stessa marca di thumb drive lo inserisca nel tuo box.
- Non scrivere le tue regole e script udev e dimenticartene. Io so quali computer hanno le mie regole udev su di essi, e quelle scatole sono molto spesso i miei computer personali, non quelli che porto in giro per le conferenze o che ho nel mio ufficio al lavoro. Più un computer è “sociale”, meno è probabile che abbia una regola udev su di esso che potrebbe potenzialmente portare i miei dati a finire sul dispositivo di qualcun altro o i dati o il malware di qualcun altro sul mio dispositivo.
In altre parole, come per gran parte del potere fornito da un sistema GNU, è vostro compito essere consapevoli di come lo state esercitando. Se ne abusate o non lo trattate con rispetto, potrebbe andare terribilmente male.
Udev nel mondo reale
Ora che potete confermare che il vostro script è attivato da udev, potete rivolgere la vostra attenzione alla funzione dello script. In questo momento, è inutile, non fa altro che registrare il fatto che è stato eseguito.
Io uso udev per innescare i backup automatici dei miei thumb drive. L’idea è che le copie master dei miei documenti attivi sono sulla mia chiavetta (dato che va ovunque io vada e potrebbe essere lavorata in qualsiasi momento), e quei documenti master vengono salvati sul mio computer ogni volta che inserisco la chiavetta in quella macchina. In altre parole, il mio computer è l’unità di backup e i miei dati di produzione sono mobili. Il codice sorgente è disponibile, quindi sentitevi liberi di guardare il codice di attachup per ulteriori esempi di vincolare i vostri test udev.
Siccome questo è quello per cui uso di più udev, è l’esempio che userò qui, ma udev può prendere molte altre cose, come i gamepad (questo è utile su sistemi che non sono impostati per caricare il modulo xboxdrv quando un gamepad è collegato) e telecamere e microfoni (utile per impostare gli ingressi quando un microfono specifico è collegato), quindi rendetevi conto che è buono per molto di più di questo esempio.
Una versione semplice del mio sistema di backup è un processo a due comandi:
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", SYMLINK+="safety%n"
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"
La prima linea rileva la mia thumb drive con gli attributi già discussi, poi le assegna un link simbolico all’interno dell’albero dei dispositivi. Il link simbolico che assegna è safety%n. %n è una macro di udev che si risolve in qualsiasi numero che il kernel dà al dispositivo, come sdb1, sdb2, sdb3, e così via. Quindi %n sarebbe l’1 o il 2 o il 3.
Questo crea un symlink nell’albero dev, quindi non interferisce con il normale processo di inserimento di un dispositivo. Questo significa che se usi un ambiente desktop a cui piace montare automaticamente i dispositivi, non gli causerai problemi.
La seconda linea esegue lo script.
Il mio script di backup assomiglia a questo:
#!/usr/bin/bash
mount /dev/safety1 /mnt/hd
sleep 2
rsync -az /mnt/hd/ /home/seth/backups/ && umount /dev/safety1
Lo script usa il collegamento simbolico, che evita la possibilità che udev nomini l’unità con un nome inaspettato (per esempio, se ho già una chiavetta chiamata DISK inserita nel mio computer, e inserisco un’altra chiavetta chiamata DISK, la seconda sarà etichettata DISK_, il che farebbe saltare il mio script). Monta safety1 (la prima partizione del disco) nel punto di montaggio che preferisco, /mnt/hd.
Una volta montato in sicurezza, usa rsync per fare il backup del disco nella mia cartella di backup (il mio script attuale usa rdiff-backup, e il vostro può usare qualsiasi soluzione di backup automatico che preferite).
Udev è il vostro dev
Udev è un sistema molto flessibile e vi permette di definire regole e funzioni in modi che pochi altri sistemi osano fornire agli utenti. Imparalo e usalo, e goditi la potenza di POSIX.
Questo articolo si basa sul contenuto del Manuale Slackermedia, che è concesso in licenza sotto la GNU Free Documentation License 1.3.
.