Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Alternative a udev pour charger les firmwares

11 réponses
Avatar
Pascal Hambourg
Salut,

J'ai une machine sous Debian GNU/Linux sur laquelle je ne veux pas udev
et qui s'en porte très bien ainsi. Mais je dois maintenant y connecter
un périphérique qui a besoin de firmwares, or apparemment c'est
normalement à udev qu'est dévolue la tâche de les charger à la demande
du noyau.

Existe-t-il une alternative simple qui ne ferait que ça ? Ou bien
devrais-je gribouiller un script infâme qui lit et écrit dans
/sys/class/firmware/, ou me résoudre à installer udev et apprendre
comment désactiver tous ses automatismes sauf le chargement des firmwares ?

10 réponses

1 2
Avatar
Yves Lambert
On Sat, 31 Jul 2010 14:07:32 +0200
Pascal Hambourg wrote:

Salut,

J'ai une machine sous Debian GNU/Linux sur laquelle je ne veux pas udev
et qui s'en porte très bien ainsi.



Ton /dev est statique ou bien tu utilise un autre mécanisme pour le
peupler ?



--
SPROTCH !

P : Non, y a rien de plus immonde que de chier sur la moquette...
M : Pas d'accord... A pire... Chier sous la moquette...
H : ?!!
Avatar
Nicolas George
Pascal Hambourg wrote in message <i313m4$qtm$:
J'ai une machine sous Debian GNU/Linux sur laquelle je ne veux pas udev
et qui s'en porte très bien ainsi. Mais je dois maintenant y connecter
un périphérique qui a besoin de firmwares, or apparemment c'est
normalement à udev qu'est dévolue la tâche de les charger à la demande
du noyau.

Existe-t-il une alternative simple qui ne ferait que ça ? Ou bien
devrais-je gribouiller un script infâme qui lit et écrit dans
/sys/class/firmware/, ou me résoudre à installer udev et apprendre
comment désactiver tous ses automatismes sauf le chargement des firmwares ?



Il y a deux choses :

- savoir quand le noyau demande un firmware ;

- charger le firmware demandé.

Pour le premier point, quand le noyau a besoin d'un firmware, il génère un
uevent, qui est communiqué à l'userland de deux manières différentes :

- En exécutant le programme pointé par le sysctl kernel.hotplug (par défaut
/sbin/hotplug, mais on peut le changer, statiquement ou dynamiquement).
Les paramètres sont alors dans les arguments ou l'environnement.

- En envoyant un message sur une socket netlink.

Le premier est clairement plus simple, mais il faut faire attention que les
uevents sont assez nombreux : chaque ajout ou suppression de matériel, mais
aussi chaque ajout ou suppression d'UID (parmi les processus existants).
Invoquer un programme à chaque fois peut faire monter la charge assez
lourdement.

Le second est plus compliqué, ne serait-ce que parce qu'il faut se
documenter sur comment les socket netlink marchent, mais il n'a pas cet
inconvénient. C'est pourquoi udev utilise netlink et désactive
kernel.hotplug. Mais ça exige un démon présent en permanence.


Pour le second point, charger le firmware, mon udev par défaut a la règle :

SUBSYSTEM=="firmware", RUN+="firmware.agent"

Et firmware.agent est un script qui, après quelques tests, fait :

echo 1 > /sys/$DEVPATH/loading
cat "$DIR/$FIRMWARE" > /sys/$DEVPATH/data
echo 0 > /sys/$DEVPATH/loading

Assez facile donc.

ou me résoudre à installer udev et apprendre
comment désactiver tous ses automatismes sauf le chargement des firmwares ?



C'est en fait assez facile : udev, c'est essentiellement udevd, un démon qui
écoute les uevents sur une socket netlink, et exécute des programmes ou crée
des noeuds en réaction à ces uevents.

Tout ce qu'udevd fait, il le fait en suivant une règle. Si ses répertoires
de règles sont vides, udevd ne fait strictement rien.

Après, il faut aussi dépatouiller un peu les scripts de lancement d'udevd,
parce que ce sont eux qui montent un tmpfs sur /dev/.
Avatar
Pascal Hambourg
Yves Lambert a écrit :
Pascal Hambourg wrote:

J'ai une machine sous Debian GNU/Linux sur laquelle je ne veux pas udev
et qui s'en porte très bien ainsi.



Ton /dev est statique ou bien tu utilise un autre mécanisme pour le
peupler ?



Statique.
Avatar
Pascal Hambourg
Nicolas George a écrit :
Pascal Hambourg wrote in message <i313m4$qtm$:
J'ai une machine sous Debian GNU/Linux sur laquelle je ne veux pas udev
et qui s'en porte très bien ainsi. Mais je dois maintenant y connecter
un périphérique qui a besoin de firmwares, or apparemment c'est
normalement à udev qu'est dévolue la tâche de les charger à la demande
du noyau.

Existe-t-il une alternative simple qui ne ferait que ça ? Ou bien
devrais-je gribouiller un script infâme qui lit et écrit dans
/sys/class/firmware/, ou me résoudre à installer udev et apprendre
comment désactiver tous ses automatismes sauf le chargement des firmwares ?



Il y a deux choses :

- savoir quand le noyau demande un firmware ;

- charger le firmware demandé.

Pour le premier point, quand le noyau a besoin d'un firmware, il génère un
uevent, qui est communiqué à l'userland de deux manières différentes :

- En exécutant le programme pointé par le sysctl kernel.hotplug (par défaut
/sbin/hotplug, mais on peut le changer, statiquement ou dynamiquement).
Les paramètres sont alors dans les arguments ou l'environnement.



Intéressant. Et plus propre que de regarder périodiquement s'il y a
quelque chose dans /sys/class/firmware/*/uevent. Le programme peut être
un script shell ?

- En envoyant un message sur une socket netlink.

Le premier est clairement plus simple, mais il faut faire attention que les
uevents sont assez nombreux : chaque ajout ou suppression de matériel, mais
aussi chaque ajout ou suppression d'UID (parmi les processus existants).



Qu'entends-tu par là au juste ?

Le second est plus compliqué, ne serait-ce que parce qu'il faut se
documenter sur comment les socket netlink marchent, mais il n'a pas cet
inconvénient. C'est pourquoi udev utilise netlink et désactive
kernel.hotplug. Mais ça exige un démon présent en permanence.



Et surtout je ne suis pas développeur, donc si ça ne peut pas se faire
avec un bête script shell de quelques lignes ça dépasse ma compétence.

Pour le second point, charger le firmware, mon udev par défaut a la règle :

SUBSYSTEM=="firmware", RUN+="firmware.agent"

Et firmware.agent est un script qui, après quelques tests, fait :

echo 1 > /sys/$DEVPATH/loading
cat "$DIR/$FIRMWARE" > /sys/$DEVPATH/data
echo 0 > /sys/$DEVPATH/loading

Assez facile donc.



Oui, j'avais lu dans la doc incluse dans les sources du noyau et c'est
ainsi que j'ai fait pour tester manuellement en récupérant les infos
dans /sys/class/firmware/*/uevent.

ou me résoudre à installer udev et apprendre
comment désactiver tous ses automatismes sauf le chargement des firmwares ?



C'est en fait assez facile : udev, c'est essentiellement udevd, un démon qui
écoute les uevents sur une socket netlink, et exécute des programmes ou crée
des noeuds en réaction à ces uevents.

Tout ce qu'udevd fait, il le fait en suivant une règle. Si ses répertoires
de règles sont vides, udevd ne fait strictement rien.

Après, il faut aussi dépatouiller un peu les scripts de lancement d'udevd,
parce que ce sont eux qui montent un tmpfs sur /dev/.



Oui, entre autres, c'est le genre de chose qui me fait un peu peur et me
retient d'y mettre le nez. Encore une usine à gaz qui ne me sert à
presque rien.
Avatar
Nicolas George
Pascal Hambourg wrote in message <i37gtn$a4b$:
Le programme peut être
un script shell ?



Bien sûr.

Qu'entends-tu par là au juste ?



Quand un processus acquiert l'UID 42 alors qu'il n'y a aucun autre processus
ayant l'UID 42, le noyau considère que l'UID 42 vient d'être créé, et émet
un uevent en conséquence. Quand un processus perd l'UID 42 (par exemple en
se terminant) et qu'il ne reste plus d'autre processus de cet UID, le noyau
considère que l'UID 42 vient d'être détruit, et émet un uevent en
conséquence.

Donc par exemple, sur un serveur de mail, quand le MTA invoque le MDA sous
l'identité du destinataire, ça va provisoirement créer l'UID correspondant
au destinataire, donc générer deux uevents.

Oui, entre autres, c'est le genre de chose qui me fait un peu peur et me
retient d'y mettre le nez. Encore une usine à gaz qui ne me sert à
presque rien.



Justement, ce n'est pas tant une usine à gaz que ça. C'est même relativement
simple et élégant, comme design. Il y a un peu d'usine à gaz au niveau des
scripts qui usuellement l'invoquent, mais justement tu n'en veux pas.
Avatar
Pascal Hambourg
Nicolas George a écrit :

Donc par exemple, sur un serveur de mail, quand le MTA invoque le MDA sous
l'identité du destinataire, ça va provisoirement créer l'UID correspondant
au destinataire, donc générer deux uevents.



C'est ce que je craignais d'avoir compris, car la machine gère le
courrier pour un domaine. Va savoir quels autres programmes, démons et
cronjobs changent aussi d'utilisateur de façon récurrente pour effectuer
des tâches spécifiques...

Oui, entre autres, c'est le genre de chose qui me fait un peu peur et me
retient d'y mettre le nez. Encore une usine à gaz qui ne me sert à
presque rien.



Justement, ce n'est pas tant une usine à gaz que ça. C'est même relativement
simple et élégant, comme design. Il y a un peu d'usine à gaz au niveau des
scripts qui usuellement l'invoquent, mais justement tu n'en veux pas.



Tu m'as presque convaincu. Il faudra encore que je regarde comment faire
pour désactiver ces scripts ou les court-circuiter et qu'ils ne
reviennent pas à la mise à jour suivante d'udev, s'ils sont gérés en
conffiles ou autrement par dpkg...

Et merci pour toutes ces informations.
Avatar
Pascal Hambourg
Nicolas George a écrit :

Pour le premier point, quand le noyau a besoin d'un firmware, il génère un
uevent, qui est communiqué à l'userland de deux manières différentes :

- En exécutant le programme pointé par le sysctl kernel.hotplug (par défaut
/sbin/hotplug, mais on peut le changer, statiquement ou dynamiquement).
Les paramètres sont alors dans les arguments ou l'environnement.



Bon, j'ai écrit le script suivant qui a l'air de marcher :
============ #!/bin/sh

echo $(date) subsytem="$SUBSYSTEM" action="$ACTION"
/var/log/hotplug.log





if [[ "$SUBSYSTEM" == "firmware" && "$ACTION" == "add" ]] ; then
echo Firmware "$FIRMWARE" requested >> /var/log/hotplug.log
HOTPLUG_FW_DIR="/lib/firmware"
if [ -f $HOTPLUG_FW_DIR/$FIRMWARE ] ; then
echo Loading firmware $FIRMWARE >> /var/log/hotplug.log
echo 1 > /sys/$DEVPATH/loading
cat $HOTPLUG_FW_DIR/$FIRMWARE > /sys/$DEVPATH/data
echo 0 > /sys/$DEVPATH/loading
else
echo Firmware $FIRMWARE not found >> /var/log/hotplug.log
echo -1 > /sys/$DEVPATH/loading
fi
fi
============ Le script enregistre une trace de tous les événements afin d'évaluer
leur fréquence. A première vue le gros des événements concerne
effectivement l'ajout/suppression d'UID, il n'y en a pas chaque seconde.

Merci encore.
Avatar
Nicolas George
Pascal Hambourg wrote in message <i3a048$j9v$:
Bon, j'ai écrit le script suivant qui a l'air de marcher :



Tant mieux. Attention cependant :

#!/bin/sh
if [[ "$SUBSYSTEM" == "firmware" && "$ACTION" == "add" ]] ; then



La construction [[ ... == ... ]] n'est pas du sh standard. Par exemple, dash
ne la reconnaît pas.
Avatar
Pascal Hambourg
Nicolas George a écrit :

La construction [[ ... == ... ]] n'est pas du sh standard. Par exemple, dash
ne la reconnaît pas.



Il me semblait bien que c'était un "bashisme". Comme je n'écris pas du
shell tous les jours, j'ai repompé la tournure vite fait dans un vieux
script que j'avais écrit ; comme il y avait un joker dans un opérande,
je n'avais pas trouvé comment faire autrement mais c'est vrai que n'est
pas le cas ici.

-if [[ "$SUBSYSTEM" == "firmware" && "$ACTION" == "add" ]] ; then
+if [ "$SUBSYSTEM" = "firmware" -a "$ACTION" = "add" ] ; then
Avatar
Pascal Hambourg
Pascal Hambourg a écrit :
Nicolas George a écrit :
La construction [[ ... == ... ]] n'est pas du sh standard. Par exemple, dash
ne la reconnaît pas.



Il me semblait bien que c'était un "bashisme". Comme je n'écris pas du
shell tous les jours, j'ai repompé la tournure vite fait dans un vieux
script que j'avais écrit ; comme il y avait un joker dans un opérande,
je n'avais pas trouvé comment faire autrement



Bête je suis. Il s'agissait d'un test de type

si variable = motif1
action1
sinon si variable = motif2
action2
sinon
action3

donc un simple case convenait très bien.
Je le ferai plus, promis.

En dehors de case, est-il possible en sh standard de tester la
correspondance d'une chaîne avec un motif sans faire appel à une
commande externe ? J'imagine que la construction [[ ... == ... ]] de
bash a été ajoutée pour pallier un manque de ce côté.
1 2