Règles udev

De ClissXXI.

Cette page décrit sommairement comment créer une règle udev qui permettra d'ajouter un lien symbolique vers une partition de périphérique USB lors de son insertion. Les outils donnés peuvent être spécifiques à la distribution Debian GNU/Linux, vous devrez peut-être les adapter à votre distribution.

Le nom de la partition insérée pouvant changer selon le nombre de périphériques branchés au système, cette technique permet ensuite de se référer à un nom fixe dans des fichiers de configuration ou des scripts (par exemple pour la sauvegarde vers un disque usb).

Sommaire

Constitution de la règle udev

Une règle udev permet de filtrer les périphériques selon différents attributs et de leur assigner un nom de périphérique, ajouter un lien symbolique vers le nom de périphérique, ou encore déclencher un script.

Recherche des attributs discriminents

Pour obtenir l'ensemble des attributs disponibles de votre partition, utilisez la commande udevadm info (c'était udevinfo sous Debian Lenny, avec un fonctionnement légèrement différent). Par exemple, pour obtenir les informations concernant la partition /dev/sdc1 (qui est une partition d'un disque dur USB), utilisez la commande suivante:

udevadm info --name=/dev/sdc1 --attribute-walk

Le résultat est assez verbeux, et donne les attributs associés à la partition, ainsi qu'aux éléments supérieurs dans la hiérarchie:

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.7/usb1/1-7/1-7:1.0/host4/target4:0:0/4:0:0:0/block/sdc/sdc1':
   KERNEL=="sdc1"
   SUBSYSTEM=="block"
   DRIVER==""
   ATTR{partition}=="1"
   ATTR{start}=="63"
   ATTR{size}=="1953520002"
   ATTR{alignment_offset}=="0"
   ATTR{stat}=="     226     1226     3120     1000   130108 15275120 30810568 102165568        0   704280 102166532"
   ATTR{inflight}=="       0        0"
 
 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host4/target4:0:0/4:0:0:0/block/sdc':
   KERNELS=="sdc"
   SUBSYSTEMS=="block"
   DRIVERS==""
   ATTRS{range}=="16"
   ATTRS{ext_range}=="256"
   ATTRS{removable}=="0"
   ATTRS{ro}=="0"
   ATTRS{size}=="1953525168"
   ATTRS{alignment_offset}=="0"
   ATTRS{capability}=="52"
   ATTRS{stat}=="     306     1265     4072     1968   130109 15275120 30810576 102165568        0   705248 102167500"
   ATTRS{inflight}=="       0        0"
 
 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host4/target4:0:0/4:0:0:0':
   KERNELS=="4:0:0:0"
   SUBSYSTEMS=="scsi"
   DRIVERS=="sd"
   ATTRS{device_blocked}=="0"
   ATTRS{type}=="0"
   ATTRS{scsi_level}=="3"
   ATTRS{vendor}=="WDC WD10"
   ATTRS{model}=="EARS-00Y5B1     "
   ATTRS{rev}=="0A80"
   ATTRS{state}=="running"
   ATTRS{timeout}=="30"
   ATTRS{iocounterbits}=="32"
   ATTRS{iorequest_cnt}=="0x1fdad"
   ATTRS{iodone_cnt}=="0x1fdad"
   ATTRS{ioerr_cnt}=="0x0"
   ATTRS{modalias}=="scsi:t-0x00"
   ATTRS{evt_media_change}=="0"
   ATTRS{queue_depth}=="1"
   ATTRS{queue_type}=="none"
   ATTRS{max_sectors}=="240"
 
 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host4/target4:0:0':
   KERNELS=="target4:0:0"
   SUBSYSTEMS=="scsi"
   DRIVERS==""
 
 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host4':
   KERNELS=="host4"
   SUBSYSTEMS=="scsi"
   DRIVERS==""
 
 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0':
   KERNELS=="1-7:1.0"
   SUBSYSTEMS=="usb"
   DRIVERS=="usb-storage"
   ATTRS{bInterfaceNumber}=="00"
   ATTRS{bAlternateSetting}==" 0"
   ATTRS{bNumEndpoints}=="02"
   ATTRS{bInterfaceClass}=="08"
   ATTRS{bInterfaceSubClass}=="06"
   ATTRS{bInterfaceProtocol}=="50"
   ATTRS{modalias}=="usb:v152Dp2338d0100dc00dsc00dp00ic08isc06ip50"
   ATTRS{supports_autosuspend}=="0"
   ATTRS{interface}=="MSC Bulk-Only Transfer"
 
 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb1/1-7':
   KERNELS=="1-7"
   SUBSYSTEMS=="usb"
   DRIVERS=="usb"
   ATTRS{configuration}=="USB Mass Storage"
   ATTRS{bNumInterfaces}==" 1"
   ATTRS{bConfigurationValue}=="1"
   ATTRS{bmAttributes}=="c0"
   ATTRS{bMaxPower}=="  2mA"
   ATTRS{urbnum}=="1935520"
   ATTRS{idVendor}=="152d"
   ATTRS{idProduct}=="2338"
   ATTRS{bcdDevice}=="0100"
   ATTRS{bDeviceClass}=="00"
   ATTRS{bDeviceSubClass}=="00"
   ATTRS{bDeviceProtocol}=="00"
   ATTRS{bNumConfigurations}=="1"
   ATTRS{bMaxPacketSize0}=="64"
   ATTRS{speed}=="480"
   ATTRS{busnum}=="1"
   ATTRS{devnum}=="2"
   ATTRS{version}==" 2.00"
   ATTRS{maxchild}=="0"
   ATTRS{quirks}=="0x0"
   ATTRS{authorized}=="1"
   ATTRS{manufacturer}=="JMicron"
   ATTRS{product}=="USB to ATA/ATAPI Bridge"
   ATTRS{serial}=="D57CA6530749"
 
 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb1':
   KERNELS=="usb1"
   SUBSYSTEMS=="usb"
   DRIVERS=="usb"
   ATTRS{configuration}==""
   ATTRS{bNumInterfaces}==" 1"
   ATTRS{bConfigurationValue}=="1"
   ATTRS{bmAttributes}=="e0"
   ATTRS{bMaxPower}=="  0mA"
   ATTRS{urbnum}=="45"
   ATTRS{idVendor}=="1d6b"
   ATTRS{idProduct}=="0002"
   ATTRS{bcdDevice}=="0206"
   ATTRS{bDeviceClass}=="09"
   ATTRS{bDeviceSubClass}=="00"
   ATTRS{bDeviceProtocol}=="00"
   ATTRS{bNumConfigurations}=="1"
   ATTRS{bMaxPacketSize0}=="64"
   ATTRS{speed}=="480"
   ATTRS{busnum}=="1"
   ATTRS{devnum}=="1"
   ATTRS{version}==" 2.00"
   ATTRS{maxchild}=="8"
   ATTRS{quirks}=="0x0"
   ATTRS{authorized}=="1"
   ATTRS{manufacturer}=="Linux 2.6.32-5-686 ehci_hcd"
   ATTRS{product}=="EHCI Host Controller"
   ATTRS{serial}=="0000:00:1d.7"
   ATTRS{authorized_default}=="1"
 
 looking at parent device '/devices/pci0000:00/0000:00:1d.7':
   KERNELS=="0000:00:1d.7"
   SUBSYSTEMS=="pci"
   DRIVERS=="ehci_hcd"
   ATTRS{vendor}=="0x8086"
   ATTRS{device}=="0x27cc"
   ATTRS{subsystem_vendor}=="0x1043"
   ATTRS{subsystem_device}=="0x8179"
   ATTRS{class}=="0x0c0320"
   ATTRS{irq}=="23"
   ATTRS{local_cpus}=="ffffffff"
   ATTRS{local_cpulist}=="0-31"
   ATTRS{modalias}=="pci:v00008086d000027CCsv00001043sd00008179bc0Csc03i20"
   ATTRS{enable}=="1"
   ATTRS{broken_parity_status}=="0"
   ATTRS{msi_bus}==""
   ATTRS{companion}==""
 
 looking at parent device '/devices/pci0000:00':
   KERNELS=="pci0000:00"
   SUBSYSTEMS==""
   DRIVERS==""

Constitution de la règle udev

Vous pouvez ensuite choisir les attributs que vous voulez tester dans la règle, que ce soit des attributs de la partition ou d'un de ses parents dans la chaine. Attention à être le plus discriminant possible pour éviter que la règle ne s'applique qu'aux périphériques voulus.

Les règles doivent figurer dans un fichier du répertoire /etc/udev/rules.d, qu'on pourra par exemple nommé 99-local.rules (les fichiers sont préfixés par un numéro pour fixer explicitement l'ordre de prise en compte des règles).

Dans la règle ci-dessous, on ne sélectionne que les périphériques de type block représentant une partition sur un périphérique USB Mass Storage, sont le serial est D57CA6530750 :

SUBSYSTEM=="block", ATTR{partition}=="1", ATTRS{configuration}=="USB Mass Storage", ATTRS{serial}=="D57CA6530750", SYMLINK+="heden"

À noter:

  • les règles sont exécutées aussi bien à la connexion qu'à la déconnexion du périphérique. L'attribut ACTION vaudra respectivement "add" ou "remove" selon les cas;
  • l'opérateur « == » désigne le test d'un attribut qui doit être égal à la valeur donnée entre parenthèse. D'autres opérateurs sont disponibles, comme « != » (reportez-vous à la documentation pour les détails);
  • le « += » après SYMLINK permet d'ajouter un lien symbolique (en plus des liens symboliques qui sont automatiquement créés par le système). Remplacez-le par « = » pour ne pas créer les autres liens symbolique prévus par le système;
  • au lieu de création d'un nouveau lien symbolique, on peut aussi changer le nom de périphérique qui sera assigné par le système. Ainsi, au lieu de /dev/sdc1, on pourrait nommer le périphérique /dev/mondisqueusb en ajoutant en fin de règle « NAME="disqueusb" », ce qui donnerait:
 SUBSYSTEM=="block", ATTR{partition}=="1", ATTRS{configuration}=="USB Mass Storage", ATTRS{serial}=="D57CA6530750", NAME="disqueusb", SYMLINK+="heden"
  • on peut aussi choisir de lancer un script ou un programme lors de la détection de ce périphérique (ça peut être pratique pour télécharger toutes les photos d'un appareil photo dès sa connexion, par exemple). Les attributs associés au périphérique seront disponibles dans l'environnement du programme (s'il s'agit d'un script shell, la commande printenv > /tmp/UDEV_ENV retournera les attributs dans le fichier /tmp/UDEV_ENV). On pourra notamment détecter si le périphérique a été branché ou débranché selon la valeur de ACTION. Attention, le script ne doit pas être trop long à s'exécuter car udev est bloqué pendant ce temps (ou assurez-vous que le programme se détache rapidement). Modifier l'attribut RUN pour désigner le programme à exécuter:
 SUBSYSTEM=="block", ATTR{partition}=="1", ATTRS{configuration}=="USB Mass Storage", ATTRS{serial}=="D57CA6530750", NAME="disqueusb", RUN+="/usr/bin/my_program"

Recharger le périphérique

Pour tester le fonctionnement de la règle, vous pouvez bien sûr redémarrer la machine (dans le cas d'un périphérique fixe comme un disque dur interne) ou débrancher puis rebrancher le périphérique (s'il s'agit d'un périphérique externe comme un disque usb), ou utiliser la commande suivante (si votre périphérique s'appelle /dev/sda1). La désignation du périphérique se fait ici par son chemin, donné également par udevadm info ci-dessus.

udevadm test /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host4/target4:0:0/4:0:0:0/block/sdc/sdc1

Informations complémentaires

  • udev sur le wiki debian
  • writing udev rules, un document complet sur les règles udev, qui date un peu (c'estla commande udevinfo qui est utilisée, et non udevadm comme ici), mais qui donne des précisions sur l'écriture des règles (en anglais)
Outils personnels