Detecção e ativação de dispositivos e a função do udev nesse processo
IntroduçãoUdev (Userspace devfs) é um sistema de arquivos presente desde o kernel 2.6 e substitui o devfs completamente. É responsável por gerenciar os arquivos de dispositivos do diretório /dev, criando e removendo os mesmos dinamicamente. O udev também tem função do hotplug, trabalhando em conjunto com o HAL (Hardware Abstraction Layer), adicionando os dispositivos conforme são instalados na máquina. Sem ele, seria impossível acessar seu pendrive, webcam e impressora, por exemplo, quando conectados. FuncionamentoEntendendo como os dispositivos são detectados e adicionados no sistema GNU/Linux. O sistema GNU/Linux faz uso do kernel e de serviços para detectar e adicionar dispositivos ao sistema, para que os mesmos fiquem disponíveis para uso do usuário e do próprio sistema. Abaixo, é mostrada a hierarquia no processo de detecção e adição de dispositivos: Como visto na figura acima, existe todo um processo até os dispositivos estarem disponíveis para uso do sistema e/ou usuários, que vai desde a detecção do device pelo kernel até a criação de um arquivo de dispositivo no diretório /dev pelo udev. Todo processo começa com o kernel detectando os dispositivos e exportando informações sobre os mesmos para o sistema de arquivos virtual Sysfs (que está montado no diretório /sys) e ao mesmo tempo, enviando um evento para o daemon do serviço udev. O evento informa ao udev uma ação no dispositivo, esta ação pode ser um adição, remoção ou alteração de um dispositivo conectado à máquina. Quando o udev é informado pelo kernel sobre o evento, trata de usar as informações do diretório /sys para identificar o device conectado, carregar o módulo correto e criar um arquivo especial no diretório /dev com exceção da placa de rede que é tratada no kernel. Aí você pergunta: E o HAL? Simples, o HAL é um serviço que informa aos programas do sistema se um dispositivo está disponível, foi alterado ou removido a todo tempo. Na verdade, o HAL já não é essencial para este trabalho, pois algumas distribuições atualmente, conseguem fazer todo este trabalho somente pelo udev, ou em conjunto com o serviço D-Bus. No entanto, para outras distribuições, isso torna-se essencial. É importante destacar que todo este processo de detectar e ativar os devices explicado anteriormente, não só acontece em Hotplug, ou seja, os dispositivos são instalados com o sistema em uso, mas também em Coldplug, os dispositivos são conectados (instalados) com a máquina desligada e o sistema, quando em uso, detecta-os. Observe que quem realmente faz o trabalho de hotplug, é o udev. Os arquivos de dispositivos criados no diretório /dev nada mais são que arquivos especiais, obtidos pela combinação de dois endereços do kernel, um chamado de major number e outro de minor number. Sendo que:
Veja na figura abaixo, um exemplo destes números: |
||||
Hierarquia dos dispositivos e chaves do udev
Hierarquia dos dispositivosAntes de começar a trabalhar com regras no udev, é necessário saber como o kernel representa os dispositivos em sua estrutura. O kernel do Linux organiza e representa os dispositivos conectados à máquina em uma estrutura de árvore, ou seja, existe uma hierarquia onde cada device é “filho” de um device “pai”. Toda esta estrutura está exposta no diretório /sys contendo informações de cada device. Para poder ter mais detalhes sobre os devices, use o comando udevadm e poderá ver todas as chaves dos dispositivos. Veja o exemplo do arquivo de dispositivo /dev/usb/lp0 da minha máquina, que representa a impressora, rodando o comando abaixo como root: # udevadm info -a -p $(sudo udevadm info -q path -n /dev/usb/lp0) A saída do comando mostra bem a organização e hierarquia do device. Sendo que /dev/usb/lp0 é filho do device “usb”, e neste device o kernel nomeia-o de “lp0”, justamente o nome dado pelo udev, que por sua vez é filho do device pai, também chamado de “usb” e o kernel nomeia-o de “2-2:1.1”, carregando o driver “usblp”, que por sua vez é filho do device “pci” e o kernel nomeia-o neste subsistema de “0000:00:1d.0”, carregando o driver “uhci_hcd”. Veja o exemplo do arquivo de dispositivo /dev/sda que representa o primeiro disco rígido da minha máquina: # udevadm info -a -p $(sudo udevadm info -q path -n /dev/sda) O device /dev/sda nesta hierarquia, é filho do device “block”, ou seja, é um dispositivo de bloco e o kernel nomeia-o de “sda”, que por sua vez, é filho do device chamado de “scsi”, e o kernel nomeia-o de “0:0:0:0”, carregando o driver “sd”, que por sua vez é filho do device chamado também de “scsi”, e o kernel nomeia-o de “target0:0:0”. Observe que, na hierarquia mostrada na saída do comando udevadm, os devices de baixo são pais dos de cima “filhos”. As chaves do udevChaves no udev são informações de dispositivos e podem ser classificadas em dois tipos, existindo as chaves de combinação e de atributos. Ambas serão abordadas a seguir, e o seu uso torna-se necessário para aplicar as regras do udev. As chaves de combinação mais usadas, são as listadas abaixo:
Além das chaves de combinação já vistas, é possível usar outras descritas abaixo:
Chaves de combinação KERNELS, SUBSYSTEMS e DRIVERS, contêm informações similares às chaves de combinação apresentadas acima, no entanto, estas chaves de combinação são usadas em dispositivos pais (parent devices). As chaves de atributo ATTR, contêm informação adicional a um dispositivo e a chave de atributo ATTRS é similar a ATTR, no entanto, é usada em devices pais (parent devices). A observação é que em uma regra, não pode ser atribuído mais de uma chave de atributo e/ou de combinação de dispositivos “pai” (device parent) junto à chave de combinação “filho” e nem combinar chaves de atributos de diferentes dispositivos pais em um único dispositivo pai. Caso isso aconteça, a regra não irá funcionar. Para a regra funcionar, podemos colocar uma ou mais chaves de combinação “filho” seguida de uma chave de atributo ou de combinação “pai” na mesma regra e/ou, caso queira atribuir mais de uma chave de atributo “pai”, é necessário informar o dispositivo a qual ela pertence, basta usar a chave de combinação “pai” SUBSYSTEMS. Se ficou confuso, na próxima página irei exemplificar para ter um melhor entendimento. Para aplicar as regras, além das chaves já mencionadas, podemos fazer uso de strings e é necessário usar operadores. Veja abaixo as strings e operadores que podemos usar. Strings que podem ser usadas nas regras:
Operadores mais usados nas regras:
Depois de toda esta explicação, vamos começar a aplicar as regras na próxima página. |
||||
Regras do udev
O udev é muito poderoso quanto à aplicação das regras, pois permite desde nomear um dispositivo até executar aplicações, e/ou scripts quando conectamos ou desconectamos, ou quando o dispositivo é alterado.
Para aplicar tais regras, é necessário ter informações obtidas através das chaves de cada device. Os arquivos que contém as regras do udev estão contidos no diretório /etc/udev/rules.d e devem ter a extensão “.rules”, caso algum arquivo dentro do diretório não use essa extensão, o seu conteúdo não será processado. Eles são lidos em ordem numérico alfabética, por exemplo: se dentro do diretório /etc/udev/rules.d, temos os arquivos “025_usb- regras.rules” e “035_usb-regras.rules”, o arquivo “025_usb-regras.rules” será lido antes que o “035_usb-regras.rules”. Agora, sintaxe das regras e exemplos de regras que funcionam e não funcionam. Cada arquivo com extensão “.rules” tem regras que seguem a seguinte sintaxe: <chave de combinação>, <chave de combinação e ou chave de atributo>, <Ação>
Para obter as informações de cada chave dos devices, usamos o comando udevadm para pegar um relatório. Não vou entrar em detalhes de uso do comando, mas deixo o link para o manual: Será usado, para extrair o relatório, a opção “info” que é utilizada para obter informações e “-p”, que indica a localização do dispositivo, e “-a” irá listar informações das propriedades do dispositivo. Vou listar as propriedades do arquivo de dispositivo /dev/sdc1 que é meu pendrive da SanDisk, usando o comando udevadm como root: # udevadm info -a -p $(udevadm info -q path -n /dev/sdc1)
Veja que não postei toda a saída do comando pois é muito longa. Agora, abaixo mostro duas regras: ACTION==”add”, SUBSYSTEM==”block”, KERNEL==”sd??”, ATTRS{vendor}==”SanDisk”, DRIVERS==”usb-storage”, SYMLINK+=”PENDRIVE”
ACTION==”add”, SUBSYSTEM==”block”, KERNEL==”sd??”, ATTRS{vendor}==”SanDisk”, SYMLINK+=”PENDRIVE” Ambas as regras têm a ação de criar um link para a partição do pendrive. No entanto, somente a segunda regra irá funcionar. Explicação da primeira regra:
Mesmo toda informação conferindo na primeira regra, não pode funcionar, pois foi atribuído junto à chave de combinação do dispositivo filho (como já foi informado na segunda página), uma chave de atributo (ATTRS) e outra de combinação (DRIVERS) de dispositivos “pais”. Deixo mais uma vez claro, que a regra não irá funcionar caso seja atribuído mais de uma chave de atributo ou de combinação de um parent device junto à uma chave de combinação de um device filho. A segunda regra tem quase todos as chaves da primeira regra, com exceção da chave de combinação DRIVERS de um dispositivo pai. E esta regra irá funcionar por que apenas uma chave, seja de atributo ou de combinação (no exemplo, uma foi de atributo) de dispositivo pai está atribuída junto às chaves de combinação do dispositivo filho que são ACTION, SUBSYSTEM e KERNEL. Agora, veja um exemplo de regra usada para executar um script: ACTION==”add”, SUBSYSTEM==”block”, KERNEL==”sd??”, SUBSYSTEMS==”usb”, RUN+=”/usr/local/bin/usb-mount.sh”
Veja que esta regra é similar às duas mostradas anteriormente. No entanto, o valor atribuído à chave de combinação SUBSYSTEM do dispositivo filho, indica que deve ser aplicada a um dispositivo de bloco, ou seja, de armazenamento. E a chave de combinação (do device parent) SUBSYSTEMS, indica que a regra só será aplicada a dispositivos pais do tipo USB; dessa forma, a regra só será aplicada a um pendrive, HD externo e/ou cartão de memória, e não a discos rígidos internos, por exemplo. Veja abaixo, o conteúdo do script /usr/local/bin/usb-mount.sh:
A finalidade do script é montar o pendrive, HD externo ou cartões de memória desabilitando a execução de executáveis, dando mais segurança quando “espetar” um destes dispositivos na máquina (afinal, nunca se sabe o que pode ter em um HD externo ou pendrive de alguém, não é verdade?) evitando a execução de vírus e outras pragas. Podemos também renomear dispositivos como placas de rede. Para ver como fazer isso, veja a saída do comando udevadm para o dispositivo Wlan0 e em seguida, irei mostrar uma regra para isso: # udevadm info -a -p /sys/class/net/wlan0
O adaptador USB está recebendo este nome de “wlan0” porque, quando o sistema o detectou, o udev atribuiu a regra abaixo: SUBSYSTEM==”net”, ACTION==”add”, DRIVERS==”?*”, ATTR{address}==”00:1a:3f:7c:2e:f4″, ATTR{dev_id}==”0x0″, ATTR{type}==”1″, KERNEL==”wlan*”, NAME=”wlan0″
Mas, com estas informações da saída do comando udevadm podemos mudar o nome do device para, por exemplo, Wireless0 como mostra a regra abaixo: SUBSYSTEM==”net”, ACTION==”add”, DRIVERS==”?*”, ATTR{address}==”00:1a:3f:7c:2e:f4″, ATTR{dev_id}==”0x0″, ATTR{type}==”1″, KERNEL==”*”, NAME=”wireless0″
Explicando a regra:
Podemos fazer muitas personalizações, além das quais já foram mostradas, podemos, por exemplo, automatizar um processo de backup toda vez que o dispositivo for conectado à máquina de forma similar à regra acima, que executa um script. Após aplicar uma regra em um dos arquivos com extensão “.rules”, torna-se necessário reiniciar o serviço do udev para as alterações entrarem em vigor (pelo menos nas distribuições Debian e CentOS, por exemplo). |