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:

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:

Agora o mesmo exemplo anterior, porém monitorando os eventos no udev:

É 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:

Obtendo varias informações do device podemos usar a –query=all:

No final do comando acima temos o reporte do MAJOR 166 do device e o MINOR, que podemos confirmar listando o device no Linux:

Verificando no Linux Allocated Devices podemos ver que 166 é referente ao ACM USB Modems conforme mostro abaixo:

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:

 

 

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.

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.

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:

Antes da regra:

Depois da regra:

Poderíamos ainda no lugar do device number no final de /dev/arduino colocar o serial do dispositivo, ou ainda o major number dele.

Exemplo com adição do MAJOR NUMBER no final do device.

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:

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.

E nosso sistema ficou assim:

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.

No sistema ficara:

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.

O sistema ficara:

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.

Conectando a pendrive teremos:

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.

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.

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.

  • Willian Henrique

    Bem legal o post, o udev é uma ferramenta básica, mas nem todos sabem como ela funciona.
    Abraços,

    • Olá Willian, acho o udev uma ferramenta poderosíssima e que disponibiliza um leque de opções, recursos para você customizar e automatizar tarefas, gosto de explorar bastante ele para me auxiliar no dia-a-dia.

      Abraços.