Una introducción a Udev: El subsistema de Linux para gestionar los eventos de los dispositivos

Udev es el subsistema de Linux que suministra a tu ordenador los eventos de los dispositivos. En términos sencillos, eso significa que es el código que detecta cuando tienes cosas conectadas a tu ordenador, como una tarjeta de red, discos duros externos (incluyendo unidades de memoria USB), ratones, teclados, joysticks y gamepads, unidades de DVD-ROM, etc. Esto hace que sea una utilidad potencialmente útil, y está lo suficientemente expuesta como para que un usuario estándar pueda programar manualmente para hacer cosas como realizar ciertas tareas cuando se conecta un determinado disco duro.

Este artículo le enseña a crear un script udev activado por algún evento udev, como la conexión de una unidad de disco duro específica. Una vez que entienda el proceso para trabajar con udev, puede utilizarlo para hacer todo tipo de cosas, como cargar un controlador específico cuando se conecta un gamepad, o realizar una copia de seguridad automática cuando se conecta la unidad de copia de seguridad.

Un script básico

La mejor manera de trabajar con udev es en pequeños trozos. No escriba todo el script por adelantado, sino que empiece con algo que simplemente confirme que udev desencadena algún evento personalizado.

Dependiendo de su objetivo para su script, no se puede garantizar que vea alguna vez los resultados de un script con sus propios ojos, así que asegúrese de que su script registra que se ha desencadenado con éxito. El lugar habitual para los archivos de registro es el directorio /var, pero eso es principalmente el dominio del usuario root. Para las pruebas, utilice /tmp, al que pueden acceder los usuarios normales y que normalmente se limpia con un reinicio.

Abra su editor de texto favorito e introduzca este sencillo script:

#!/usr/bin/bash
/usr/bin/date >> /tmp/udev.log

Coloque esto en /usr/local/bin o en algún otro lugar de la ruta ejecutable por defecto. Llámelo trigger.sh y, por supuesto, hágalo ejecutable con chmod +x.

$ sudo mv trigger.sh /usr/local/bin
$ sudo chmod +x /usr/local/bin/trigger.sh

Este script no tiene nada que ver con udev. Cuando se ejecuta, el script coloca una marca de tiempo en el archivo /tmp/udev.log. Pruebe el script usted mismo:

$ /usr/local/bin/trigger.sh
$ cat /tmp/udev.log
Tue Oct 31 01:05:28 NZDT 2035

El siguiente paso es hacer que udev desencadene el script.

Identificación del dispositivo

Para que su script sea desencadenado por un evento del dispositivo, udev debe saber bajo qué condiciones debe llamar al script. En la vida real, puedes identificar una unidad de disco duro por su color, el fabricante y el hecho de que la acabas de conectar a tu ordenador. Su ordenador, sin embargo, necesita un conjunto diferente de criterios.

Udev identifica los dispositivos por los números de serie, los fabricantes, e incluso los números de identificación del proveedor y del producto. Dado que esto es temprano en la vida de su secuencia de comandos udev, ser tan amplia, no específica, y todo lo que incluye como sea posible. En otras palabras, lo primero que quiere es capturar casi cualquier evento válido de udev para desencadenar su script.

Con el comando udevadm monitor, puede intervenir en udev en tiempo real y ver lo que ve cuando conecta diferentes dispositivos. Conviértase en root y pruébelo.

$ su
# udevadm monitor

La función de monitorización imprime los eventos recibidos para:

  • UDEV: el evento que envía udev después de procesar la regla
  • KERNEL: el uevent del kernel

Con la ejecución de udevadm monitor, conecte una unidad de disco duro y observe cómo se arroja todo tipo de información a su pantalla. Observe que el tipo de evento es un evento ADD. Esa es una buena manera de identificar qué tipo de evento quieres.

El comando udevadm monitor proporciona un montón de buena información, pero puedes verlo con un formato más bonito con el comando udevadm info, asumiendo que sabes dónde se encuentra actualmente tu unidad de disco duro en tu árbol /dev. Si no es así, desenchufe y vuelva a enchufar su unidad de disco duro y, a continuación, emita inmediatamente este comando:

$ su -c 'dmesg | tail | fgrep -i sd*'

Si ese comando devuelve sdb: sdb1, por ejemplo, sabrá que el kernel ha asignado a su unidad de disco duro la etiqueta sdb.

Alternativamente, puede utilizar el comando lsblk para ver todas las unidades conectadas a su sistema, incluyendo sus tamaños y particiones.

Ahora que ha establecido dónde se encuentra su unidad en su sistema de archivos, puede ver la información de udev sobre ese dispositivo con este comando:

# udevadm info -a -n /dev/sdb | less

Esto devuelve mucha información. Concéntrese en el primer bloque de información por ahora.

Su trabajo es elegir las partes del informe de udev sobre un dispositivo que son más exclusivas de ese dispositivo, y luego decirle a udev que active su script cuando se detecten esos atributos únicos.

El proceso de información de udevadm informa sobre un dispositivo (especificado por la ruta del dispositivo), y luego «camina» por la cadena de dispositivos padres. Para cada dispositivo encontrado, imprime todos los atributos posibles usando un formato clave-valor. Puede componer una regla para que coincida con los atributos de un dispositivo más los atributos de un solo 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 regla udev debe contener un atributo de un solo dispositivo padre.

Los atributos padre son cosas que describen un dispositivo desde el nivel más básico, como que es algo que se ha enchufado en un puerto físico o que es algo con un tamaño o que se trata de un dispositivo extraíble.

Dado que la etiqueta KERNEL de sdb puede cambiar dependiendo de cuántas otras unidades estaban enchufadas antes de enchufar esa unidad de disco duro, ese no es el atributo padre óptimo para una regla udev. Sin embargo, funciona para una prueba de concepto, por lo que podría utilizarlo. Un candidato aún mejor es el atributo SUBSYSTEM, que identifica que se trata de un dispositivo de sistema «en bloque» (por lo que el comando lsblk lista el dispositivo).

Abra un archivo llamado 80-local.rules en /etc/udev/rules.d e introduzca este código:

SUBSYSTEM=="block", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

Guarde el archivo, desenchufe su memoria USB de prueba y reinicie.

¿Espera, reiniciar en una máquina Linux?

Teóricamente, puede simplemente emitir udevadm control –reload, que debería cargar todas las reglas, pero a estas alturas del juego, es mejor eliminar todas las variables. Udev es lo suficientemente complejo, y usted no quiere estar acostado en la cama toda la noche preguntándose si esa regla no funcionó debido a un error de sintaxis o si simplemente debería haber reiniciado. Así que reinicie sin importar lo que su orgullo POSIX le diga.

Cuando su sistema esté de nuevo en línea, cambie a una consola de texto (con Ctl+Alt+F3 o similar) y conecte su unidad de disco duro. Si estás ejecutando un kernel reciente, probablemente verás un montón de salidas en tu consola cuando conectes la unidad. Si ves un mensaje de error como Could not execute /usr/local/bin/trigger.sh, probablemente hayas olvidado hacer ejecutable el script. De lo contrario, con suerte todo lo que ves es que un dispositivo fue conectado, obtuvo algún tipo de asignación de dispositivo del kernel, y así sucesivamente.

Ahora, el momento de la verdad:

$ cat /tmp/udev.log
Tue Oct 31 01:35:28 NZDT 2035

Si ves una fecha y hora muy reciente devuelta desde /tmp/udev.log, udev ha disparado con éxito tu script.

Refinar la regla en algo útil

El problema con esta regla es que es muy genérica. Enchufar un ratón, un pendrive o el pendrive de otra persona activará indiscriminadamente tu script. Ahora es el momento de empezar a centrarse en la unidad de pulgar exacta que desea desencadenar su secuencia de comandos.

Una forma de hacerlo es con el ID del proveedor y el ID del producto. Para obtener estos números, puede utilizar el 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

En este ejemplo, el 03f0:3307 antes de TyCoon Corp. denota los atributos idVendedor e idProducto. También puede ver estos números en la salida de udevadm info -a -n /dev/sdb | grep vendor, pero encuentro la salida de lsusb un poco más fácil para los ojos.

Ahora puede incluir estos atributos en su regla.

SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/thumb.sh"

Pruebe esto (sí, todavía debe reiniciar, sólo para asegurarse de que está recibiendo reacciones frescas de udev), y debería funcionar igual que antes, sólo que ahora si conecta, por ejemplo, una unidad de disco duro fabricada por una empresa diferente (por lo tanto con un idVendor diferente) o un ratón o una impresora, el script no se activará.

Siga añadiendo nuevos atributos para centrarse aún más en esa única unidad de disco duro que desea activar su script. Usando udevadm info -a -n /dev/sdb, puede encontrar cosas como el nombre del proveedor, a veces un número de serie, o el nombre del producto, y así sucesivamente.

Para su propia cordura, asegúrese de añadir sólo un nuevo atributo a la vez. La mayoría de los errores que he cometido (y he visto a otras personas en línea) es lanzar un montón de atributos en su regla udev y preguntarse por qué la cosa ya no funciona. Probar los atributos uno por uno es la forma más segura de asegurarse de que udev puede identificar su dispositivo con éxito.

Seguridad

Esto trae a colación las preocupaciones de seguridad de escribir reglas udev para hacer algo automáticamente cuando se conecta una unidad. En mis máquinas, ni siquiera tengo activado el montaje automático y, sin embargo, este artículo propone scripts y reglas que ejecutan comandos sólo por tener algo enchufado.

Dos cosas a tener en cuenta aquí.

  1. Enfoca tus reglas udev una vez que las tengas funcionando para que activen scripts sólo cuando realmente lo desees. Ejecutar un script que copie ciegamente los datos hacia o desde su ordenador es una mala idea en caso de que cualquier persona que por casualidad lleve la misma marca de unidad de disco duro lo conecte a su caja.
  2. No escriba su regla udev y sus scripts y se olvide de ellos. Sé qué ordenadores tienen mis reglas udev en ellos, y esas cajas son la mayoría de las veces mis ordenadores personales, no los que llevo a conferencias o tengo en mi oficina en el trabajo. Cuanto más «social» es un ordenador, menos probable es que tenga una regla udev en él que podría potencialmente resultar en que mis datos terminen en el dispositivo de otra persona o los datos o el malware de otra persona en mi dispositivo.

En otras palabras, como con gran parte del poder proporcionado por un sistema GNU, es su trabajo ser consciente de cómo está manejando ese poder. Si abusa de él o no lo trata con respeto, podría ir muy mal.

Udev en el mundo real

Ahora que puede confirmar que su script es activado por udev, puede dirigir su atención a la función del script. Ahora mismo, es inútil, no hace nada más que registrar el hecho de que se ha ejecutado.

Utilizo udev para desencadenar copias de seguridad automáticas de mis unidades de disco duro. La idea es que las copias maestras de mis documentos activos están en mi unidad de disco duro (ya que va a todas partes y podría ser trabajada en cualquier momento), y esos documentos maestros se respaldan en mi ordenador cada vez que conecto la unidad a esa máquina. En otras palabras, mi ordenador es la unidad de copia de seguridad y mis datos de producción son móviles. El código fuente está disponible, así que siéntase libre de mirar el código de attachup para más ejemplos de restricción de sus pruebas udev.

Dado que es para lo que más uso udev, es el ejemplo que usaré aquí, pero udev puede agarrar muchas otras cosas, como gamepads (esto es útil en sistemas que no están configurados para cargar el módulo xboxdrv cuando se conecta un gamepad) y cámaras y micrófonos (útil para establecer entradas cuando se conecta un micrófono específico), así que date cuenta de que es bueno para mucho más que este ejemplo.

Una versión simple de mi sistema de copia de seguridad es un proceso de dos comandos:

SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", SYMLINK+="safety%n"
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

La primera línea detecta mi unidad de disco duro con los atributos ya discutidos, y luego asigna a la unidad de disco duro un enlace simbólico dentro del árbol de dispositivos. El enlace simbólico que asigna es safety%n. El %n es una macro de udev que se resuelve a cualquier número que el kernel da al dispositivo, como sdb1, sdb2, sdb3, y así sucesivamente. Así que %n sería el 1 o el 2 o el 3.

Esto crea un symlink en el árbol dev, por lo que no interfiere con el proceso normal de conectar un dispositivo. Esto significa que si usas un entorno de escritorio al que le gusta montar automáticamente los dispositivos, no le causarás problemas.

La segunda línea ejecuta el script.

Mi script de copia de seguridad tiene el siguiente aspecto:

#!/usr/bin/bash
mount /dev/safety1 /mnt/hd
sleep 2
rsync -az /mnt/hd/ /home/seth/backups/ && umount /dev/safety1

El script utiliza el enlace simbólico, lo que evita la posibilidad de que udev nombre la unidad de disco de forma inesperada (por ejemplo, si ya tengo una unidad de disco en miniatura llamada DISK conectada a mi ordenador, y conecto mi otra unidad de disco en miniatura también llamada DISK, la segunda se etiquetará como DISK_, lo que frustraría mi script). Monta safety1 (la primera partición de la unidad) en mi punto de montaje preferido de /mnt/hd.

Una vez montado de forma segura, utiliza rsync para hacer una copia de seguridad de la unidad en mi carpeta de copia de seguridad (mi script actual utiliza rdiff-backup, y el tuyo puede utilizar cualquier solución de copia de seguridad automatizada que prefieras).

Udev es tu dev

Udev es un sistema muy flexible y te permite definir reglas y funciones de formas que pocos otros sistemas se atreven a proporcionar a los usuarios. Apréndalo y utilícelo, y disfrute del poder de POSIX.

Este artículo se basa en el contenido del Manual de Slackermedia, que está licenciado bajo la Licencia de Documentación Libre GNU 1.3.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.