Démarrer un service lorsque un périphérique est prêt

Vous avez réalisé ou vous voulez réaliser un truc impensable avec votre Raspberry Pi ? Cet endroit est pour vous...

Modérateur : Francois

piper
Raspinaute
Messages : 658
Enregistré le : sam. 5 juin 2021 18:57

Re: Démarrer un service lorsque un périphérique est prêt

Message par piper » jeu. 9 févr. 2023 11:52

Ce n'est pas encore la solution miracle car si j'ai bien compris :
les règles udev permettent de :
- renommer un périphérique
- créer des liens symboliques
- forcer une adresse mac (carte réseau)
- préparer les périphériques de partitionnement (disque)
- lancer un programme (si celui si répond très rapidement car cela bloque la poursuite du chargement de udev)
- modifier/créer une variable d'environnement
- détecter le branchement / débranchement à chaud d'un périphériques USB

Il n'est pas fait pour interférer avec les programmes utilisateurs.

Avec les règles udev, je peux dans mon cas :
- détecter le chargement de udev sur mon périphérique et assigner une variable d'environnement par exemple ou lancer un petit script
- mais pas lancer mon service qui est un programme utilisateur

Par contre, j'ai maintenant la méthode avec udevadm pour identifier de manière certaine mon périphérique quelque soit le port usb sur lequel il est branché.

Pour le moment, je ne vois qu'une solution :
- exploiter udevadm dans systemd (ou un script dans systemd) pour identifier mon matériel, voir si le pilote est chargé et s'il l'est : alors démarrer mon service.
Mais je bloque encore car j'aimerai ne pas faire de boucle avec un un sleep (beurk) mais utiliser les bonnes pratiques de systemd (genre : la clé After)

Entretemps, j'ai découvert autre chose :
Si je lance mon service par init.d (à l'ancienne), il démarre alors que le pilote est chargé, alors que si j'utilise systemd, il essaie de démarrer avant.
What the F .... ?
On pourrait dire que ça résoud le Pb mais non : la méthode par init.d est destinée à disparaitre dans un avenir de plus en plus proche.
3 Pi4 : Emby / Samba , Librelec, Android TV
3 Pi3 : Hifiberry /OSMC, Games station, Samba / VPN / HotSpot Wifi
2 Pi2 : RFID, radio reveil (PiReveil)
1 Pi0 : traker GPS et acquisitions
1 Pi0 2W : tests divers
5 Arduinos dont 4 nanos et 1 Mega
1 ESP32

destroyedlolo
Raspinaute
Messages : 1587
Enregistré le : dim. 10 mai 2015 18:44
Localisation : Dans la campagne à côté d'Annecy
Contact :

Re: Démarrer un service lorsque un périphérique est prêt

Message par destroyedlolo » jeu. 9 févr. 2023 21:43

piper a écrit :
jeu. 9 févr. 2023 11:10
C'est ma signature en bas des programmes que j'écris : RTFM :mrgreen:
Ouai, mais du coup, ca oblige a écrire une doc :lol:
  • BananaPI : Gentoo, disque SATA de 2 To
  • Domotique : 1-wire, TéléInfo, Tablette passée sous Gentoo, ESP8266
  • Multimedia par DNLA
  • Et pleins d'idées ... et bien sûr, pas assez de temps.
Un descriptif de ma domotique 100% fait maison.

piper
Raspinaute
Messages : 658
Enregistré le : sam. 5 juin 2021 18:57

Re: Démarrer un service lorsque un périphérique est prêt

Message par piper » jeu. 9 févr. 2023 23:50

A moins que j'en sois le seul et unique utilisateur, j'écris toujours une doc.
D'ailleurs je me demande souvent pourquoi, vu qu'elle n'est jamais lue et pourtant accessible de chaque écran avec une arrivée directe sur l'aide concernant l'écran ou page sur laquelle l'utilisateur se trouve.
D'où quelque fois, mes réponses avec un volume assez fort pour être entendu de tout l'étage : "Read The Fucking Manual" et mon image de "râleur au mauvais caractère" qui me colle à la peau.
3 Pi4 : Emby / Samba , Librelec, Android TV
3 Pi3 : Hifiberry /OSMC, Games station, Samba / VPN / HotSpot Wifi
2 Pi2 : RFID, radio reveil (PiReveil)
1 Pi0 : traker GPS et acquisitions
1 Pi0 2W : tests divers
5 Arduinos dont 4 nanos et 1 Mega
1 ESP32

jelopo
Raspinaute
Messages : 310
Enregistré le : mer. 11 oct. 2017 10:23

Re: Démarrer un service lorsque un périphérique est prêt

Message par jelopo » ven. 10 févr. 2023 10:10

Bonjour,
piper a écrit :
jeu. 9 févr. 2023 23:50
A moins que j'en sois le seul et unique utilisateur, j'écris toujours une doc.
Vu que je suis maintenant le seul utilisateur de mes scripts, la doc n'est que pour moi, et pourtant, ça m'évite de perdre bien du temps pour comprendre ce que j'ai codé.
piper a écrit :
jeu. 9 févr. 2023 23:50
D'où quelque fois, mes réponses avec un volume assez fort pour être entendu de tout l'étage : "Read The Fucking Manual" et mon image de "râleur au mauvais caractère" qui me colle à la peau.
Quand j'étais dans l'informatique, j'étais un peu comme ça aussi, ça m'a valu des promotions loupées quand j'avais affiché en grand sur mon bureau "Quand on fait n'importe quoi, on a n'importe quoi". Je crois que la hiérarchie avait pris ça pour elle (oups) et non pour mes collègues qui travaillaient à l'arrache... Parfois, le message est bon mais pas ceux qui le reçoivent. :oops:

Bon sinon, coté systemd, vous avancez ? Arrivez vous à créer une "target" ou un "service" qui démarre après une règle udev afin de la placer dans un [After] ?

A+

piper
Raspinaute
Messages : 658
Enregistré le : sam. 5 juin 2021 18:57

Re: Démarrer un service lorsque un périphérique est prêt

Message par piper » mar. 14 févr. 2023 16:03

Débordé par le boulot, j'ai du mettre ce projet de côté quelques jours depuis mon dernier message.
Depuis, j'ai trouvé une autre documentation :

https://linuxembedded.fr/2018/03/kernel ... du-hotplug

D'après celle-ci je peux demander que udev créer automatiquement un nouvelle élément de systemd correspondant à mon périphérique si ce dernier est détecté

Et mon service doit pouvoir connaitre la présence du périphérique en utilisant la clé ReloadPropagatedFrom le nom de l'élément de systemd que udev a créer à la détection du périphérique grâce à ma règle udev (à l'aide des clés TAG et ENV{SYSTEMD_ALIAS})

Bref, on s'éloigne beaucoup de l'utilisation de "After" dont je me doutais qu'il ne serait pas utilisable dans ce contexte.

Reste plus qu'à essayer quand j'aurai un peu de temps à passer dessus.
3 Pi4 : Emby / Samba , Librelec, Android TV
3 Pi3 : Hifiberry /OSMC, Games station, Samba / VPN / HotSpot Wifi
2 Pi2 : RFID, radio reveil (PiReveil)
1 Pi0 : traker GPS et acquisitions
1 Pi0 2W : tests divers
5 Arduinos dont 4 nanos et 1 Mega
1 ESP32

jelopo
Raspinaute
Messages : 310
Enregistré le : mer. 11 oct. 2017 10:23

Re: Démarrer un service lorsque un périphérique est prêt

Message par jelopo » mer. 15 févr. 2023 09:37

Bonjour,
Cela semble correspondre à votre demande.
Je comprend pourquoi "on" utilise juste un sleep maintenant (crade, mais rapide et efficace!) ... :lol:

Bonne bidouilles.

A+

Artemus24
Raspinaute
Messages : 1077
Enregistré le : ven. 15 sept. 2017 19:15

Re: Démarrer un service lorsque un périphérique est prêt

Message par Artemus24 » lun. 20 févr. 2023 00:11

Salut à tous.

Cela vous arrive de temps en temps de lire les didacticiels de ce forum ?
Voici comment créer une règle udev qui va déclencher un script lors du montage d'une clef usb.
Je ne vais pas tout reprendre mais préciser quelques points :

a) vous devez modifier le fichier "/lib/systemd/system/systemd-udevd.service".
A la fin de celui-ci, ajoutez la ligne suivante :

Code : Tout sélectionner

MountFlags=shared
b) pourquoi cette modification ?
Sans ce paramètre, on ne peut pas monter ou démonter des périphériques au travers des règles udev.

c) après la modification, recharger les services :

Code : Tout sélectionner

systemctl daemon-reload
d) vous créez un script bash, par exemple "/root/test.sh" :

Code : Tout sélectionner

#!/bin/bash

if mountpoint -q /mnt/directory; then
        echo "Coucou Piper :)" > /mnt/directory/toto.txt
fi

exit
e) que fait-il ?
Il vérifie l'existence du montage du répertoire "/mnt/directory".
Puis il va créer un fichier, genre log, dans le répertoire et y mettre un message.

f) et voici la règle udev :

Code : Tout sélectionner

SUBSYSTEM!="block",ATTRS{idVendor}!="0951",ATTRS{idProduct}!="1603",GOTO="my_usb_key_end"
ATTRS{serial}!="0019E000B46EA921258F0084",GOTO="my_usb_key_end"
KERNEL!="sd[b-z]1",GOTO="my_usb_key_end"

ACTION=="add",ENV{ID_OPTIONS}="defaults,auto"

ACTION=="add",RUN+="/bin/mount -t $env{ID_FS_TYPE} -o $env{ID_OPTIONS} /dev/%k /mnt/directory"
ACTION=="add",RUN+="/root/test.sh"
# ACTION=="remove",RUN+="/bin/umount /mnt/directory"

LABEL="my_usb_key_end"
Cette règle réalise le montage et le démontage du périphérique, enfin de la clef usb.
Il monte le répertoire sous le nom "/mnt/directory".

g) on lance le service :

Code : Tout sélectionner

systemctl restart udev.service
h) vérification du "status" du service "udev" :

Code : Tout sélectionner

~> systemctl status udev.service
● systemd-udevd.service - Rule-based Manager for Device Events and Files
     Loaded: loaded (/lib/systemd/system/systemd-udevd.service; static)
     Active: active (running) since Mon 2023-02-20 00:03:43 CET; 12s ago
TriggeredBy: ● systemd-udevd-kernel.socket
             ● systemd-udevd-control.socket
       Docs: man:systemd-udevd.service(8)
             man:udev(7)
   Main PID: 27695 (systemd-udevd)
     Status: "Processing with 24 children at max"
      Tasks: 1
        CPU: 86ms
     CGroup: /system.slice/systemd-udevd.service
             └─27695 /lib/systemd/systemd-udevd

févr. 20 00:03:43 RaspberryPi.local systemd[1]: Starting Rule-based Manager for Device Events and Files...
févr. 20 00:03:43 RaspberryPi.local systemd-udevd[27695]: Network interface NamePolicy= disabled on kernel command line, ignoring.
févr. 20 00:03:43 RaspberryPi.local systemd[1]: Started Rule-based Manager for Device Events and Files.
~>
h) est-ce que mon répertoire est présent ?

Code : Tout sélectionner

~> df -h
Sys. de fichiers Taille Utilisé Dispo Uti% Monté sur
/dev/root           20G    5,5G   14G  30% /
devtmpfs           3,9G       0  3,9G   0% /dev
tmpfs              3,9G       0  3,9G   0% /dev/shm
tmpfs              1,6G    9,8M  1,6G   1% /run
tmpfs              5,0M    4,0K  5,0M   1% /run/lock
tmpfs              3,9G     20K  3,9G   1% /tmp
tmpfs              3,9G    360K  3,9G   1% /var/log
tmpfs              3,9G       0  3,9G   0% /var/tmp
/dev/sda5           98G     24K   93G   1% /share
/dev/sda3          9,8G     31M  9,3G   1% /warehouse
/dev/sda6          295G    3,1G  277G   2% /backup
/dev/sda1         1022M     51M  972M   5% /boot
tmpfs              790M     36K  790M   1% /run/user/0
tmpfs              790M     32K  790M   1% /run/user/1000
/dev/sdb1           16G     47M   15G   1% /mnt/directory
~>
Il est bien présent, en dernière ligne du "df -h".

i) on vérifie :

Code : Tout sélectionner

~> cat /mnt/directory/toto.txt
Hello Piper !
~>
Ca fonctionne !!!

Artemus24.
@+
RPI4B/8GB + Argon FanHAt
Rpi3A+, Rpi3B+
RPi 2B + Joy-It I2C Serial 20x4 2004 LCD Module
RPi 2B + PIM273 Unicorn HAT HD 16x16 Leds RGB
RPi0v1.3, RPi0W + LibreElec/Kodi, Rpi0WH + Tuner TV HAT
NodeMCU ESP32

piper
Raspinaute
Messages : 658
Enregistré le : sam. 5 juin 2021 18:57

Re: Démarrer un service lorsque un périphérique est prêt

Message par piper » mar. 21 févr. 2023 11:34

Merci je l'avais vu
Sauf que mon problème n'a rien à voir avec le montage du volume d'un périphérique de mémoire de masse usb.
J'ai un exécutable qui doit être lancé au démarrage (avec systemd : facile)
Mais avant qu'il ne démarre, je veux être sur que le pilote est déjà chargé dans le noyau.
3 Pi4 : Emby / Samba , Librelec, Android TV
3 Pi3 : Hifiberry /OSMC, Games station, Samba / VPN / HotSpot Wifi
2 Pi2 : RFID, radio reveil (PiReveil)
1 Pi0 : traker GPS et acquisitions
1 Pi0 2W : tests divers
5 Arduinos dont 4 nanos et 1 Mega
1 ESP32

Artemus24
Raspinaute
Messages : 1077
Enregistré le : ven. 15 sept. 2017 19:15

Re: Démarrer un service lorsque un périphérique est prêt

Message par Artemus24 » mar. 21 févr. 2023 19:18

Salut Piper.
Piper a écrit :Là, on me dit que le port usb n'était pas prêt lors du démarrage du service
J'ai peut-être été induit en erreur quand tu parles de port USB car j'ai compris que tu branchais quelque chose.
C'est le rôle des règles udev, de déclencher un traitement lorsqu'un périphérique est monté, pas celui des services.

Si tu veux un service qui se déclenche tout le temps, voici comme faire :

Code : Tout sélectionner

[Unit]
Description=Bash Test Program
After=multi-user.target

[Service]
Type=simple
User=root
ExecStart=/usr/bin/bash /warehouse/Prog_Bash/04.Service/test.sh
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
Toutes les 5 secondes, le script bash "test.sh" va s'exécuter.

Si je désire afficher le contenu du répertoire qui se trouve dans ma clef usb, qui elle même n'est pas encore monté, il suffit de le tester :

Code : Tout sélectionner

#!/bin/bash

DEST='/warehouse/Prog_Bash/04.Service/fichier.log'

if [ -d "/media/root/DIRECTORY" ]; then
        echo "----------------"      >> $DEST
        echo $(date +%H:%M:%S)       >> $DEST
        ls -al /media/root/DIRECTORY >> $DEST
fi

exit
Si un service plante, il ne peux pas redémarrer tout seul.
Il faut le relancer en faisant un "systemctl start nom_du_service.service".

Il y a la dépendance. J'ai testé le montage de ma clef usb que je vois en faisant :

Code : Tout sélectionner

systemctl list-units --type=mount
J'ai mis cette dépendance dans un "after" et un "Requires", mais cela ne fait que planter le service, si elle n'est pas présente.
Piper a écrit :Mais avant qu'il ne démarre, je veux être sur que le pilote est déjà chargé dans le noyau.
De quoi parles-tu ? Il faudrait être précis dans ta demande.

Cordialement.
Artemus24.
@+
RPI4B/8GB + Argon FanHAt
Rpi3A+, Rpi3B+
RPi 2B + Joy-It I2C Serial 20x4 2004 LCD Module
RPi 2B + PIM273 Unicorn HAT HD 16x16 Leds RGB
RPi0v1.3, RPi0W + LibreElec/Kodi, Rpi0WH + Tuner TV HAT
NodeMCU ESP32

Artemus24
Raspinaute
Messages : 1077
Enregistré le : ven. 15 sept. 2017 19:15

Re: Démarrer un service lorsque un périphérique est prêt

Message par Artemus24 » mer. 22 févr. 2023 05:47

Salut Piper.

J'ai trouvé une solution qui conditionne dans le service, le ou les programme(s) qui doi(ven)t s'exécuter.
Il faut jouer sur les codes retour et dire ce que l'on veut faire avec.

a) le programme que tu dois exécuter va se lancer par la commande "ExecStart".
Tu peux en mettre plusieurs, les uns à la suite des autres.

b) pour que le ou les programme(s) puisse(nt) s'exécuter, il faut mettre une condition, qui va retourner deux codes retour :
--> 0 : il est dans les bonnes conditions pour exécuter le programme.
--> 2 : le programme ne va pas s'exécuter.

c) la condition va se faire par la commande "ExecStartPre" qui va se placer avant les "ExecStart".

d) je demande à ce que le service redémarre tout le temps, mais cinq secondes après son dernier arrêt :

Code : Tout sélectionner

[service]
Restart=always
RestartSec=5
e) les conditions sur le code retour va se faire ainsi :

Code : Tout sélectionner

RestartPreventExitStatus=0
Si le code retour est à 0, je demande à ce qu'il n'y ait pas de redémarrage.

Code : Tout sélectionner

RestartForceExitStatus=2
Si le code retour est à 2, je demande à forcer le redémarre du service.

f) ce qui donne :

Code : Tout sélectionner

[Unit]
Description=Bash Test Program
After=multi-user.target

[Service]
Type=simple
User=root
ExecStartPre=/usr/bin/bash /warehouse/Service/02.Bash/verify.sh
ExecStart=/usr/bin/bash /warehouse/Service/02.Bash/test.sh
Restart=always
RestartSec=5
RestartPreventExitStatus=0
RestartForceExitStatus=2

[Install]
WantedBy=multi-user.target
g) comment j'ai testé ? Avec ma clef usb tout simplement.
Si le répertoire "/media/root/Directory" a été monté, verify.sh donne un code retour à 0, sinon c'est 2.

J'espère que cette solution te convient.
Cordialement.
Artemus24.
@+
RPI4B/8GB + Argon FanHAt
Rpi3A+, Rpi3B+
RPi 2B + Joy-It I2C Serial 20x4 2004 LCD Module
RPi 2B + PIM273 Unicorn HAT HD 16x16 Leds RGB
RPi0v1.3, RPi0W + LibreElec/Kodi, Rpi0WH + Tuner TV HAT
NodeMCU ESP32

Répondre

Retourner vers « Utilisateurs avancés »