Como ejecutar scripts al conectar dispositivo USB linux

Sin mucha introducción el otro día tenía un script que necesitaba ejecutarse cada vez que se conectara mi celular. La solución no fue del todo directa así que considero útil los pasos que use.

Conectar el device y revisar devices mediante lsusb

En mi caso es un celular. Importante anotar bus, device

lsusb
Bus 002 Device 059: ID 12d1:107e Huawei Technologies Co., Ltd.

Conseguir mayores detalles del device

udevadm info -a -p $(udevadm info -q path -n /dev/bus/usb/002/059)
Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device. looking at device '/devices/pci0000:00/0000:00:14.0/usb2/2-2': KERNEL=="2-2" SUBSYSTEM=="usb" DRIVER=="usb" ATTR{authorized}=="1" ATTR{avoid_reset_quirk}=="0" ATTR{bConfigurationValue}=="1" ATTR{bDeviceClass}=="00" ATTR{bDeviceProtocol}=="00" ATTR{bDeviceSubClass}=="00" ATTR{bMaxPacketSize0}=="64" ATTR{bMaxPower}=="500mA" ATTR{bNumConfigurations}=="1" ATTR{bNumInterfaces}==" 3" ATTR{bcdDevice}=="0299" ATTR{bmAttributes}=="c0" ATTR{busnum}=="2" ATTR{configuration}=="hisuite_mtp_mass_storage_adb" ATTR{devnum}=="59" ATTR{devpath}=="2" ATTR{idProduct}=="107e" ATTR{idVendor}=="12d1" ATTR{ltm_capable}=="no" ATTR{manufacturer}=="HUAWEI" ATTR{maxchild}=="0" ATTR{product}=="SNE-LX3" ATTR{quirks}=="0x0" ATTR{removable}=="removable" ATTR{speed}=="480" ATTR{urbnum}=="722" ATTR{version}==" 2.00" looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2': KERNELS=="usb2" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{authorized}=="1" ATTRS{authorized_default}=="1" ATTRS{avoid_reset_quirk}=="0" ATTRS{bConfigurationValue}=="1" ATTRS{bDeviceClass}=="09" ATTRS{bDeviceProtocol}=="01" ATTRS{bDeviceSubClass}=="00" ATTRS{bMaxPacketSize0}=="64" ATTRS{bMaxPower}=="0mA" ATTRS{bNumConfigurations}=="1" ATTRS{bNumInterfaces}==" 1" ATTRS{bcdDevice}=="0404" ATTRS{bmAttributes}=="e0" ATTRS{busnum}=="2" ATTRS{configuration}=="" ATTRS{devnum}=="1" ATTRS{devpath}=="0" ATTRS{idProduct}=="0002" ATTRS{idVendor}=="1d6b" ATTRS{interface_authorized_default}=="1" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="Linux 4.4.0-210-generic xhci-hcd" ATTRS{maxchild}=="9" ATTRS{product}=="xHCI Host Controller" ATTRS{quirks}=="0x0" ATTRS{removable}=="unknown" ATTRS{speed}=="480" ATTRS{urbnum}=="1284" ATTRS{version}==" 2.00" looking at parent device '/devices/pci0000:00/0000:00:14.0': KERNELS=="0000:00:14.0" SUBSYSTEMS=="pci" DRIVERS=="xhci_hcd" ATTRS{broken_parity_status}=="0" ATTRS{class}=="0x0c0330" ATTRS{consistent_dma_mask_bits}=="64" ATTRS{d3cold_allowed}=="1" ATTRS{device}=="0x9c31" ATTRS{dma_mask_bits}=="64" ATTRS{driver_override}=="(null)" ATTRS{enable}=="1" ATTRS{irq}=="40" ATTRS{local_cpulist}=="0-3" ATTRS{local_cpus}=="0f" ATTRS{msi_bus}=="1" ATTRS{numa_node}=="-1" ATTRS{subsystem_device}=="0x228e" ATTRS{subsystem_vendor}=="0x103c" ATTRS{vendor}=="0x8086" looking at parent device '/devices/pci0000:00': KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS==""

Primero preparamos el script a usar, en este caso yo use una notificacion para revisar graficamente que el script se esta ejecutando. Otra alternativa podria ser crear un archivo o una carpeta para señalar que se ejecuto correctamente. En fin agregar lo que se requiere ejecutar. En este caso como utilizo notify-send se requiere exportar el DISPLAY y el XAUTHORITY de lo contrario no funcionan las notificaciones.

IMPORTANTE el script tiene que tener el #!/bin/bash de lo contrario fallara

#!/bin/bash export DISPLAY=":0" export XAUTHORITY=/home/aferral/.Xauthority notify-send "running_script_USB" echo "running"

Tambien recordar permitir que script sea ejecutable

chmod +x /home/aferral/t.sh

En este punto seria util probar que el script ejecute correctamente antes de intentar ejecutarlo con udev.

Posterior a esto editar/crear el archivo con las reglas ante eventos de devices. El nombre puede ser cualquiera, pero el numero es importante ya que da el orden de ejecucion ante eventos.

vim /etc/udev/rules.d/99-my_rule.rules

Este paso es necesario para buscar reglas para detectar el device. IMPORTANTE hay que conseguir reglas que solo calcen una vez por ejemplo si solo se usa SUBSYSTEM=="usb" el celular realizaría 2 trigger de la regla.

Dado el texto del device genere estas reglas. Notar que sin el ATTR{configuration}=="hisuite_mtp_mass_storage_adb" se ejecutar mas de una vez.

# version que ejecuta como root ACTION=="add", ATTR{configuration}=="hisuite_mtp_mass_storage_adb", SUBSYSTEM=="usb", ATTRS{idVendor}=="1d6b", ATTRS{idProduct}=="0002", RUN+="/bin/bash -c 'bash /home/aferral/t.sh 2>&1 | tee /tmp/logs.txt # version que ejecuta como usuario aferral ACTION=="add", ATTR{configuration}=="hisuite_mtp_mass_storage_adb", SUBSYSTEM=="usb", ATTRS{idVendor}=="1d6b", ATTRS{idProduct}=="0002", RUN+="/bin/bash -c 'runuser aferral -l -s /bin/bash /home/aferral/t.sh 2>&1 | tee /tmp/logs.txt'

Al script le agregue algunas partes para facilitar debug de errores. Escribira en /tmp/logs.txt toda salida de stdout o stderr. Importante que en la especificacion del path sea path completo no path relativos.

Tambien opcional pero util es ejecutar con runuser de lo contrario el script objetivo se ejecuta como root lo cual puede producir ciertos problemas con los archivos generados u otros recursos. Tambien notar que hay que usar /bin/bash -c para poder utilizar los pipes, de lo contrario no logra interpretar la redireccion de stderr o el pipe a comando tee.

Realizar recarga de udev y revisar logs al conectar el usb. En caso de encontrar un error este deberia quedar en /tmp/log.txt , pero puede ser que la regla este mal configurada o el comando RUN este mal configurado. Para revisar leemos el log de syslog.

sudo service udev restart tail -f /var/log/syslog

Ahora conectar el device USB. Si todo esta bien deberá enviar una notificación.

Referencias