I Introduction

L’objectif est de pouvoir lancer un script à l’insertion d’une clef USB. Script pouvant effectuer une sauvegarde de données, une copie ou lancer un processus particulier.

II Présentation rapide de UDEV

UDEV est mis en œuvre depuis les versions Linux supérieures à 2.6 (cat /proc/version). C’est un gestionnaire de périphériques qui permet la détection voire l’installation lorsqu’un nouveau est inséré.

UDEV utilise Sysfs également mis en œuvre à partir du noyau 2.6. Ce dernier inscrit dans le répertoire /sys tous les périphériques détectés par le noyau linux.

Lorsqu’un disque est détecté, UDEV fixe plusieurs noms. Ils sont placés dans /dev/disk et pour chaque référence un lien symbolique est fait vers le fichier périphérique :

xavior@mon_pc:~/scripts/udev$ tree /dev/disk/
/dev/disk/
├── by-id
│   ├── nvme-CT1000P5PSSD8_2135313D2BC8 -> ../../nvme0n1
│   ├── nvme-CT1000P5PSSD8_2135313D2BC8-part1 -> ../../nvme0n1p1
│   ├── nvme-CT1000P5PSSD8_2135313D2BC8-part2 -> ../../nvme0n1p2
│   ├── nvme-CT1000P5PSSD8_2135313D2BC8-part3 -> ../../nvme0n1p3
│   ├── nvme-CT1000P5PSSD8_2135313D2BC8-part4 -> ../../nvme0n1p4
│   ├── nvme-CT1000P5PSSD8_2135313D2BC8-part5 -> ../../nvme0n1p5
│   ├── nvme-eui.000000000000000100a07521313d2bc8 -> ../../nvme0n1
│   ├── nvme-eui.000000000000000100a07521313d2bc8-part1 -> ../../nvme0n1p1
│   ├── nvme-eui.000000000000000100a07521313d2bc8-part2 -> ../../nvme0n1p2
│   ├── nvme-eui.000000000000000100a07521313d2bc8-part3 -> ../../nvme0n1p3
│   ├── nvme-eui.000000000000000100a07521313d2bc8-part4 -> ../../nvme0n1p4
│   ├── nvme-eui.000000000000000100a07521313d2bc8-part5 -> ../../nvme0n1p5
│   ├── usb-General_USB_Flash_Disk_AA00000000013411-0:0 -> ../../sda
│   ├── usb-General_USB_Flash_Disk_AA00000000013411-0:0-part1 -> ../../sda1
│   └── usb-General_USB_Flash_Disk_AA00000000013411-0:0-part2 -> ../../sda2
├── by-label
│   ├── EFI-USB -> ../../sda1
│   └── GRUB-SOS -> ../../sda2
├── by-partlabel
│   ├── Basic\x20data\x20partition -> ../../nvme0n1p3
│   ├── EFI-USB -> ../../sda1
│   ├── EFI\x20system\x20partition -> ../../nvme0n1p1
│   ├── GRUB-SOS -> ../../sda2
│   └── Microsoft\x20reserved\x20partition -> ../../nvme0n1p2
├── by-partuuid
│   ├── 3eb7f155-14ef-47c5-9b9c-431a2a1288a0 -> ../../nvme0n1p2
│   ├── 3f6e7377-15e6-4d8e-8b78-5a3e60c7fc66 -> ../../sda1
│   ├── 7618d45d-2513-46c4-8c4e-85159a05db05 -> ../../nvme0n1p5
│   ├── 98a46934-67d7-4d04-8255-3672e33994c4 -> ../../nvme0n1p3
│   ├── a6881757-9e91-4f77-a28f-75c63e88e381 -> ../../nvme0n1p4
│   ├── ab7d9f47-7c39-4956-86d8-546bcd7db63c -> ../../nvme0n1p1
│   └── f6c7c1ae-1fd3-4819-8a8e-f3a16f9def3c -> ../../sda2
├── by-path
│   ├── pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0 -> ../../sda
│   ├── pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0-part1 -> ../../sda1
│   ├── pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0-part2 -> ../../sda2
│   ├── pci-0000:03:00.0-nvme-1 -> ../../nvme0n1
│   ├── pci-0000:03:00.0-nvme-1-part1 -> ../../nvme0n1p1
│   ├── pci-0000:03:00.0-nvme-1-part2 -> ../../nvme0n1p2
│   ├── pci-0000:03:00.0-nvme-1-part3 -> ../../nvme0n1p3
│   ├── pci-0000:03:00.0-nvme-1-part4 -> ../../nvme0n1p4
│   └── pci-0000:03:00.0-nvme-1-part5 -> ../../nvme0n1p5
└── by-uuid
    ├── 06F242C3F242B729 -> ../../nvme0n1p4
    ├── 1e6402aa-22a8-4774-ba35-ea349e77b9a0 -> ../../nvme0n1p2
    ├── 3b9c95e0-5e8c-4f2b-a71d-3d247c311e9b -> ../../nvme0n1p5
    ├── 46484D6A5D2880DC -> ../../sda2
    ├── 4CB8-B0FE -> ../../nvme0n1p1
    ├── 5055-11ED -> ../../sda1
    └── 7466C75E66C7202A -> ../../nvme0n1p3

Pour cela UDEV utilise des règles déjà existantes à l’installation du système. Elles se trouvent dans le répertoire /lib/udev/rules.d :

xavior@mon_pc:/lib/udev/rules.d$ ls
39-usbmuxd.rules                  60-serial.rules                        75-net-description.rules                  80-iio-sensor-proxy.rules
40-usb-media-players.rules        60-tpm-udev.rules                      75-probe_mtd.rules                        80-libinput-device-groups.rules
40-usb_modeswitch.rules           60-virtualbox-dkms.rules               77-mm-broadmobi-port-types.rules          80-mm-candidate.rules
40-vm-hotadd.rules                60-virtualbox-guest-utils.rules        77-mm-cinterion-port-types.rules          80-net-setup-link.rules
50-apport.rules                   60-virtualbox.rules                    77-mm-dell-port-types.rules               80-udisks2.rules
50-firmware.rules                 61-autosuspend-manual.rules            77-mm-dlink-port-types.rules              81-net-dhcp.rules
50-udev-default.rules             61-gdm.rules                           77-mm-ericsson-mbm.rules                  84-nm-drivers.rules
55-dm.rules                       61-gnome-settings-daemon-rfkill.rules  77-mm-fibocom-port-types.rules            85-brltty.rules
55-ippusbxd.rules                 61-persistent-storage-android.rules    77-mm-foxconn-port-types.rules            85-hdparm.rules
56-hpmud.rules                    64-btrfs.rules                         77-mm-gosuncn-port-types.rules            85-hplj10xx.rules
56-lvm.rules                      64-xorg-xkb.rules                      77-mm-haier-port-types.rules              85-nm-unmanaged.rules
60-autosuspend-chromiumos.rules   65-libwacom.rules                      77-mm-huawei-net-port-types.rules         85-regulatory.rules
60-block.rules                    66-snapd-autoimport.rules              77-mm-longcheer-port-types.rules          90-alsa-restore.rules
60-cdrom_id.rules                 69-cd-sensors.rules                    77-mm-mtk-port-types.rules                90-bolt.rules
60-crda.rules                     69-libmtp.rules                        77-mm-nokia-port-types.rules              90-console-setup.rules
60-drm.rules                      69-lvm-metad.rules                     77-mm-pcmcia-device-blacklist.rules       90-fwupd-devices.rules
60-evdev.rules                    69-wacom.rules                         77-mm-qdl-device-blacklist.rules          90-libgpod.rules
60-fido-id.rules                  70-joystick.rules                      77-mm-quectel-port-types.rules            90-libinput-fuzz-override.rules
60-inputattach.rules              70-mouse.rules                         77-mm-sierra.rules                        90-nm-thunderbolt.rules
60-input-id.rules                 70-nvmf-autoconnect.rules              77-mm-simtech-port-types.rules            90-pulseaudio.rules
60-libfprint-2.rules              70-power-switch.rules                  77-mm-telit-port-types.rules              95-cd-devices.rules
60-libgphoto2-6.rules             70-printers.rules                      77-mm-tplink-port-types.rules             95-dm-notify.rules
60-libsane.rules                  70-spice-vdagentd.rules                77-mm-ublox-port-types.rules              95-upower-csr.rules
60-pcmcia.rules                   70-touchpad.rules                      77-mm-usb-device-blacklist.rules          95-upower-hidpp.rules
60-persistent-alsa.rules          70-u2f.rules                           77-mm-usb-serial-adapters-greylist.rules  95-upower-hid.rules
60-persistent-input.rules         70-uaccess.rules                       77-mm-x22x-port-types.rules               95-upower-wup.rules
60-persistent-storage-dm.rules    71-power-switch-proliant.rules         77-mm-zte-port-types.rules                96-e2scrub.rules
60-persistent-storage.rules       71-seat.rules                          78-graphics-card.rules                    97-hid2hci.rules
60-persistent-storage-tape.rules  71-u-d-c-gpu-detection.rules           78-sound-card.rules                       99-systemd.rules
60-persistent-v4l.rules           73-seat-late.rules                     80-debian-compat.rules
60-sensor.rules                   73-special-net-names.rules             80-drivers.rules

Pour intégrer ses propres règles, le répertoire suivant est à utiliser : /etc/udev/rules.d

Le nom de fichier doit avoir l’extension ».rules ». Les fichiers sont pris en compte par ordre alphabétique. Ainsi le nom suivant pouvant être utilisé « 10-local.rules« .

III Ecriture de règles UDEV personnalisées

III.1 Une règle

Un règle comporte des clefs qui permettent :

  • de rechercher spécifiquement un périphérique :
    • « KERNEL »
    • « SUBSYSTEM »
    • « DRIVER »
    • « ENV{key} » –> clé/valeur de UDEV
    • « ATTR {key} » –> clé/valeur de Sysfs
    • « ATTR{filename} »
    • « ACTION »
    • « DEVPATH »
    • « SYMLINK »
    • « SYSCTL{kernel parameter} »
    • « TAG »
  • de définir des actions :
    • « NAME »
    • « SYMLINK »
    • « OWNER, GROUP, MODE »
    • « SECLABEL »
    • « ATTR{Key} »
    • « SYSCTL{Key} »
    • « ENV{key} »
    • « RUN{type} »

III.2 Les opérateurs

Les opérateurs permettent de définir soit une recherche soit une affectation et qui sont :

OpérateurSignification
==égalité
!=non égalité
=affecte valeur
-=enlève valeur
:=affecte valeur puis non modifiable ensuite
+=ajoute une nouvelle valeur

III.3 Exemple de règles simples permettant l’exécution d’un script

III.3.1 Exemple 1 : détection d’ajout d’un périphérique

Première règle pour voir ce qui se passe :

ACTION=="add", RUN+="/bin/sh  -c '/bin/echo %k : %p >> /home/xavior/events.log'"

Cette règle va loguer tout les ajouts de périphériques :

  • filtre : « ACTION== »add »
  • action : RUN+= »/bin/sh -c ‘/bin/echo %k : %p >> /home/xavior/events.log' »

Pour être sûr que la règle soit prise en compte :

sudo udevadm control --reload-rules

ce qui donne le résultat suivant en branchant une clef USB :

xavior@mon_pc:~$ cat events.log
scsi_tmf_0 : /devices/virtual/workqueue/scsi_tmf_0
2-3 : /devices/pci0000:00/0000:00:14.0/usb2/2-3
2-3:1.0 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0
host0 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0
host0 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/scsi_host/host0
target0:0:0 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0
0:0:0:0 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0
0:0:0:0 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/bsg/0:0:0:0
sg0 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/scsi_generic/sg0
0:0:0:0 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/scsi_disk/0:0:0:0
0:0:0:0 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/scsi_device/0:0:0:0
8:0 : /devices/virtual/bdi/8:0
sda : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda
sda1 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1
sda2 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2
8:2-fuseblk : /devices/virtual/bdi/8:2-fuseblk

Comme on peut le voir, des paramètres ont été récupérés de UDEV et affiché par le script shell:

  • « %k » –> le nom donnée par le Kernel pour le périphérique trouvé
  • « %p » –> le chemin du périphérique

Il existe une vingtaine de variables utilisables, toutes renseignées dans le « man udev« 

III.3.2 Exemple 2 : détection d’ajout d’une clef USB

Nous allons maintenant voir comment filtrer que sur l’insertion de clef USB. Pour cela nous allons ajouter d’autres filtres pour affiner la recherche.

ACTION=="add", KERNEL=="sd*" ,RUN+="/bin/sh  -c '/bin/echo %N : $name : %P : %k : %p >> /home/xavior/events2.log'"

Après avoir branché 2 clefs USB nous obtenons le résultat suivant :

xavior@mon_pc~$ cat events2.log 
/dev/sda : sda : : sda : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda
/dev/sda1 : sda1 : sda : sda1 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1
/dev/sda2 : sda2 : sda : sda2 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2
/dev/sdb : sdb : : sdb : /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host1/target1:0:0/1:0:0:0/block/sdb
/dev/sdb1 : sdb1 : sdb : sdb1 : /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host1/target1:0:0/1:0:0:0/block/sdb/sdb1

Nous obtenons ici les clefs USB (sda et sdb) ainsi que les partitions associées…

III.4 Des outils pour cibler plus précisément un périphérique

UDEV fonctionne via les messages envoyés par le noyau. Des outils sont disponibles pour les visualiser ou connaître les propriétés des périphériques installés.

III.4.1 « udevman monitor » : visualiser les messages envoyé par noyau pour les périphériques

Pour visualiser en temps réel ces messages il peut être utilisé la commande « udevadm monitor« . Ainsi pour voir ces messages :

udevadm monitor -k

ce qui donne :

monitor will print the received events for:
KERNEL - the kernel uevent

KERNEL[75339.500524] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3 (usb)
KERNEL[75339.503965] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0 (usb)
KERNEL[75339.504052] add      /devices/virtual/workqueue/scsi_tmf_0 (workqueue)
KERNEL[75339.504137] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0 (scsi)
KERNEL[75339.504157] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/scsi_host/host0 (scsi_host)
KERNEL[75339.504196] bind     /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0 (usb)
KERNEL[75339.504238] bind     /devices/pci0000:00/0000:00:14.0/usb2/2-3 (usb)
KERNEL[75340.783708] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0 (scsi)
KERNEL[75340.783739] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0 (scsi)
KERNEL[75340.783763] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/scsi_device/0:0:0:0 (scsi_device)
KERNEL[75340.783798] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/scsi_disk/0:0:0:0 (scsi_disk)
KERNEL[75340.783823] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/scsi_generic/sg0 (scsi_generic)
KERNEL[75340.783856] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/bsg/0:0:0:0 (bsg)
KERNEL[75340.802225] add      /devices/virtual/bdi/8:0 (bdi)
KERNEL[75340.811131] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda (block)
KERNEL[75340.811170] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1 (block)
KERNEL[75340.811203] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2 (block)
KERNEL[75340.840671] bind     /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0 (scsi)
KERNEL[75341.052677] add      /devices/virtual/bdi/8:2-fuseblk (bdi)

Pour connaître les propriétés associées à chaque signal :

udevadm monitor -k -p

Ce qui donne :

monitor will print the received events for:
KERNEL - the kernel uevent

KERNEL[75441.408389] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3 (usb)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb2/2-3
SUBSYSTEM=usb
DEVNAME=/dev/bus/usb/002/084
DEVTYPE=usb_device
PRODUCT=90c/1000/1100
TYPE=0/0/0
BUSNUM=002
DEVNUM=084
SEQNUM=9090
MAJOR=189
MINOR=211

KERNEL[75441.411726] add      /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0 (usb)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0
SUBSYSTEM=usb
DEVTYPE=usb_interface
PRODUCT=90c/1000/1100
TYPE=0/0/0
INTERFACE=8/6/80
MODALIAS=usb:v090Cp1000d1100dc00dsc00dp00ic08isc06ip50in00
SEQNUM=9091

...

III.4.2 « udevman info » : retrouver les propriétés et valeurs d’un périphérique

Il est également possible de retrouver toutes les clefs et valeurs d’un périphérique déjà connecté. Pour cela on utilise toujours la commande « udevadm » avec le paramètre ‘info‘ et le périphérique recherché

udevadm info /dev/sda

Ce qui donne :

P: /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda
N: sda
L: 0
S: disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0
S: disk/by-id/usb-General_USB_Flash_Disk_AA00000000013411-0:0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda
E: DEVNAME=/dev/sda
E: DEVTYPE=disk
E: MAJOR=8
E: MINOR=0
E: SUBSYSTEM=block
E: USEC_INITIALIZED=75442785275
E: ID_VENDOR=General
E: ID_VENDOR_ENC=General\x20
E: ID_VENDOR_ID=090c
E: ID_MODEL=USB_Flash_Disk
E: ID_MODEL_ENC=USB\x20Flash\x20Disk\x20\x20
E: ID_MODEL_ID=1000
E: ID_REVISION=1100
E: ID_SERIAL=General_USB_Flash_Disk_AA00000000013411-0:0
E: ID_SERIAL_SHORT=AA00000000013411
E: ID_TYPE=disk
E: ID_INSTANCE=0:0
E: ID_BUS=usb
E: ID_USB_INTERFACES=:080650:
E: ID_USB_INTERFACE_NUM=00
E: ID_USB_DRIVER=usb-storage
E: ID_PATH=pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_3_1_0-scsi-0_0_0_0
E: ID_PART_TABLE_UUID=ae60942d-dbbf-4514-9585-9ee78cf6b983
E: ID_PART_TABLE_TYPE=gpt
E: DEVLINKS=/dev/disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0 /dev/disk/by-id/usb-General_USB_Flash_Disk_AA00000000013411-0:0
E: TAGS=:systemd:

Pour la colonne de gauche :

  • E : une propriété –> il faudra utiliser ENV{} pour filtrer sur ce type de clef ;
    • à savoir que les propriétés commençant par ID_xxxx sont ajoutées par des règles UDEV
  • N : nom du périphérique proposé par le noyau ;
  • S : lien symbolique créé vers le périphérique ;
  • P: chemin vers sysfs (/sys/…).

Maintenant pour avoir plus d’informations comprenant l’ensemble des propriétés du device :

udevadm info -a /dev/sda

Ce qui donne :

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:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda':
    KERNEL=="sda"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{removable}=="1"
    ATTR{range}=="16"
    ATTR{ext_range}=="256"
    ATTR{stat}=="     260        7     9088      228        0        0        0        0        0      192      228        0        0        0        0        0        0"
    ATTR{hidden}=="0"
    ATTR{events_async}==""
    ATTR{events}=="media_change"
    ATTR{inflight}=="       0        0"
    ATTR{ro}=="0"
    ATTR{capability}=="51"
    ATTR{alignment_offset}=="0"
    ATTR{size}=="15720448"
    ATTR{events_poll_msecs}=="-1"
    ATTR{discard_alignment}=="0"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0':
    KERNELS=="0:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
...

Les valeurs ATTR{xxx} sont issues des proriétés fournies par Sysfs

III.5 Exemple de sélection d’un périphérique particulier

Après avoir vu comment obtenir l’ensemble des propriétés d’un périphérique nous allons voir comment définir nos règles Udev pour sélectionner précisément un périphérique, ici une clef USB. Une fois la clef trouvée, cela actionnera un script.

III.5.1 Cibler précisément une clef USB par son numéro de série

Nous allons voir comment cibler précisément une clef USB unique.

ACTION=="add",KERNEL=="sd[a-z]" ATTRS{serial}=="AA00000000015023", RUN+="/bin/sh  -c '/bin/echo %N : $name : %P : %k : %p >> /home/xavior/events3.log'"

Explications :

  • ACTION== »add » –> ne sélectionne que les évènements d’ajout de périphérique
  • KERNEL== »sd[a-z] » –> ne sélectionne que la clef physique (et non les partitions)
  • ATTRS{serial}== »AA00000000015023″ –> filtre sur le numéro de série de la clef (via les propriétés Sysfs)

Ce qui nous donne :

/dev/sdb : sdb : : sdb : /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host1/target1:0:0/1:0:0:0/block/sdb

III.5.2 Cibler tout type de clef USB insérée

Il suffit de reprendre la règle d’avant et d’enlever un filtre comme suivant :

ACTION=="add",KERNEL=="sd[a-z]", RUN+="/bin/sh  -c '/bin/echo %N : $name : %P : %k : %p >> /home/xavior/events3.log'"

Ce qui donne après insertion de 2 clefs USB différentes :

/dev/sda : sda : : sda : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda
/dev/sdb : sdb : : sdb : /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host1/target1:0:0/1:0:0:0/block/sdb

III.5.3 Cibler toutes les partitions d’une clef USB insérée

Maintenant on souhaite avoir seulement le nom des partitions d’une clef usb :

ACTION=="add",KERNEL=="sd*[0-9]", RUN+="/bin/sh  -c '/bin/echo %N : $name : %P : %k : %p >> /home/xavior/events3.log'"

Ce qui donne après l’insertion d’une clef :

/dev/sda1 : sda1 : sda : sda1 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1
/dev/sda2 : sda2 : sda : sda2 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2

III.5.4 Cibler la partition d’une clef USB qui porte un nom logique précis

Cette règle s’activera que si la clef USB possède un nom logique de partition précis.

ACTION=="add",KERNEL=="sd*[0-9]", ENV{PARTNAME}=="GRUB-SOS", RUN+="/bin/sh  -c '/bin/echo %N : $name : %P : %k : %p >> /home/xavior/events3.log'"

Ce qui donne après l’insertion de plusieurs clefs USB différentes :

/dev/sda2 : sda2 : sda : sda2 : /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2

IV Propriété UDEV des devices non visibles dans une règle (dans certains cas)

Lorsque on utilise la règle suivante qui effectue un filtre sur des propriétés qui ont été ajoutées par UDEV (propriété commençant par ID_xxxx) il se peut qu’elle ne fonctionne pas car vide… alors que tout semble correct.

ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", RUN+="/bin/sh  -c '/bin/echo  ID_FS_USAGE :  $env{ID_FS_USAGE} : PARTNAME : $env{PARTNAME} : %N : $name : %P >> /home/xavior/events4.log'"

Il faut bien faire attention au nom de fichier qui porte cette règle. Dans notre cas le nom de fichier utilisé est « 10-local.rules« . Il est pris en compte avant que les valeurs ajoutées par « UDEV » soient renseignées. Sous Ubuntu 20.04 par exemple, les règles qui vont renseigner ces valeurs sont les fichiers commençant à partir du numéro 60xxx (dans /liv/udev/rules.d).

Donc pour filtrer sur les propriétés des devices de type disque, il faut changer l’ordre de priorité de lecture de notre règle par une priorité plus tardive comme par exemple en utilisant le nom de fichier « 61-local.rules« . Et ce n’est qu’à ce moment que le règle pourra complètement agir et avoir un résultat comme celui-ci :

ID_FS_USAGE : filesystem : PARTNAME : EFI-USB : /dev/sda1 : sda1 : sda
ID_FS_USAGE : filesystem : PARTNAME : GRUB-SOS : /dev/sda2 : sda2 : sda

V Exemples finaux

Nous trouverons 2 exemples pratiques d’UDEV :

  • une sauvegarde pour une clef usb bien précise
  • une copie systèmatique des données lors d’un périphérique inséré USB

V.1 Sauvegarde de données pour une clef USB bien précise

V.1.1 Définition d’une règle UDEV

Nous allons cibler un matériel (clef USB) bien précis. Pour voir les propriétés nous allons dans un premier temps brancher la clef.

Puis nous allons voir les propriétés : udevadm info /dev/sda1 :

xavior@mon_pc:/etc/udev/rules.d$ udevadm info /dev/sda1
P: /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1
N: sda1
L: 0
S: disk/by-id/usb-SMI_USB_DISK_AA00000000015023-0:0-part1
...
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1
E: DEVNAME=/dev/sda1
E: DEVTYPE=partition
E: PARTN=1
E: PARTNAME=Sauvegarde
E: MAJOR=8
E: MINOR=1
E: SUBSYSTEM=block
...
E: ID_REVISION=1100
E: ID_SERIAL=SMI_USB_DISK_AA00000000015023-0:0
E: ID_SERIAL_SHORT=AA00000000015023
E: ID_TYPE=disk
...
E: ID_FS_UUID=C025-EDD1
E: ID_FS_UUID_ENC=C025-EDD1
E: ID_FS_VERSION=FAT32
E: ID_FS_TYPE=vfat
E: ID_FS_USAGE=filesystem
E: ID_PART_ENTRY_SCHEME=gpt
E: ID_PART_ENTRY_NAME=Sauvegarde
...

Nos critères seront :

  • PARTNAME : nom de la partition,
  • ID_SERIAL_SHORT : numéro de série de la clef USB.

Ce qui fera notre règle UDEV suivante : sudo vim /etc/udev/rules.d/61-local.rules

##########################
# Règles UDEV Perso
#########################


# Ajout clef USB dédiée à la sauvegarde
ACTION=="add",KERNEL=="sd[a-z][1-9]", ATTRS{serial}=="AA00000000015023", RUN+="/home/xavior/scripts/udev/udev_test.sh $name $env{ID_SERIAL_SHORT} $env{ID_PART_ENTRY_NAME} "

Cette règle se déclenchera si :

  • la clef USB est insérée ;
  • le nom du périphérique est de type disque USB (sda1, sdb2, autres…) ;
  • le numéro de série est celui de la clef.

On aurait pu ajouter le nom de la partition. Dans cet exemple il a été décidé de vérifier ce point dans le script.

Enfin, si les conditions sont remplies alors le script udev_test.sh sera executé. Les paramètres donnés au script sont :

  • $name : le nom du périphérique attribué par le noyau ;
  • $env{ID_SERIAL_SHORT} : le numéro de série de la clef usb ;
  • $env{IP_PART_ENTRY_NAME} : le nom de la partition.

V.1.2 Script bash associé

Et maintenant le script bash « udev_test » qui va effectuer la sauvegarde de données du PC vers la clef :

##########################################################
# Script permettant la sauvegarde des fichiers importants 
#  par simple insertion de la clef
# --> lancé par règle UDEV
#   $1 -> nom partition
#   $2 -> numéro de série de la clef USB
#   $3 -> libellé de la partition
##########################################################



##########################################################
#  Function permettant de notifier
#   $1 -> texte à afficher
##########################################################
function notifier() {
	# récupérer les users Xorg et num display 
	userX=`who | cut -f 1 -d ' '`
	displayX=`who | cut -f 4 -d ' '`

	# si chaine non vide
	if [ "$userX" = "" ] 
	then
		echo "userX vide ...."
	else
       		export DISPLAY=$displayX
        	export HOME=/home/$userX
        	# envoie de la notification
        	su $userX -c "zenity --notification --text=\"$1\""
	fi
}


#######################################################################
#  Main
#######################################################################

clear

# Récupération des arguments
nom_partition=$1
num_serial=$2
libelle_partition=$3

# Répertoire de montage cible
nom_repertoire="/mnt/tmp_$nom_partition"

# Tests finaux pour confirmer ciblage clef USB
continuer=0
if [ "$num_serial" = "AA00000000015023" ] && [ "$libelle_partition" = "Sauvegarde" ]; then
	continuer=1
fi

if [ $continuer -eq 1 ]; then

	notifier "Insertion clef USB $1 -- $2\n Début SAUVEGARDE..."

	##################
	# Montage partition
	mkdir $nom_repertoire
	mount /dev/$nom_partition $nom_repertoire

	################
	# Opérations à faire : sauvegarde des données...

	# Chemin répertoire final sur lequel sera monté la clef USB et effectué la sauvegarde
	nom_rep_sauvegarde="$nom_repertoire/Sauvegarde"

	# teste si répertoire sauvegarde existe --> si non on créé
	if [ ! -d $nom_rep_sauvegarde ]; then
		mkdir $nom_rep_sauvegarde
		mkdir $nom_rep_sauvegarde/scripts
		mkdir $nom_rep_sauvegarde/0_DOC_Vitaux
	fi

	# Copie des fichiers sur support amovible USB

	rsync -az --delete-after /home/xavior/scripts/ $nom_rep_sauvegarde/scripts/
	rsync -az --delete-after /home/xavior/Documents/0_DOC_Vitaux/ $nom_rep_sauvegarde/0_DOC_Vitaux/
	cp -R -f '/home/xavior/Bureau/Mots de passe.kdbx' $nom_rep_sauvegarde/

	######################
	# Demontage partition
	umount $nom_repertoire
	rmdir $nom_repertoire

	notifier "FIN SAUVEGARDE : $1 -- $2"
fi

Ce qui donne le résultat ci-dessous une fois la clef insérée :

V.2 Copie systématique du contenu d’une clef USB vers le PC

Dans cet exemple nous allons jouer les mini-pirates : dès qu’une clef USB est insérée sur le PC, on copie systématiquement le contenu de la clef …

V.2.1 Définition d’une règle UDEV

Notre règle sera simple :

# copie systématique d'une clef USB
ACTION=="add",KERNEL=="sd[a-z][1-9]", RUN+="/home/xavior/scripts/udev/udev_test2.sh $name $env{ID_SERIAL_SHORT} $env{ID_PART_ENTRY_NAME}"

Les conditions d’execution du script sont :

  • l’ajout d’un périphérique,
  • un périphérique de type sda1, sdc2 ou autres …

V.2.2 Script bash associé

Le script ci-dessous va copier le contenu de la clef usb dans le home :

#!/bin/bash

##########################################################
# Script permettant la sauvegarde des fichiers importants 
#  par simple insertion de la clef
# --> lancé par règle UDEV
#   $1 -> nom partition
#   $2 -> numéro de série de la clef USB
#   $3 -> libellé de la partition
##########################################################


#######################################################################
#  Main
#######################################################################

clear
# Récupération des arguments
nom_partition=$1
num_serial=$2
libelle_partition=$3
# Répertoire de montage cible
nom_repertoire="/mnt/tmp_$nom_partition"

##################
# Montage partition
mkdir $nom_repertoire
mount /dev/$nom_partition $nom_repertoire

################
# Opérations ...

# création répertoire final
repertoire_final="/home/xavior/usb/$num_serial/$nom_partition"
if [ ! -d $repertoire_final ]; then
	mkdir -p $repertoire_final
fi

# copie des données
cp -R -f -u $nom_repertoire/* $repertoire_final 

######################
# Demontage partition
umount $nom_repertoire
rmdir $nom_repertoire

VI Conclusion et ressources

Nous avons vu comment implémenter des scripts avec UDEV lors d’ajout ou de retrait de périphériques USB. UDEV est particulièrment utile dans le cadre de l’automatisation de tâches en fonction d’évènements de type matériel.

Ressources :

(UDEV) Lancer script à l’insertion d’une clef USB

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *