USB Mass Storage device con udev e Kernel 2.6.x

Introduzione

Con questo Howto ho la presunzione di voler essere d'aiuto a chi desidera automatizzare il sistema di riconoscimento e di mounting di device USB quali pen drive, Hard Disk, Card Reader etc.

Premessa

Ultimamente mi sono ritrovato a possedere sempre piu' dispositivi USB e ad avere la necessita' di automatizzare la gestione degli stessi. Piu' esattamente possego un Pen Drive, un HD esterno, una fotocamera digitale, un card reader e un lettore MP3. Tutti questi dispositivi funzionano benissimo sotto Linux essendo gestiti perfettamente come USB Mass Storage devices. La cosa piu' snervante e' che bisogna sempre andare a vedere dove il sistema crea i block device per poter montare correttamente il dispositivo. Ad esempio la prima partizione del mio HD viene riconosciuta come /dev/sda1, se pero' lo monto insieme al Pen Drive allora sara' riconosciuto come /dev/sdb1 e cosi' via. Questo mi impedisce di poter creare delle entry fisse nel mio fstab. Dopo un po' di ricerche ecco che finalmente trovo la soluzione con udev.

Requisiti

  1. Un PC (eh eh) con Linux (preferibilmente Slckware).
  2. Kernel della serie 2.6.x (io uso la 2.6.6) scaricabile da www.kernel.org con supporto sysfs
  3. Hotplug scaricabile dalla current di Slackware
  4. udev scaricabile da www.kernel.org/pub/linux/utils/kernel/hotplug/

Preparazione

Compiliamo la ns. Kernel come al solito ricordandoci di settare in General setup :

Support for hot-pluggable devices

Assicuriamoci che sysfs sia montato. Per fare cio' aggiungiamo una linea al nostro fstab del tipo : none /sys sysfs defaults diamo un bel:

mount -a

et voila'.

Installazione

Una volta scaricati i sorgenti di udev scompattiamo il pacchetto con :

tar -xzf udev-XXX.tar.gz (dove XXX e' la versione di udev che avete scaricato).

Andiamo nella directory appena creata con:

cd udev-XXX

e diamo un bel:

make

se non avvengono catastrofi nella compilazione possiamo tranquillamente installare il tutto con:

make install

A questo punto dobbiamo copiare lo script di avvio di udev nella nostra /etc/rc.d. Lo script opportuno si trova nella directory extra dei sorgenti e si chiama start_udev lo copiamo con :

cp extra/start_udev /etc/rc.d

Bisogna ora fare in modo che lo script sia eseguito all'avvio, modifichiamo il file rc.local aggiungendo la linea /etc/rc.d/start_udev.

Configurazione

Passiamo dunque alla configurazione di udev. Nella directory /etc/udev troviamo il file udev.conf apriamolo con il ns. editor favorito e cerchiamo la linea:

# udev_rules - The name and location of the udev rules file
udev_rules="/etc/udev/rules.d/"

Modifichiamola con :

udev_rules="/etc/udev/udev.rules

Questo dira' ad udev dove trovare il file di definizione delle regole (ARRGH non sono riuscito a tradurlo meglio !)

Ora dobbiamo scrivere le regole per l'identificazione delle ns. devices USB. Per fare questo dobbiamo conoscere qualcosa dei nostri dispositivi, piu' precisamente il “vendor” e il “model” che altro non sono che il “venditore” e il “modello”. Per avere queste informazioni possiamo avvalerci dell' utility udevinfo procedendo come segue: attacchiamo il dispositivo che vogliamo identificare e digitiamo :

dmesg

qu dovremmo vedere alla fine un messaggio del tipo :

scsi1 : SCSI emulation for USB Mass Storage devices
Vendor: WDC WD60 Model: 0AB-60CBA0 Rev: 03.0
Type: Direct-Access ANSI SCSI revision: 02
SCSI device sda: 117231409 512-byte hdwr sectors (60022 MB)
sda: assuming drive cache: write through
sda: sda1 sda2
Attached scsi disk sda at scsi1, channel 0, id 0, lun 0
Attached scsi generic sg0 at scsi1, channel 0, id 0, lun 0, type 0
USB Mass Storage device found at 2

(questo e' l'output di dmesg dopo che ho attaccato il mio HD esterno). Sappiamo quindi che il dispositivo e' attacato su “/dev/sda epossiamo con udevinfo interrogare il path adeguato:

udevinfo -a -p /sys/block/sda

l'output sara' pressapoco questo:

udevinfo starts with the device the node belongs to and then walks up the
device chain, to print for every device found, all possibly useful attributes
in the udev key format.
Only attributes within one device section may be used together in one rule,
to match the device for which the node will be created.
looking at class device '/sys/block/sda':

SYSFS{dev}="8:0"

SYSFS{range}="16"

SYSFS{size}="117231409"

SYSFS{stat}=" 68 7 75 273 0 0 0 0 0 273 273"


follow the class device's "device"

looking at the device chain at '/sys/devices/pci0000:00/0000:00:0b.0/usb2/2-1/2-1:1.0/host1/1:0:0:0':

BUS="scsi"

ID="1:0:0:0"

SYSFS{detach_state}="0"

SYSFS{device_blocked}="0"

SYSFS{max_sectors}="240"

SYSFS{model}="0AB-60CBA0 "

SYSFS{queue_depth}="1"

SYSFS{rev}="03.0"

SYSFS{scsi_level}="3"

SYSFS{state}="running"

SYSFS{type}="0"

SYSFS{vendor}="WDC WD60"

Guardiamo nella sezione che contiene il BUS scsi . Qui abbiamo le informazioni che ci interessano per scrivere il nostro udev.rules, riapriamo il ns editor e aggiungiamo questa linea a udev.rules:

BUS="scsi", SYSFS{vendor}="WDC WD60",SYSFS{model}="0AB-60CBA0", NAME="exthd%n"

Facciamo attenzione ad eventuali spazi nei nomi !! Abbiamo cosi' detto ad udev che quando questa device viene attaccata deve creare un node che si chiama “exthd%n” dove %n e' il numero di partizione che verra' rilevata. La prossima volta che attaccheremo il dispositivo compariranno (per miracolo ?) nella directory /udev due block devices che si chiamano exthd1 e exthd2. Possiamo ora usare queste block devices per montare il nostro disco al posto di /dev/sda1 e /dev/sda2 A tal proposito scriviamo nel nostro fstab le seguenti linee :

/udev/exthd1 /mnt/extern/FAT32 vfat noauto,users,gid=100,umask=3 0 0
/udev/exthd2 /mnt/extern/Linux auto noauto,users

(Nel mio caso la prima partizione dell'HD e' Fat32 e la seonda e' ext3) Arrivati fin qui non ci resta che montare il nostro dispositivo con:

mount /udev/exthd1

OHHHH funziona ! Ma se siamo veramente pigri e non vogliamo neanche dare il mount ? Ecco che udev puo' aiutarci anche nell'automount.

AUTOMOUNT

Durante l'installazione di udev e' stata creata una directory /etc/dev.d/. E' li' che andremo a “smanettare” per poter far funzionare il nostro automount. Udev per ogni device “creata” si va a cercare in /etc/dev.d/ una directory che abbia lo stesso nome della device. Nel nostro esempio dopo aver attaccato l'HD esterno si a a cercare una directory /etc/dev.d/exthd1 e una volta trovata esegue tutto cio' che termina con estensione “.dev” Non ci resta quindi che crearci una directory con : mkdir /etc/dev.d/exthd1 e all'interno di questa creare uno script pressappoco cosi' :

#!/bin/bash
if [ "$ACTION" == "add" ] ; then
logger -t dev.d "Mounting external HD"
/bin/mount /mnt/extern/FAT32
fi
if [ "$ACTION" == "remove" ] ; then
logger -t dev.d "Unmounting external HD"
/bin/umount /mnt/extern/FAT32
fi

Udev usa le stesse regole di Hotplug per quel che riguarda ACTION ( fate riferimento al man di Hotplug) Questo script verra' eseguito, ogni volta che la device verra' attaccata o staccata dal sistema. L'esecuzione avviene come utente root per cui facciamo in modo che nel fstab i permessi di accesso siano settati secondo le nostre esigenze.

Buon divertimento !!!

Credits

Questo Howto e' stato scritto scopiazzando varie cose che ho trovato sulla rete e che mi sono state utili a capire il funzionamento di udev. Udev e' fornito di una piccola documentazione che si trova nella directory dei sorgenti, non molto in verita', ma si puo' benissimo integrare con quel meraviglioso strumento che e' Internet. Attenzione udev non e' solo questo, in futuro rimpiazzera' del tutto (forse) il devfs tradizionale. Ringrazio tutti gli iscritti a Slacky.it che mi hanno aiutato dopo anni di Distro porfessionali a ributtarmi nell'avventura Slackware.

A mio figlio Jan

Sal Paradiso Giugno 2004