Uma introdução ao Udev: O subsistema Linux para gerenciar eventos de dispositivos

Udev é o subsistema Linux que abastece o seu computador com eventos de dispositivos. Em inglês simples, isso significa que é o código que detecta quando você tem coisas conectadas ao seu computador, como uma placa de rede, discos rígidos externos (incluindo unidades USB), mouses, teclados, joysticks e gamepads, unidades de DVD-ROM, e assim por diante. Isso faz dele um utilitário potencialmente útil, e é bastante exposto que um usuário padrão pode fazer coisas como executar certas tarefas quando um determinado disco rígido está conectado.

Este artigo ensina como criar um script udev acionado por algum evento udev, como conectar uma unidade de polegar específica. Uma vez entendido o processo para trabalhar com o udev, você pode usá-lo para fazer todo o tipo de coisas, como carregar um driver específico quando um controle de jogo é anexado, ou executar uma cópia de segurança automática quando você anexa sua unidade de backup.

Um script básico

A melhor maneira de trabalhar com o udev é em pequenos pedaços. Não escreva o script inteiro antecipadamente, mas comece com algo que simplesmente confirme que o udev aciona algum evento personalizado.

Dependente do seu objetivo para o seu script, você não pode garantir que você nunca verá os resultados de um script com seus próprios olhos, então certifique-se de que o seu script registra que ele foi acionado com sucesso. O lugar habitual para arquivos de log é no diretório /var, mas isso é principalmente o domínio do usuário root. Para testar, use /tmp, que é acessível por usuários normais e normalmente é limpo com um reboot.

Abra seu editor de texto favorito e digite este script simples:

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

Coloca isto em /usr/local/bin ou algum lugar assim no caminho executável padrão. Chame-lhe trigger.sh e, claro, torne-o executável com chmod +x.

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

Este script não tem nada a ver com o udev. Quando ele executa, o script coloca um timestamp no arquivo /tmp/udev.log. Teste você mesmo o script:

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

O próximo passo é fazer o udev acionar o script.

Unique device identification

Para que o script seja acionado por um evento de dispositivo, o udev deve saber sob quais condições ele deve chamar o script. Na vida real, você pode identificar uma unidade de polegar pela sua cor, o fabricante e o fato de que você acabou de conectá-la ao seu computador. Seu computador, no entanto, precisa de um conjunto diferente de critérios.

Udev identifica os dispositivos por números de série, fabricantes e até mesmo por números de identificação de fornecedor e de produto. Uma vez que isto está no início da vida útil do seu udev script, seja o mais amplo, não específico e com tudo incluído possível. Em outras palavras, você quer primeiro capturar quase qualquer evento udev válido para acionar seu script.

Com o comando udevm monitor, você pode tocar no udev em tempo real e ver o que ele vê quando você conecta diferentes dispositivos. Torne-se root e tente-o.

$ su
# udevadm monitor

A função monitor imprime eventos recebidos para:

  • UDEV: o evento udev envia após o processamento de regras
  • KERNEL: o evento do kernel

Com o monitor udevadm a correr, ligue uma drive de polegar e observe enquanto todo o tipo de informação é lançada para a sua tela. Note que o tipo de evento é um evento ADD. Essa é uma boa maneira de identificar que tipo de evento você quer.

O comando udevadm monitor fornece muitas informações boas, mas você pode vê-lo com uma formatação mais bonita com o comando udevadm info, assumindo que você saiba onde o seu drive de polegar está atualmente localizado na sua árvore /dev. Se não, desconecte e conecte seu drive de polegar de volta, então emita imediatamente este comando:

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

Se este comando retornar sdb: sdb1, por exemplo, você sabe que o kernel atribuiu ao seu drive de polegar a etiqueta sdb.

Alternately, você pode usar o comando lsblk para ver todas as unidades anexadas ao seu sistema, incluindo seus tamanhos e partições.

Agora você tenha estabelecido onde sua unidade está localizada no seu sistema de arquivos, você pode ver informações do udev sobre aquele dispositivo com este comando:

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

Isto retorna um monte de informações. Foque no primeiro bloco de informações por enquanto.

O seu trabalho é escolher partes do relatório do udev sobre um dispositivo que são mais exclusivas daquele dispositivo, então diga ao udev para acionar o seu script quando esses atributos exclusivos forem detectados.

O processo de informações do udevm relata sobre um dispositivo (especificado pelo caminho do dispositivo), então “anda” pela cadeia de dispositivos pai. Para cada dispositivo encontrado, ele imprime todos os atributos possíveis usando um formato de valor chave. Você pode compor uma regra para combinar de acordo com os atributos de um dispositivo mais atributos de um único dispositivo pai.

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"

Uma regra udev deve conter um atributo de um único dispositivo pai.

Atributos parentais são coisas que descrevem um dispositivo a partir do nível mais básico, tal como é algo que foi conectado a uma porta física ou é algo com um tamanho ou este é um dispositivo removível.

Desde que a etiqueta KERNEL da sdb pode mudar dependendo de quantas outras unidades foram conectadas antes de você conectar essa unidade de polegar, esse não é o atributo pai ideal para uma regra udev. No entanto, funciona para uma prova de conceito, para que você possa usá-la. Um candidato ainda melhor é o atributo SUBSYSTEM, que identifica que este é um dispositivo de sistema “block” (e é por isso que o comando lsblk lista o dispositivo).

Abra um ficheiro chamado 80-local.rules em /etc/udev/rules.d e digite este código:

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

Salve o arquivo, desconecte sua unidade de teste e reinicie.

Espere, reinicie em uma máquina Linux?

Teóricamente, você pode apenas emitir controle udevadm –reload, que deve carregar todas as regras, mas neste estágio do jogo, é melhor eliminar todas as variáveis. O udev é suficientemente complexo, e você não quer ficar deitado na cama a noite toda pensando se essa regra não funcionou por causa de um erro de sintaxe ou se você simplesmente deveria ter reiniciado. Então reinicie independentemente do que o seu orgulho POSIX lhe disser.

Quando o seu sistema estiver novamente online, mude para uma consola de texto (com Ctl+Alt+F3 ou similar) e ligue a sua drive de polegar. Se você estiver rodando um kernel recente, você provavelmente verá um monte de saída no seu console quando você conectar a unidade. Se você vir uma mensagem de erro como Não foi possível executar /usr/local/bin/trigger.sh, você provavelmente esqueceu de tornar o script executável. Caso contrário, esperançosamente tudo o que você vê é um dispositivo que foi plugado, ele recebeu algum tipo de atribuição de dispositivo do kernel, e assim por diante.

Agora, o momento da verdade:

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

Se você vir uma data e hora muito recente retornada de /tmp/udev.log, o udev acionou com sucesso o seu script.

Refining the rule into something useful

O problema com esta regra é que ela é muito genérica. Conectar um mouse, uma unidade de polegar ou a unidade de polegar de outra pessoa irá acionar indiscriminadamente o seu script. Agora é a hora de começar a focar na unidade de polegar exata que você quer acionar seu script.

Uma maneira de fazer isso é com a ID do fornecedor e ID do produto. Para obter estes números, você pode usar o 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

Neste exemplo, o 03f0:3307 antes da TyCoon Corp. denota os atributos idVendor e idProduct. Você também pode ver estes números na saída do udevadm info -a -n /dev/sdb | grep vendor, mas eu acho a saída do lsusb um pouco mais fácil aos olhos.

Você pode agora incluir estes atributos na sua regra.

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

Teste isto (sim, você ainda deve reiniciar, apenas para ter certeza que você está recebendo novas reações do udev), e deve funcionar como antes, apenas agora se você conectar, digamos, uma unidade de polegar fabricada por uma empresa diferente (portanto com um idVendor diferente) ou um mouse ou uma impressora, o script não será acionado.

Calme-se adicionando novos atributos para focar ainda mais naquela unidade de polegar única que você quer acionar seu script. Usando udevadm info -a -n /dev/sdb, você pode descobrir coisas como o nome do fornecedor, às vezes um número de série, ou o nome do produto, e assim por diante.

Para sua própria sanidade, certifique-se de adicionar apenas um novo atributo de cada vez. A maioria dos erros que eu cometi (e vi outras pessoas online cometerem) é atirar um monte de atributos para a regra do udev e me perguntar por que a coisa não funciona mais. Testar atributos um por um é a maneira mais segura de garantir que o udev possa identificar seu dispositivo com sucesso.

Segurança

Isso traz à tona as preocupações de segurança de escrever regras do udev para fazer algo automaticamente quando uma unidade é conectada. Nas minhas máquinas, eu nem sequer tenho a montagem automática ligada, e ainda assim este artigo propõe scripts e regras que executam comandos apenas por ter algo ligado.

Duas coisas a ter em mente aqui.

  1. Focalize as suas regras udev uma vez que as tenha a funcionar de modo a activar os scripts apenas quando realmente as quiser. Executar um script que copia cegamente dados de ou para o seu computador é uma má ideia no caso de alguém que carregue a mesma marca de unidade de polegar o ligar à sua caixa.
  2. Não escreva as suas regras e scripts udev e esqueça-os. Eu sei quais computadores têm as minhas regras udev, e essas caixas são na maioria das vezes os meus computadores pessoais, não os que levo para conferências ou tenho no meu escritório no trabalho. Quanto mais “social” for um computador, menos provável é que ele tenha uma regra udev que possa resultar em meus dados acabarem no dispositivo de outra pessoa ou nos dados ou malware de outra pessoa no meu dispositivo.

Em outras palavras, como com tanto poder fornecido por um sistema GNU, é seu trabalho estar atento a como você está empunhando esse poder. Se você abusar dele ou falhar em tratá-lo com respeito, ele pode muito bem dar horrivelmente errado.

Udev no mundo real

Agora que você possa confirmar que seu script é acionado pelo udev, você pode voltar sua atenção para a função do script. Neste momento, é inútil, não fazendo nada mais do que registar o facto de ter sido executado.

Udev para accionar backups automáticos das minhas unidades do polegar. A idéia é que as cópias-mestras dos meus documentos ativos estão na minha unidade de polegar (já que ela vai aonde quer que eu vá e pode ser trabalhada a qualquer momento), e esses documentos-mestras são copiados para o meu computador toda vez que eu conecto a unidade àquela máquina. Em outras palavras, meu computador é a unidade de backup e meus dados de produção são móveis. O código fonte está disponível, por isso sinta-se à vontade para ver o código de anexação para mais exemplos de como restringir os seus testes udev.

Desde que é para isso que eu mais uso o udev, é o exemplo que vou usar aqui, mas o udev pode pegar muitas outras coisas, como gamepads (isto é útil em sistemas que não estão configurados para carregar o módulo xboxdrv quando um gamepad está conectado) e câmeras e microfones (útil para configurar entradas quando um microfone específico está conectado), então perceba que é bom para muito mais do que este exemplo.

Uma versão simples do meu sistema de backup é um processo de dois comandos:

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

A primeira linha detecta a minha unidade de polegar com os atributos já discutidos, depois atribui à unidade de polegar um link simbólico dentro da árvore de dispositivos. O symlink que ele atribui é safety%n. A %n é uma macro udev que resolve para qualquer número que o kernel der ao dispositivo, como sdb1, sdb2, sdb3, e assim por diante. Então %n seria o 1 ou o 2 ou o 3.

Isto cria um link simbólico na árvore dev, para não interferir com o processo normal de ligar um dispositivo. Isto significa que se você usar um ambiente desktop que gosta de montar dispositivos automaticamente, você não estará causando problemas para ele.

A segunda linha executa o script.

O meu script de backup fica assim:

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

O script usa o symlink, o que evita a possibilidade de udev nomear a unidade algo inesperado (por exemplo, se eu já tiver uma unidade de polegar chamada DISK ligada ao meu computador, e eu ligar a minha outra unidade de polegar também chamada DISK, a segunda será rotulada de DISK_, o que iria enganchar o meu script). Ele monta segurança1 (a primeira partição da unidade) no meu ponto de montagem preferido de /mnt/hd.

Once seguramente montado, ele usa rsync para fazer o backup da unidade para minha pasta de backup (meu script atual usa rdiff-backup, e o seu pode usar qualquer solução de backup automatizada que você preferir).

Udev é seu dev

Udev é um sistema muito flexível e permite que você defina regras e funções de maneiras que poucos outros sistemas ousam fornecer aos usuários. Aprenda-o e use-o, e desfrute do poder do POSIX.

Este artigo é baseado no conteúdo do Manual Slackermedia, que é licenciado sob a Licença de Documentação Livre GNU 1.3.

Deixe uma resposta

O seu endereço de email não será publicado.