Utilisation de sysfs Organisation de sysfsL'utilisation de
sysfs a été brièvement évoqué précédemment. Dans le but d'écrire des règles basées sur ces informations, il vous faut connaître le nom des attributs et leurs valeurs.
Sysfs a une structure très simple. Il est logiquement divisé en répertoires, chacun contient un certain nombre de fichiers (
attributs) qui contiennent en général une seule valeur. Certains liens symboliques sont présents, parcourant plusieurs branches de "l'arbre"
sysfs.
Certains répertoires sont situés sur les niveaux supérieurs du dispositif. Le niveau supérieur lie d'autres parties de
sysfs vers le périphérique en question. Les chemins des périphériques du niveau supérieur sont classifiés dans le répertoire
sysfs, contenant un fichier dev. La commande suivante permet de les lister : find /sys -name dev
Par exemple, sur mon système, le répertoire /sys/block/sda est le chemin du périphérique de mon disque dur. Il est lié au contrôleur sur lequel celui-ci est connecté avec le lien symbolique /sys/block/sda/device/, qui en même temps est lié au pilote du périphérique avec le lien symbolique /sys/block/sda/device/driver/.
Quand vous écrivez des règles basées sur les informations de
sysfs, vous devez simplement remplacer les attributs par ceux trouvés dans ces fichiers. Par exemple, je peux lire la taille de mon disque dur avec : cat /sys/block/sda/size
234441648
Je peux donc utiliser dans une règle
udev ATTR{size}=="234441648" pour identifier ce disque. Comme
udev fait une recherche dans toute la branche du périphérique, je peux aussi choisir d'afficher une autre partie de cette branche (e.g. attributes dans /sys/class/block/sda/device/). Cependant il y a d'autres choses à prendre en considération quand on utilise d'autres parties de la branche, comme cela est décrit plus loin.
Bien que cela serve d'introduction utile pour la structure du
sysfs et pour comprendre le fonctionnement de
udev, le changement avec
sysfs est souvent une perte de temps qui n'est donc pas nécessaire.
udevinfoUdevinfo est probablement l'outil le plus puissant pour aider dans la construction des règles. Tout ce que vous devez connaître est la dénomination
sysfs du périphérique en question. Par exemple : udevinfo -a -p /sys/block/sda
------------------**INFORMATIONS DE TYPE 1**------------------
looking at device '/block/sda':
KERNEL=="sda"
SUBSYSTEM=="block"
ATTR{stat}==" 128535 2246 2788977 766188 73998 317300 3132216 5735004 0 516516 6503316"
ATTR{size}=="234441648"
ATTR{removable}=="0"
ATTR{range}=="16"
ATTR{dev}=="8:0"
------------------**INFORMATIONS DE TYPE 2**------------------
looking at device '/devices/pci0000:00/0000:00:07.0/host0/target0:0:0/0:0:0:0':
ID=="0:0:0:0"
BUS=="scsi"
DRIVER=="sd"
ATTR{ioerr_cnt}=="0x0"
ATTR{iodone_cnt}=="0x31737"
ATTR{iorequest_cnt}=="0x31737"
ATTR{iocounterbits}=="32"
ATTR{timeout}=="30"
ATTR{state}=="running"
ATTR{rev}=="3.42"
ATTR{model}=="ST3120827AS "
ATTR{vendor}=="ATA "
ATTR{scsi_level}=="6"
ATTR{type}=="0"
ATTR{queue_type}=="none"
ATTR{queue_depth}=="1"
ATTR{device_blocked}=="0"
Comme vous pouvez le voir, udevinfo renvoie une liste d'informations que vous pouvez utiliser dans vos règles
udev. Avec l'exemple précédant je peux créer deux règles pour ce périphérique : SUBSYSTEM=="block", ATTR{size}=="234441648", NAME="my_hard_disk"
BUS=="scsi", ATTR{model}=="ST3120827AS", NAME="my_hard_disk"
Dans ces exemple, vous avez pu voir la
séparation des informations (type 1 et type 2), car vous
ne pouvez
pas mélanger ces informations dans une règle, sinon elle ne fonctionnera pas. En effet, ils sont considérés comme des périphériques différents (looking at device '/block/sda' et looking at device '/devices/pci0000:00/0000:00:07.0/host0/target0:0:0/0:0:0:0' sont
deux périphériques
distincts).
Par exemple, cette règle est
invalide : # **règle fausse**
SUBSYSTEM=="block", ATTR{size}=="234441648", ATTR{model}=="ST3120827AS", NAME="my_hard_disk"
Normalement vous aurez beaucoup d'attributs, et vous devrez en choisir quelques uns (de la même section) pour construire votre règle. En général, vous voudrez choisir les attributs qui identifient votre périphérique de façon unique et persistante. Dans ces exemples j'ai choisi la taille et le numéro de série de mon disque. Je n'ai pas utilisé les nombres sans signification comme ATTR{iodone_cnt}=="0x31737".
Notez aussi que les attributs donnés par udevinfo sont séparés par des espaces (voyez ST3120827AS dans l'exemple précédent). Dans vos règles, vous pouvez spécifier les espaces supplémentaires, ou les couper comme je l'ai fait.
La où udevinfo se complique, c'est que vous devez connaître les branches supérieures (/sys/block/sda dans l'exemple précédant), ce qui n'est pas toujours évident. Cependant, comme en général vous écrivez des règles pour les périphériques "nodes" existants, vous pouvez utiliser
udev pour trouver la branche supérieure : udevinfo -a -p $(udevinfo -q path -n /dev/sda)
Méthodes AlternativesBien que udevinfo soit la méthode la plus sûre pour lister les attributs exacts pour construire vos règles, certains utilisateurs préféreront utiliser d'autres outils. Les outils comme usbview montrent des informations similaires, pouvant être utilisées pour créer des règles.
Le coin du geek Créer des permissions et des propriétésUdev vous permet de gérer dans vos règles les propriétés et les permissions de chaque périphérique.
La clef d'assignation GROUP vous permet de définir à quel groupe appartient un périphérique "node". Dans cet exemple, les périphériques
framebuffer appartiennent au groupe Video : KERNEL=="fb[0-9]*", NAME="fb/%n", SYMLINK+="%k", GROUP="video"
La clef OWNER, peut-être moins intéressante, vous permet de définir le propriétaire du périphérique "node". Dans cet exemple, l'utilisateur
John sera mis comme propriétaire pour les lecteurs de disquettes : KERNEL=="fd[0-9]*", OWNER="john"
Par défaut,
udev crée les permissions pour "node" avec les droits 0660 (lire/écrire pour tous les utilisateurs/groupes, vous pouvez trouver quelques informations sur ces chiffres dans la documentation de
chmod, avec la commande man chmod). Si c'est nécessaire, vous pouvez les modifier pour certains périphériques en utilisant les règles avec la clef d'assignation MODE. Cet exemple définit que le périphérique peut être utilisé par tout le monde : KERNEL=="inotify", NAME="misc/%k", SYMLINK+="%k", MODE="0666"
Utiliser des programmes pour nommer les périphériquesDans certaines circonstances, vous pouvez avoir besoin de plus de flexibilité que les règles
udev en donnent. Dans ce cas vous pouvez demander à
udev de lancer un programme, afin d'utiliser ce qui est sorti par ce programme pour créer le nom de périphérique.
Pour utiliser cette fonction, vous devez simplement spécifier la ligne de commande entière du programme à utiliser (ainsi que ses paramètres) dans la clef d'assignation PROGRAM, vous pouvez trouver des variantes d'utilisation du %c dans les sections
NAME/SYMLINK.
Les exemples suivants se référent a un programme fictif appelé /bin/device_namer. Ce device_namer prendrait un argument en ligne de commande, qui est le nom donné par le noyau au périphérique. À partir de ce nom, device_namer donnerait les informations sur sa sortie (stdout), séparées en plusieurs parties. Chaque partie est un seul mot et les parties sont séparées par un seul espace.
Dans ce premier exemple, nous considérons que les informations en sortie de device_namer sont un nombre de parties, chacune forme un lien symbolique pour le périphérique en question. KERNEL=="hda", PROGRAM="/bin/device_namer %k", SYMLINK+="%c"
L'exemple suivant considère que les informations en sortie de device_namer contiennent deux parties, la première est le nom du périphérique, et la seconde est le nom pour un lien symbolique additionnel. Nous introduisons maintenant la substitution %c{
N}, en référence au nombre de parties des informations en sortie : KERNEL=="hda", PROGRAM="/bin/device_namer %k", NAME="%c{1}", SYMLINK+="%c{2}"
Le prochain exemple considère que device_namer retourne le nom du périphérique, suivi par un nombre variable de liens symboliques. Pour accéder à ces derniers, nous introduisons la substitution %c{
N+}, qui sera remplacé par les parties
N,
N+1,
N+2… jusqu'à la dernière. KERNEL=="hda", PROGRAM="/bin/device_namer %k", NAME="%c{1}", SYMLINK+="%c{2+}"
Les réponses créées à partir de la sortie du programme peuvent être utilisées dans n'importe quelle clef d'assignation et pas seulement avec NAME et SYMLINK. L'exemple suivant utilise un programme fictif qui déterminerait le groupe qui doit avoir les droits de ce périphérique : KERNEL=="hda", PROGRAM="/bin/who_owns_device %k", GROUP="%c"
Exécuter des programmes sur des événementsUne autre raison d'écrire des règles
udev est de lancer un programme quand un périphérique est connecté ou déconnecté. Par exemple, vous voulez lancer un script qui va télécharger automatiquement les photos de votre appareil photo lorsque vous le connectez.
Ne confondez pas ceci avec la fonction PROGRAM décrite précédement. PROGRAM sert à lancer des programmes qui génèrent des noms de périphériques et rien d'autre. Quand ces programmes sont éxecutés, le périphérique "node" n'a pas encore été créé, donc faire une action sur ce périphérique n'est pas possible.
La fonction introduite ici vous permet de lancer un programme après la mise en place du périphérique. Ce programme peut interagir avec le périphérique, cependant il doit s'éxecuter rapidement car
udev est mis en pause quand ces programmes sont lancés. Il ne faut donc pas négliger de s'assurer que le programme s'arrête de lui même.
Voici un exemple de règle qui utilise l'assignation RUN : KERNEL=="sdb", RUN+="/usr/bin/my_program"
Quand /usr/bin/my_program est éxecuté, plusieurs informations de
udev sont accessibles par les variables d'environnement. Ceci inclue les clef comme SUBSYSTEM. Vous pouvez aussi utiliser la variable d'environnement ACTION pour détecter si le périphérique est connecté (valeur "add") ou déconnecté (valeur "remove").
Interactions avec l'environmentUdev fournit une clef ENV pour les variables d'environnement qui peut être utilisée à la fois pour
trouver et
assigner des variables.
Dans le cas d'une assignation, vous pouvez placer des variables d'environnement que vous pourrez retrouver par la suite. Vous pourrez aussi y acceder depuis les programmes externes lancés à l'aide des techniques décrites précédement. Voici un exemple de syntaxe de règle pour créer une variable d'environnement : KERNEL=="fd0", SYMLINK+="floppy", ENV{some_var}="value"
Dans le cas de la
recherche, vous pouvez vous assurer que les règles se lancent seulement selon une variable d'environnement. Notez que l'environnement que
udev voit ne sera pas le même que celui que l'utilisateur voit en console. Voici un exemple de règle : KERNEL=="fd0", ENV{an_env_var}=="yes", SYMLINK+="floppy"
Cette règle ne crée le lien /dev/floppy que si $an_env_var est égal à "yes" dans l'environnement
udev.
Options additionnellesLa clef OPTIONS est une liste d'options supplémentaire pour le traitement de la règle :
- all_partitions: crée autant de partitions que possible pour un disque, plutôt que seulement celles créés au démarrage;
- ignore_device: ignore complétement l'événement;
- last_rule: empêche l'éxécution des règles suivantes.
Par exemple, cette règle place mon disque dur dans le groupe disk et s'assure qu'aucune règle qui suit n'aura d'effet dessus : KERNEL=="sda", GROUP="disk", OPTIONS+="last_rule"