Neste post vamos falar sobre o famoso udev, poderosíssimo gerenciador dinâmico de dispositivos do Linux a partir do Kernel 2.6, tendo como antecessores a combinação DEVFS e hotplug.
Um pouco de historia agora, um device no Linux nada mais é que um pseudo-arquivo que possui a combinação de dois endereços, o major number e o minor number, referentes a indicar a categoria do dispositivo e a identificação do dispositivo conectado, antes do udev o DEVFS era quem criava os dispositivos no /dev e tinha todos a pronta entrega independente de atribuir poucos para uso, paralelamente trabalhava-se com o hotplug, este já entrava em cena quando novos dispositivos eram conectados, principalmente os USB, então caso necessitasse subir algum modulo do kernel, setar permissões, executar rotinas isso era com o hotplug e suas toneladas de scripts.
Porém conforme aumentava-se o numero de devices, e o numero de dispositivos no servidor o número de scripts do hotplug também, e sucessivamente percebia-se isso no tempo de boot do sistema.
O Udev
Então chega o udev, com a função de ser dinâmico em termos de criar os dispositivos no /dev e não criar toneladas de pastas, subpastas e devices como o DevFS, e ter o poder de detectar novos dispositivos e montá-los como o hotplug, porém mais rápido, escrito em C, essa parte de administração roda em user-space e não como DevFS em kernel-space, perde-se na flexibilidade dos scripts do hotplug e ganha-se e muito no meu ponto de vista com as regras no udev.
Esta é uma característica forte no udev, onde qualquer personalização ou configuração é baseada em regras(rules), onde você pode definir permissões, nomes, link-simbólicos para devices, chamar scripts e diversas outras características.
Os arquivos de configuração/personalização do udev encontram-se:
# Customizadas /etc/udev/rules.d/ # Volateis /run/udev/rules.d/ # Sistema /lib/udev/rules.d/
Um exemplo de arquivo de regra do udev é o /etc/udev/rules.d/70-persistent-net.rules, o numero inicial é de identificação e que da ordem sobre a execução, em seguida um nome para identificar e por fim .rules e você já possui uma ou varias regras para o udev carregar a partir de agora, e vamos ver como recarregar as regras sem ter que reiniciar.
Com essas regras, acabamos com vários problemas que usuários de Linux sofrem, como “conectar o arduino e não conseguir gravar o firmware nele”, ou “plugou o gravador Olimex e não consegue gravar o firmware no ARM Cortex-M”, “conectou a pendrive de dados, mas agora reconheceu como /dev/sdf1 e antes era /dev/sde1”, vamos ver como será fácil resolver estes problemas.
Para criar uma regra você deve conhecer os operadores e as opções ou chaves, na tabela 1 os operadores e na tabela 2 os parâmetros, variáveis, atributos para isso:
Tabela 1: Operadores udev
== | Comparação por igualdade |
!= | Comparação por diferença |
= | Atribuindo um valor |
+= | Adiciona um valor para uma chave especifica |
:= | Atribui valor para um chave e não permiti mais modificação |
Tabela 2: Parâmetros/chaves/atributos udev
ACTION | Nome da ação do evento |
KERNEL | Nome do dispositivo no Kernel |
DEVPATH | Nome do device path, algo como /devices/* |
SUBSYSTEM | Nome no subsistema, algo como sound ou net |
BUS | Nome de um barramento, como IDE, USB e demais |
DRIVER | Nome do device driver |
ID | Nome do dispositivo, independente do nome no Kernel |
SYSFS{value} | Um valor de atributo sysfs, que pode ser qualquer coisa |
ENV{key} | Uma variável ambiente, que pode ser qualquer coisa |
PROGRAM | Execução de um programa externo. A key é considerada verdadeira se o programa retorna um valor 0 |
RESULT | A saída padrão retornado por uma chamada anterior PROGRAM |
NAME | O nome do arquivo de dispositivo a ser criado pela regra. Note-se que apenas a primeira regra com uma especificação de NAME terá efeito, as demais linhas para o mesmo device dever-a usar SYMLINK |
SYMLINK | Um link-simbólico para um device criado |
OWNER | O dono do dispositivo |
GROUP | O grupo a qual o dispositivo ira pertencer |
MODE | Permissão para acesso ao dispositivo, no estilo octal (644, 777, 700) |
RUN | Uma lista de programas a serem executados pelo dispositivo |
LABEL | Um rotulo com nome para ser usado dentro do arquivo de configuração |
GOTO | Salta para um regra, usando o nome da regra em uma LABEL |
IMPORT{type} | Importa um arquivo ou resultado da execução de um arquivo |
WAIT_FOR_SYSFS | Espera por um arquivo de dispositivo especificado a ser criado. Usado para solucionar problemas de tempo e de dependência |
OPTIONS | Habilita opções especiais:
last_rule: termina a execução da regra para esse tipo de dispositivo; ignore_device: ignora a regra atual; ignore_remove: ignora pedidos de remoção subsequentes; all_partitions: cria arquivos de dispositivos para partições de todos disk partitions |
Monitorando os dispositivos
Agora vamos ver como monitorar em tempo-real as ações e eventos quando um dispositivo é conectado e também, como podemos obter todas informações necessárias de um device no Linux para então criar uma regra.
Usando o comando udevadm monitor irei conectar/desconectar um Arduino UNO na porta USB e monitorar os eventos em no kernel:
$ sudo udevadm monitor --kernel monitor will print the received events for: KERNEL - the kernel uevent KERNEL[4752.231047] add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb) KERNEL[4752.232172] add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) KERNEL[4752.232252] add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1 (usb) KERNEL[4752.501637] add /module/cdc_acm (module) KERNEL[4752.502598] add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/tty/ttyACM0 (tty) KERNEL[4752.502709] add /bus/usb/drivers/cdc_acm (drivers) ... KERNEL[4789.059557] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/tty/ttyACM0 (tty) KERNEL[4789.059662] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) KERNEL[4789.059718] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1 (usb) KERNEL[4789.060618] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb)
Agora o mesmo exemplo anterior, porém monitorando os eventos no udev:
$ sudo udevadm monitor --udev monitor will print the received events for: UDEV - the event which udev sends out after rule processing UDEV [4808.836203] add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb) UDEV [4808.838929] add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1 (usb) UDEV [4808.840352] add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) UDEV [4808.858759] add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/tty/ttyACM0 (tty) ... UDEV [4817.734337] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1 (usb) UDEV [4817.734488] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/tty/ttyACM0 (tty) UDEV [4817.736085] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) UDEV [4817.745708] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb)
É fácil notar que a diferença da saída no modo –kernel e –udev é a parte dos módulos e drivers que são utilizados no dispositivo, e é muito legal ver os eventos add ao conectar e remove ao desconectar o dispositivo USB.
Vimos que o Arduino UNO criou o device /dev/ttyACM0, sabendo disso, conseguimos obter diversas informações com o dispositivo conectado, com o path do device usando o udevadm info:
$ sudo udevadm info --query=path --name=/dev/ttyACM0 /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/tty/ttyACM0
Obtendo varias informações do device podemos usar a –query=all:
$ sudo udevadm info --query=all --name=/dev/ttyACM0 P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/tty/ttyACM0 N: ttyACM0 S: serial/by-id/usb-Arduino__www.arduino.cc__Arduino_Uno_64938323231351215071-if00 S: serial/by-path/pci-0000:00:1d.0-usb-0:1.2:1.0 E: DEVLINKS=/dev/serial/by-id/usb-Arduino__www.arduino.cc__Arduino_Uno_64938323231351215071-if00 /dev/serial/by-path/pci-0000:00:1d.0-usb-0:1.2:1.0 E: DEVNAME=/dev/ttyACM0 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/tty/ttyACM0 E: ID_BUS=usb E: ID_MM_CANDIDATE=1 E: ID_MODEL=Arduino_Uno E: ID_MODEL_ENC=Arduino\x20Uno E: ID_MODEL_FROM_DATABASE=Uno (CDC ACM) E: ID_MODEL_ID=0001 E: ID_PATH=pci-0000:00:1d.0-usb-0:1.2:1.0 E: ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_2_1_0 E: ID_REVISION=0000 E: ID_SERIAL=Arduino__www.arduino.cc__Arduino_Uno_64938323231351215071 E: ID_SERIAL_SHORT=64938323231351215071 E: ID_TYPE=generic E: ID_USB_DRIVER=cdc_acm E: ID_USB_INTERFACES=:020201:0a0000: E: ID_USB_INTERFACE_NUM=00 E: ID_VENDOR=Arduino__www.arduino.cc_ E: ID_VENDOR_ENC=Arduino\x20\x28www.arduino.cc\x29 E: ID_VENDOR_FROM_DATABASE=Arduino SA E: ID_VENDOR_ID=2341 E: MAJOR=166 E: MINOR=0 E: SUBSYSTEM=tty E: UDEV_LOG=3 E: USEC_INITIALIZED=4887960216
No final do comando acima temos o reporte do MAJOR 166 do device e o MINOR, que podemos confirmar listando o device no Linux:
$ ls -l /dev/ttyACM0 crw-rw---- 1 root dialout 166, 0 Ago 23 16:22 /dev/ttyACM0
Verificando no Linux Allocated Devices podemos ver que 166 é referente ao ACM USB Modems conforme mostro abaixo:
166 char ACM USB modems 0 = /dev/ttyACM0 First ACM modem 1 = /dev/ttyACM1 Second ACM modem
E um comando que uso muito quando quero obter as diversas informações de um device para criar uma regra é udevadm info –attribute-walk como abaixo:
$ sudo udevadm info --attribute-walk --name=/dev/ttyACM0 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:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/tty/ttyACM0': KERNEL=="ttyACM0" SUBSYSTEM=="tty" DRIVER=="" looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0': KERNELS=="2-1.2:1.0" SUBSYSTEMS=="usb" DRIVERS=="cdc_acm" ATTRS{bInterfaceClass}=="02" ATTRS{bmCapabilities}=="6" ATTRS{bInterfaceSubClass}=="02" ATTRS{bInterfaceProtocol}=="01" ATTRS{bNumEndpoints}=="01" ATTRS{supports_autosuspend}=="1" ATTRS{bAlternateSetting}==" 0" ATTRS{bInterfaceNumber}=="00" looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2': KERNELS=="2-1.2" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{bDeviceSubClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{devpath}=="1.2" ATTRS{idVendor}=="2341" ATTRS{speed}=="12" ATTRS{bNumInterfaces}==" 2" ATTRS{bConfigurationValue}=="1" ATTRS{bMaxPacketSize0}=="8" ATTRS{busnum}=="2" ATTRS{devnum}=="7" ATTRS{configuration}=="" ATTRS{bMaxPower}=="100mA" ATTRS{authorized}=="1" ATTRS{bmAttributes}=="c0" ATTRS{bNumConfigurations}=="1" ATTRS{maxchild}=="0" ATTRS{bcdDevice}=="0000" ATTRS{avoid_reset_quirk}=="0" ATTRS{quirks}=="0x0" ATTRS{serial}=="64938323231351215071" ATTRS{version}==" 1.10" ATTRS{urbnum}=="12" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="Arduino (www.arduino.cc)" ATTRS{removable}=="removable" ATTRS{idProduct}=="0001" ATTRS{bDeviceClass}=="02" ATTRS{product}=="Arduino Uno" looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1': KERNELS=="2-1" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{bDeviceSubClass}=="00" ATTRS{bDeviceProtocol}=="01" ATTRS{devpath}=="1" ATTRS{idVendor}=="8087" ATTRS{speed}=="480" ATTRS{bNumInterfaces}==" 1" ATTRS{bConfigurationValue}=="1" ATTRS{bMaxPacketSize0}=="64" ATTRS{busnum}=="2" ATTRS{devnum}=="2" ATTRS{configuration}=="" ATTRS{bMaxPower}=="0mA" ATTRS{authorized}=="1" ATTRS{bmAttributes}=="e0" ATTRS{bNumConfigurations}=="1" ATTRS{maxchild}=="6" ATTRS{bcdDevice}=="0000" ATTRS{avoid_reset_quirk}=="0" ATTRS{quirks}=="0x0" ATTRS{version}==" 2.00" ATTRS{urbnum}=="110" ATTRS{ltm_capable}=="no" ATTRS{removable}=="fixed" ATTRS{idProduct}=="0024" ATTRS{bDeviceClass}=="09" looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2': KERNELS=="usb2" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{bDeviceSubClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{devpath}=="0" ATTRS{idVendor}=="1d6b" ATTRS{speed}=="480" ATTRS{bNumInterfaces}==" 1" ATTRS{bConfigurationValue}=="1" ATTRS{bMaxPacketSize0}=="64" ATTRS{authorized_default}=="1" ATTRS{busnum}=="2" ATTRS{devnum}=="1" ATTRS{configuration}=="" ATTRS{bMaxPower}=="0mA" ATTRS{authorized}=="1" ATTRS{bmAttributes}=="e0" ATTRS{bNumConfigurations}=="1" ATTRS{maxchild}=="3" ATTRS{bcdDevice}=="0308" ATTRS{avoid_reset_quirk}=="0" ATTRS{quirks}=="0x0" ATTRS{serial}=="0000:00:1d.0" ATTRS{version}==" 2.00" ATTRS{urbnum}=="26" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="Linux 3.8.0-35-generic ehci_hcd" ATTRS{removable}=="unknown" ATTRS{idProduct}=="0002" ATTRS{bDeviceClass}=="09" ATTRS{product}=="EHCI Host Controller" looking at parent device '/devices/pci0000:00/0000:00:1d.0': KERNELS=="0000:00:1d.0" SUBSYSTEMS=="pci" DRIVERS=="ehci-pci" ATTRS{irq}=="23" ATTRS{subsystem_vendor}=="0x17aa" ATTRS{broken_parity_status}=="0" ATTRS{class}=="0x0c0320" ATTRS{companion}=="" ATTRS{consistent_dma_mask_bits}=="32" ATTRS{dma_mask_bits}=="32" ATTRS{local_cpus}=="00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f" ATTRS{device}=="0x1c26" ATTRS{uframe_periodic_max}=="100" ATTRS{enable}=="1" ATTRS{msi_bus}=="" ATTRS{local_cpulist}=="0-3" ATTRS{vendor}=="0x8086" ATTRS{subsystem_device}=="0x3975" ATTRS{numa_node}=="-1" ATTRS{d3cold_allowed}=="1" looking at parent device '/devices/pci0000:00': KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS==""
Criando regras
Já conhecemos onde ficam salva as regras, vimos como explorar e obter informações dos devices e agora com estas informações vamos criar algumas regras e automatizar algo quando nosso dispositivo for conectado, e como exemplo irei usar um Arduino UNO e um HD Externo USB.
Nossa primeira regra será para setar a permissão do device USB do Arduino para leitura e escrita para o proprietário, grupo e outros, assim qualquer aplicação poderá escrever no dispositivo, e para facilitar quero que crie um link-simbólico do nosso device no caso /dev/ttyACM0 para /dev/arduino, para isso juntei algumas informações que coletamos com o –attribute-walk.
KERNEL=="ttyACM0" SUBSYSTEMS=="usb" DRIVERS=="cdc_acm" ATTRS{idVendor}=="2341" ATTRS{serial}=="64938323231351215071" ATTRS{manufacturer}=="Arduino (www.arduino.cc)" ATTRS{idProduct}=="0001" ATTRS{product}=="Arduino Uno"
Podemos usar qualquer uma das informações para criar uma regra, neste caso vou usar o KERNEL, SUBSYSTEMS, idVendor e idProduct, então vamos criar a regra /run/udev/rules.d/50-arduino.rules, se quiser pode criar em /etc/udev/rules.d.
KERNEL=="ttyACM*",SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0001", MODE="666", SYMLINK+="arduino%n"
Tem que ser uma ação de ‘add’, onde o KERNEL seja algo com ttyACM, o SUBSYSTEMS usb e enquadre o idVendor e idProduct conforme especificado na informação adquirida, se isso tudo conferir a permissão deste device será 666 [r+w] e um SYMLINK será criado, algo com /dev/arduino[id].
Vamos aplicar a nossa regra sem ter que reiniciar, recarregando com o comando abaixo:
$ sudo udevadm control --reload-rules
Antes da regra:
$ ls /dev/ttyACM0 -l crw-rw---- 1 root dialout 166, 0 Ago 24 21:28 /dev/ttyACM0
Depois da regra:
$ ls -l /dev/{ttyACM0,arduino*} lrwxrwxrwx 1 root root 7 Ago 24 21:58 /dev/arduino0 -> ttyACM0 crw-rw-rw- 1 root dialout 166, 0 Ago 24 21:58 /dev/ttyACM0
Poderíamos ainda no lugar do device number no final de /dev/arduino colocar o serial do dispositivo, ou ainda o major number dele.
KERNEL=="ttyACM*",SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0001", MODE="666", SYMLINK+="arduino$attr{serial}"
$ sudo udevadm control --reload-rules $ ls -l /dev/{ttyACM0,arduino*} lrwxrwxrwx 1 root root 7 Ago 24 22:49 /dev/arduino64938323231351215071 -> ttyACM0 crw-rw-rw- 1 root dialout 166, 0 Ago 24 22:49 /dev/ttyACM0
Exemplo com adição do MAJOR NUMBER no final do device.
KERNEL=="ttyACM*",SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0001", MODE="666", SYMLINK+="arduino%M"
$ ls -l /dev/{ttyACM0,arduino*} lrwxrwxrwx 1 root root 7 Ago 24 22:52 /dev/arduino166 -> ttyACM0 crw-rw-rw- 1 root dialout 166, 0 Ago 24 22:52 /dev/ttyACM0
Uma lista das combinações e opções que pode-se usar na regras:
%r | Diretório do device |
%p | DEVPATH |
%k | Valor interno do dispositivo |
%n | Numero de dispositivo |
%N | Nome temporário do dispositivo |
%M | Major Number do dispositivo |
%m | Minor Number do dispositivo |
%s{atributo} ou $attr{atributo} | Valor de um atributo do SysFS |
%E{variavel} ou $attr{variavel} | Valor de uma variável ambiente |
%c | Saída do PROGRAM |
%% | Caractere % |
Agora vamos fazer uma outra regra para um HD Externo, no caso o meu Samsung M3, executei o mesmo procedimento para USB do Arduino com o comando udevadm info –attribute-walk –name=/dev/sdc, no meu caso /dev/sdc é a unidade do meu HD externo neste momento.
E para criar a regra para ele, usarei as seguintes informações:
KERNEL=="sdc" SUBSYSTEM=="block" ATTRS{manufacturer}=="Samsung M3 Portable"
A regra mais simples e básica para este dispositivo de bloco seria de encontrar o dispositivo e seria muito legal se montasse o mesmo, vamos fazer isso.
KERNEL=="sd*", SUBSYSTEM=="block", ATTRS{manufacturer}=="Samsung M3 Portable", NAME="samsung_externo", RUN+="/bin/mount /dev/samsung_externo /mnt/hd_externo"
E nosso sistema ficou assim:
$ mount | grep samsung /dev/samsung_externo on /mnt/hd_externo type fuseblk (rw,nosuid,nodev,allow_other,blksize=4096)
Então o udev procura por qualquer entrada no kernel com sd*, que esteja no SUBSYSTEMS block e que a informação de Manufacturer enquadre com “Samsung M3 Portable”, sendo assim o nome do dispositivo será /dev/samsung_externo e logo em seguida o RUN irá executar o comando mount.
Mas e se nosso HD externo possuir mais de uma partição? Vamos ver.
KERNEL=="sd?[1-9]", SUBSYSTEM=="block", ATTRS{manufacturer}=="Samsung M3 Portable", NAME="samsung_data%n", RUN+="/bin/mount /dev/samsung_data%n /mnt/data%n"
No sistema ficara:
$ mount | grep samsung /dev/samsung_data2 on /mnt/data2 type ext4 (rw) /dev/samsung_data1 on /mnt/data1 type fuseblk (rw,nosuid,nodev,allow_other,blksize=4096)
O atributo chave é o KERNEL, onde irá filtrar por sd?[1-9], sendo o ? qualquer caractere, e o %n sendo a identificação de cada partição, como este HD eu sei que possui duas partições eu já possuo uma regra que diferencia as duas partições e os dois pontos de montagem, vamos ver.
KERNEL=="sd?1", SUBSYSTEM=="block", ATTRS{manufacturer}=="Samsung M3 Portable", NAME="samsung_backup", RUN+="/bin/mount /dev/samsung_backup /mnt/backups" 6 KERNEL=="sd?2", SUBSYSTEM=="block", ATTRS{manufacturer}=="Samsung M3 Portable", NAME="samsung_yocto", RUN+="/bin/mount /dev/samsung_yocto /mnt/yocto"
O sistema ficara:
$ mount | grep samsung /dev/samsung_yocto on /mnt/yocto type ext4 (rw) /dev/samsung_backup on /mnt/backups type fuseblk (rw,nosuid,nodev,allow_other,blksize=4096)
Eu usei o exemplo de montar o device, mas você pode usar outros como disparar um evento para abrir uma janela com o partição montada, por exemplo com o utilitário nautilus.
São muitas as possibilidades e recursos para manipular devices com udev, indo muito além da porta USB como estamos vendo.
Extra
Como dica extra, mostrarei uma simples regra para um pendrive, usarei o serial dele como chave, ele irá criar o device /dev/hardlock, montar no diretório /mnt/hardlock e abrir o ponto de montagem com o Nautilus, esta será a regra /etc/udev/rules.d/12-mount-pendrive-hl.rules.
ACTION=="add", KERNEL=="sd?1", SUBSYSTEMS=="usb", ATTRS{serial}=="5B7709002298", SYMLINK+="hardlock", ENV{UDISKS_IGNORE}="1", RUN+="/bin/sh -c 'mount /dev/hardlock /mnt/hardlock; /lib/udev/open-mount.sh /mnt/hardlock'" ACTION=="remove", KERNEL=="sd?1", SUBSYSTEMS=="usb", ATTRS{serial}=="5B7709002298", RUN+="/bin/sh -c 'umount -f /mnt/hardlock'"
Conectando a pendrive teremos:
$ mount | grep hardlock /dev/sdc1 on /mnt/hardlock type vfat (rw) $ ls -l /dev/hardlock lrwxrwxrwx 1 root root 4 Ago 25 22:14 /dev/hardlock -> sdc1
Eu criei duas regras uma para evento de conectar que irá montar o dispositivo e outra para quando desconectar o pendrive e o dispositivo seja desmontado, a dica aqui vai para ENV{UDISKS_IGNORE}=1 que irá ignorar a ação para o utilitário udisks, que no caso montaria automaticamente a pendrive e abriria uma janela, em seguida uso o RUN, primeiro faço um mount do device e logo em seguida chamo meu script open-mount.sh criado em /lib/udev, vamos ver o script que é bem simples.
#! /bin/sh export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin export DISPLAY=:0.0 if [ -d $1 ]; then /usr/bin/nautilus $1 exit 0 fi exit 1
Um shell script bem simples que configura o PATH, exporta o DISPLAY e verifica se o parâmetro passado é um diretório, se existe no caso, se positivo irá ser aberto com o Nautilus.
E para encerrar com chave de ouro, vamos retrabalhar na regra do Arduino e dessa vez vamos configurar o RUN para assim que conectar o Arduino na USB a IDE abra, edite novamente o /etc/udev/rules.d/50-arduino.rules.
KERNEL=="ttyACM*",SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0001", MODE="666", SYMLINK+="arduino%n", RUN+="/bin/sh -c 'export DISPLAY=:0.0; /opt/arduino-1.0.5/arduino'"
E vamos adicionar RUN+=”/bin/sh -c ‘COMANDO’ “, no meu caso a IDE esta em /opt/arduino-1.0.5/arduino, recarregue as regras e conecte o Arduino e a IDE irá abrir ao conectar o Arduino.
Pode-se estender para automatizar tarefas com gravadores, outras placas de desenvolvimento, conectar um HD externo e iniciar backup, bloquear dispositivos ou programas, o limite é a sua imaginação.
O post ficou bem extenso mas bem divertido e consegui passar um conteúdo rico e bem pratico de uso do udev.
Espero que tenham gostado.
Até a próxima!
Referências
https://pt.wikipedia.org/wiki/Udev
https://www.kernel.org/doc/Documentation/devices.txt
https://www.kernel.org/pub/linux/utils/kernel/hotplug/udev/udev.html
Linux – O poderoso udev by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.