Crear reglas de udev
La receta rápida:
Para saber qué dispositivo se asigna por ejemplo a nuestro pendrive, lo conectamos y hacemos:gisajo@gisa:~$ dmesg | tail
sd 8:0:0:0: [sdd] Mode Sense: 03 00 00 00
sd 8:0:0:0: [sdd] Assuming drive cache: write through
sd 8:0:0:0: [sdd] 4014078 512-byte hardware sectors (2055 MB)
sd 8:0:0:0: [sdd] Write Protect is off
sd 8:0:0:0: [sdd] Mode Sense: 03 00 00 00
sd 8:0:0:0: [sdd] Assuming drive cache: write through
sdd: sdd1
sd 8:0:0:0: [sdd] Attached SCSI removable disk
sd 8:0:0:0: Attached scsi generic sg3 type 0
usb-storage: device scan complete
Ya vemos que lo ha puesto como sdd. Ahora vamos a averiguar el vendedor y el modelo:
gisajo@gisa:~$ udevinfo -a -p /sys/block/sdd | grep -e vendor -e model
ATTRS{vendor}=="JetFlash"
ATTRS{model}=="TS2GJF180 "
ATTRS{vendor}=="0x10de"
ATTRS{subsystem_vendor}=="0x1043"
Creamos un archivo /etc/udev/rules.d/010_gure_katxarroak.rules y le metemos una línea tal que así:
Nótese que udevinfo ha devuelto dos atributos vendor. Cada uno de ellos se refiere a un dispositivo "padre" diferente, o mejor dicho, a un "padre" y a un "abuelo". Esto de padres y abuelos se refiere a los dispositivos del que cuelga el dispositivo que usa nuestro pendrive. Estos podrían ser la controladora sata y el bus pci, por ejemplo. El comando udevinfo nos saca los atributos agrupados por dispositivos, con la sección correspondiente a cada dispositivo comenzando con una línea "looking at device" o "looking at parent device".
En nuestra regla puede haber atributos pertenecientes al "hijo" y a uno de los ancestros. Cualquiera de los "ancestros", pero sólo uno. Si la regla contiene atributos correspondientes a dos o más ancestros, fallará.
La explicación larga.
Udev
Este documento es una modificación del la guia completa original, disponible en http://www.reactivated.net/writing_udev_rules.html.
Los sistemas GNU/Linux tienen una carpeta /dev. Los archivos dentro de esta carpeta son "nodos" que permiten comunicarse al sistema con el aparato en cuestión. Por ejemplo, típicamente nuestro disco duro estará representado por el nodo /dev/hda (si es un disco IDE) o el nodo /dev/sda (si es un disco SCSI, SATA, o una memoria USB). De modo que para acceder al disco duro, el sistema accede al archivo /dev/hda (o el que corresponda, siempre dentro de la carpeta /dev).
Antes del kernel 2.6, la carpeta /dev estaba siempre llena con todos los nodos correspondientes a cualquier tipo de aparato que se pudiera conectar al ordenador, independientemente de que ese aparato estuviera realmente conectado al ordenador o no. Por tanto, la carpeta /dev estaba siempre llena de archivos, la mayoría de los cuales no se usaban nunca.
udev, presente en kernels 2.6, es un mecanismo para evitar esto. Su finalidad es crear al vuelo los nodos necesarios para acceder al hardware que realmente está en el sistema. Para lograrlo, a) busca en la carpeta /sys la información correspondiente al dispositivo, y b) le aplica una serie de reglas definidas por el root hasta que encuentra una que coincide. Si encuentra una coincidencia, hace lo que dice la regla. Si no encuentra ninguna, crea el nodo con el nombre que le da el kernel, y listos. De este modo, sólo se crean los nodos que realmente hacen falta.
Los sistemas GNU/Linux se instalan con las reglas de udev suficientes para manejar la mayoría de los casos. Estas reglas se han ido mejorando con el tiempo, pero aún hay casos en los que resulta conveniente añadir o modificar reglas.
Un caso extremo que solía ocurrir era éste: una persona arranca su ordenador con un pendrive usb conectado. Este pendrive era reconocido por el kernel antes que el disco duro del ordenador. Por tanto lo llamaba /dev/sda en lugar del disco interno del ordenador, que pasaba a ser /dev/sdb. Como resultado, el ordenador no podía arrancar, ya que el nuevo /dev/sda no contiene el sistema operativo, sino datos personales.
Esto ya no pasa, pero aún hay casos en los que resulta conveniente modificar o añadir reglas udev. Por ejemplo, si tenemos dispositivos externos usb y queremos que aparezcan siempre en el mismo sitio; podemos hacer que el pendrive se monte siempre en una carpeta "pendrive" y la cámara en una carpeta "cámara". A esto se le llama "persistent naming".
Persistent naming
udev proporciona persistent naming para algunos tipos de dispositivo sin necesidad de hacer nada El caso más evidente es el que nos ocupa, dispositivos de almacenamiento. udev crea enlaces simbólicos en la carpeta /dev/disk que apuntan a los nodos de /dev. De este modo, podemos usar estos enlaces simbólicos en vez de los nodos. Esto se hace evidente por ejemplo en ubuntu, cuyo archivo /etc/fstab usa los enlaces simbólicos bajo /dev/disk/by-uuid en lugar del típico /dev/sda1, etc.
Si conectamos un pendrive, veremos que en las diferentes carpetas bajo /dev/disk aparecen enlaces simbólicos al nuevo nodo, por ejemplo "usb-JetFlash_TS2GJF180_YLDITMRV-0:0". Al quitar el pendrive, el enlace y el nodo desaparecen, pero si lo volvemos a montar, el enlace simbóloco vuelve a aparecer exactamente igual, aunque el nodo al que apunta haya cambiado.
El inconveniente de estos enlaces es que el nombre resulta siempre muy largo: llamar a un dispositivo /dev/disk/by-uuid/0ff35f9a-f15a-4e97-a769-e64150bdd915 es mucho menos práctico que llamarlo /dev/camara.
Escribir reglas
Archivos de reglas
Las reglas de udev se guardan como archivos de texto en la carpeta /etc/udev/rules.d, y deben acabar siempre con la extensión .rules. Las reglas por defecto se guardan en udev.rules. Es mejor que no toquemos este archivo; en su lugar crearemos otro archivo y meteremos nuestras reglas en él.
Los archivos de reglas son analizados en busca de reglas que sean de aplicación al hardware del sistema. Esto se hace por orden léxico. Es decir, un archivo llamado gurekatxarroak.rules será analizado antes que el archivo udev.rules. El archivo 01.rules será analizado antes que el archivo 02.rules, etc. El oden en que se examinan las reglas es importante en algunos casos. Por regla general, querremos que nuestras reglas sean analizadas antes que las reglas por defecto, de modo que podemos crear un archivo /etc/udev/rules.d/010gure_katxarroak.rules y meter nuestras reglas en él.
Las líneas que comienzan con un # son comentarios y el sistema las ignora. También ignora las líneas en blanco. Cualquier otra línea es una regla. Las reglas deben ocupar una sola línea.
Al encontrar una regla que coincide con el hardware presente, udev hace lo que indica esa regla y sigue buscando otras reglas que puedan ser de aplicación. Esto quiere decir que podemos crear múltiples reglas para el mismo dispositivo, si queremos. Esto es lo que permite que se creen enlaces simbólicos tanto en /dev/disk/by-id como en /dev/disk/by-uuid, etc, todos apuntando al mismo dispositivo. Podemos usar cualquiera de esos caminos para acceder al dispositivo.
Sintaxis de las reglas
Las reglas se componen de una serie de pares clave/valor, separados por comas. Las claves pueden ser de coincidencia y de asignación. Las distinguimos porque las de coincidencia llevan dos signos igual (==) mientras que las de asignación llevan un solo signo igual (=). Cada regla debe tener al menos una coincidencia y una asignación. Cuando los valores de todas las claves de coincidencia coinciden con un dispositivo, se invocan todas las acciones especificadas por las claves de asignación.
Un ejemplo de regla bien sencillo:
KERNEL=="hdb", NAME="disco_extra"
Lo que la regla dice es que cuando el kernel encuentre un dispositivo al que coresponda "hdb", le asigne un nombre "disco_extra", en vez del "hdb" que el kernel le iba a dar por defecto.
Recuerda, cada regla debe estar en su propia línea.
Reglas básicas
udev proporciona varias claves de coincidencia. Las más usadas son:
- - KERNEL - compara con el nombre que el kernel da al dispositivo, por ejemplo, sda.
- - SUBSYSTEM - compara con el subsistema en el que integra el dispositivo, por ejemplo, usb o ata.
- - DRIVER - compara con el nombre del driver que gobierna el dispositivo, por ejemplo, usb-storage
Hay otras claves de coincidencia que se verán más adelante.
Las claves de asignación más usadas son:
- NAME - el nombre que se usará para crear el nodo. Por ejemplo, si usamos NAME=="ppkk", udev creará un nodo llamado /dev/ppkk
- SYMLINK - permite especificar el enlace simbólico que se creará.
También en este caso, existen más claves de asignación que estas dos. Más adelante se verán algunas. La lista completa está en la página man de udev.
En el caso típico, nuestras reglas no tendrán ninguna asignación NAME. De este modo el nodo se crea siempre con el nombre del kernel por defecto. Lo que nos interesa es crear una asignación SYMLINK="pendrive" o SYMLINK="camara". Por ejemplo:
KERNEL=="sdb", SYMLINK="pendrive"
En realidad, esta regla no es muy útil, ya que eso sólo nos deja acceder al pendrive en sí. Cosa que puede ser útil para particionarlo pero para nada más. Lo que queremos es acceder a las particiones que pueda tener el pendrive/disco. Lo conseguiremos con una regla como ésta:
KERNEL=="sdb", SYMLINK+="pendrive%n"
Nótese el símbolo + delante del igual, indicando que lo que sigue es una lista de enlaces, no uno solo. Nótese también el "%n" añadido después de "pendrive". Esta regla creará una serie de enlaces simbólicos sustituyendo automáticamente "%n" por el número de partición. Por tanto, si el pendrive tenía tres particiones, aparecerán cuatro enlaces simbólicos: /dev/pendrive, /dev/pendrive1, /dev/pendrive2 y /dev/pendrive3, que apuntarán respecyivamente a /dev/sdb, /dev/sdb1, /dev/sdb2 y /dev/sdb3
Usar la información de la carpeta /sys
Las claves de coincidencia que hemos visto hasta ahora (KERNEL, SUBSYSTEM y DRIVER) se quedan un poco cortas. Para tener un control más fino, necesitamos claves que permitan identificar dispositivos usando códigos de vendedor, número de serie, etc. De esta manera, incluso si tenemos dos discos exactamente iguales podremos distinguir uno del otro.
La mayoría de los drivers exportan esta información usando sysfs, lo que significa que podemos acceder a ella en algún lugar dentro de la carpeta /sys. La clave de coincidencia que sirve para comparar contra cualquiera de los atributos presentes en /sys es ATTR{atributo}. Por ejemplo, ATTR{size}=="398297088" coincidirá con un dispositivo de ese tamaño. Para saber cuál es el size de nuestro disco duro, hacemos:
gisajo@gisa:~$ udevinfo -a -p /sys/block/sda | grep size
ATTR{size}=="398297088"
Y con esto ya sabemos qué tamaño indicar en la regla, que podría quedar como:
KERNEL=="sda", ATTR{size}=="398297088", SYMLINK+="disco_duro%n"
Esto funciona muy bien con el atribito size, porque en efecto es un atributo del dico duro. Pero si intentamos hacer lo mismo con otros atributos que parecen más evidentes, como ATTR{vendor} y ATTR{model}, que nos permitirían usar el nombre del fabricante y el modelo del disco en nuestra regla, fallaría. Esto se debe a que la jerarquía de dispositivos otorga esos atributos no al dispositivo sda, sino a su dispositivo "padre". Podemos solventar el problema usando la clave ATTRS en lugar de ATTR. ATTR compara contra los atributos del dispositivo "hijo". ATTRS compara además contra los atributos de todos sus "padres". udevinfo se encarga de ponernos las claves tal cual las necesitamos, basta con copiar y pegar.
Controlando permisos y propietario del dispositivo
Podemos controlar los permisos y propietarios de los dispositivos usando las claves MODE, OWNER y GROUP. Por ejemplo, si queremos constar como propietarios del pendrive y que los demás puedan ver lo que tenemos en el, pero no añadir, cambiar ni borrar nada, haríamos una regla como ésta:
ATTRS{vendor}=="JetFlash",ATTRS{model}=="TS2GJF180",SYMLINK+="pendrive%n",OWNER="gisajo",MODE="0755"
Y si queremos que los compañeros de grupo puedan meternos cosas en el pendrive:
ATTRS{vendor}=="JetFlash",ATTRS{model}=="TS2GJF180",SYMLINK+="pendrive%n",GROUP="cuadrilla",MODE="0775"