Linux – O poderoso udev

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://wiki.debian.org/udev

https://www.kernel.org/doc/Documentation/devices.txt

https://www.kernel.org/pub/linux/utils/kernel/hotplug/udev/udev.html

 

Share Button

CC BY-NC-SA 4.0 Linux – O poderoso udev by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.