Escribiendo reglas UDEV para distinguir discos externos

Últimamente tengo que pasar a menudo información entre distintos discos USB externos. Las posibles formas de conectarlos generan tantas combinaciones distintas que resulta intratable usar los identificadores convencionales para montar las unidades (sda1,sdc4,...). Además, varios discos están particionados de forma idéntica por lo que en caso de estar conectados a la vez resulta difícil saber cual es cual, salvo que siempre se enchufen en el mismo orden.

La solución lógica para que un mismo disco siempre tenga un identificador único, independientemente del número de discos que se hayan conectado y del orden en el que se haya hecho es usar reglas UDEV.

A continuación explico una forma rápida para localizar los valores concretos de un disco y así poder escribir una regla que lo identifique.

Para una guía completa sobre cómo escribir reglas UDEV, consultar http://www.reactivated.net/writing_udev_rules.html

Lo primero que hay que saber es cómo nombra el kernel al disco. Si tu sistema no carga automáticamente el módulo usb-storage al conectar el disco, hazlo manualmente:

# modprobe -v usb-storage

Tras conectarlo, ejecuta:

# dmesg | tail
scsi 3:0:0:0: Direct-Access WDC WD74 0GD-50FLC0 8F33 PQ: 0 ANSI: 2 CCS
sd 3:0:0:0: [sdb] 145226112 512-byte hardware sectors (74356 MB)
sd 3:0:0:0: [sdb] Write Protect is off

...

Entre corchetes vemos el nombre de dispositivo que le ha dado el kernel al disco, en este caso sdb.

Normalmente con el identificador del fabricante del disco y el modelo exacto suele ser suficiente para crear una regla UDEV que lo identifique. Estos dos datos los podemos sacar rápidamente con los siguientes comandos:

# cat /sys/block/sdb/device/model
0GD-50FLC0

# cat /sys/block/sdb/device/vendor
WDC WD74

Pero si por ejemplo tenemos dos discos idénticos necesitaremos más datos para distinguirlos, los podemos obtener con el comando

# udevinfo -a -p /sys/block/sdb
...
looking at device '/block/sdb':
KERNEL=="sdb"
SUBSYSTEM=="block"
DRIVER==""
ATTR{capability}=="12"
ATTR{stat}==" 198 770 2464 997 2 0 16 2 0 655 999"
ATTR{size}=="145226112"
ATTR{removable}=="0"
ATTR{range}=="16"
ATTR{dev}=="8:16"

looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb7/7-4/7-4:1.0/host3/target3:0:0/3:0:0:0':
KERNELS=="3:0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{modalias}=="scsi:t-0x00"
ATTRS{ioerr_cnt}=="0x0"
ATTRS{iodone_cnt}=="0xcf"
ATTRS{iorequest_cnt}=="0xcf"
ATTRS{iocounterbits}=="32"
ATTRS{timeout}=="60"
ATTRS{state}=="running"
ATTRS{rev}=="8F33"
ATTRS{model}=="0GD-50FLC0"
ATTRS{vendor}=="WDC WD74"
ATTRS{scsi_level}=="3"
ATTRS{type}=="0"
ATTRS{queue_type}=="none"
ATTRS{queue_depth}=="1"
ATTRS{device_blocked}=="0"
ATTRS{max_sectors}=="240"
...

Como se aprecia, la información se muestra en distintos bloques. Podemos usar cualquiera de los datos de un bloque para crear una regla, pero sin mezclar datos de distintos bloques.

Por ejemplo, para este disco, una regla que además del dispositivo estándar, cree un enlace simbólico, tendría el siguiente aspecto:

SUBSYSTEMS=="scsi", ATTRS{vendor}=="WDC WD74", ATTRS{model}=="0GD-50FLC0*", NAME="%k", SYMLINK+="seeder%n"

Con esta regla, cada vez que se conecte el disco podrá ser accedido siempre a través de /dev/seeder. Como hemos añadido %n al final de la regla, en caso de que el disco tenga varias particiones, podrán ser accedidas en /dev/seeder1,/dev/seeder2,...

Otro ejemplo para otro disco duro

# dmesg | tail
scsi 4:0:0:0: Direct-Access IC25N030 ATCS04-0 CA3O PQ: 0 ANSI: 0
sd 4:0:0:0: [sdd] 58605120 512-byte hardware sectors (30006 MB)
sd 4:0:0:0: [sdd] Write Protect is off
sd 4:0:0:0: [sdd] Mode Sense: 03 00 00 00

....

Por tanto, este nuevo disco es sdd. Para mostrar su infromación

# udevinfo -a -p /sys/block/sdd
...
ATTRS{model}=="ATCS04-0"
ATTRS{vendor}=="IC25N030"
....

En este caso una posible regla sería

SUBSYSTEMS=="scsi", ATTRS{vendor}=="IC25N030", ATTRS{model}=="ATCS04-0*", NAME="%k", SYMLINK+="leecher%n"

Las reglas las podemos guardar en el archivo /etc/udev/rules.d/10-discosUSB.rules