Comment exécuter un processus de longue durée sur un événement Udev?

11

Je veux exécuter une connexion ppp lorsque mon modem USB est connecté, j'utilise donc cette udevrègle:

ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="16d8",\
    RUN+="/usr/local/bin/newPPP.sh $env{DEVNAME}"

(Mon modem apparaît en /devtant que ttyACM0)

newPPP.sh:

#!/bin/bash
/usr/bin/pon prov $1 >/dev/null 2>&1 &

Problème:

L' udevévénement se déclenche et newPPP.sh est en cours d'exécution, mais le newPPP.shprocessus est tué après ~ 4-5 secondes. pppn'a pas le temps de se connecter (son délai d'attente est de 10 secondes pour la connexion par ligne commutée).

Comment puis-je exécuter un processus de longue durée, qui ne sera pas tué?

J'ai essayé d'utiliser nohup, mais cela n'a pas fonctionné non plus.

Système: Arch Linux

Mise à jour

J'ai trouvé une solution ici , grâce à maxschlepzig .

J'utilise at nowpour exécuter mon travail indépendamment du processus udev.

Mais la seule question reste sans réponse: pourquoi fonctionne nohupet &ne fonctionne pas?

Communauté
la source

Réponses:

11

Si vous exécutez une distribution décente avec le support de systemd, le moyen le plus simple et le plus sûr techniquement est d'utiliser une unité de périphérique .

De cette façon, systemd contrôlera pleinement le script de longue durée et pourra même terminer correctement le processus une fois que le périphérique sera arrêté / supprimé - le détachement du processus signifie que vous abandonnez le contrôle total de l'état du processus et son histoire.

En plus de cela, vous pourrez inspecter l'état de l'appareil et de son service attaché en exécutant systemctl status my-ppp-thing.device.

Voir également cet article de blog pour plus d'exemples et de détails.

Elias Probst
la source
6

De nos jours, udev utilise des groupes de contrôle pour rechercher-n-détruire les tâches générées. Une solution consiste à utiliser "at now" ou "batch". Une autre solution consiste à faire un double fork et à "déplacer" le processus vers un autre groupe de contrôle. Ceci est un exemple de code python (un code similaire peut être écrit dans n'importe quelle langue):

os.closerange(0, 65535)  # just in case
pid = os.fork()
if not pid:
  pid = os.fork()  # fork again so the child would adopted by init
  if not pid:
    # relocate this process to another cgroup
    with open("/sys/fs/cgroup/cpu/tasks", "a+") as fd:
      fd.write(str(os.getpid()))
    sleep(3)  # defer execution by XX seconds
    # YOUR CODE GOES HERE
sleep(0.1)  # get forked process chance to change cgroup

La sortie de débogage peut être envoyée, par exemple, à syslog.

Alexandre Kandalintsev
la source
1
Pourquoi udev irait-il si loin pour détruire les processus engendrés?
user30747
Je suppose que c'est parce que les programmes lancés par udev bloquent le démon (par exemple avec une règle udev connectée à la connexion d'un écran externe, un programme de longue durée empêchera le nouvel affichage d'être réellement utilisé). Je suis sûr que cela a son propre raisonnement technique, mais cela signifie que les processus générés peuvent contenir des parties importantes du système et doivent être tués.
tobek
2

Shell a la capacité d'exécuter des commandes en arrière-plan:

(

lots of code

) &

Les commandes regroupées par les accolades avec esperluette après elles seront exécutées de manière asynchrone dans un sous-shell. Je l'utilise pour me connecter automatiquement lorsqu'un modem USB est inséré et commuté. Cela prend environ 20 secondes et fonctionne bien sous udev.

user42295
la source
Vous pouvez vouloir rediriger stderr, stdout et stderr dans une telle situation.
mdpc
@mdpc hmm ... pourquoi? J'ai vu usb_modeswitch fermer les flux dans ce scénario: exec 1 <& - 2 <& - 5 <& - 7 <& -
user42295
1

Je l'ai fait fonctionner avec setsid. Ma partie RUN de la règle udev:

RUN+="/bin/bash script.sh"

puis dans le script:

#!/bin/bash
if [ "$1" != "fo_real" ]; then
  /usr/bin/setsid $(/usr/bin/dirname $0)/$(/usr/bin/basename $0) fo_real &
  exit
fi

Rest of script is here....

Le premier appel au script renvoie avec l'état de sortie 0, mais le deuxième appel au script continue de fonctionner avec PPID = 1.

Vivant
la source
0

Probablement parce que son processus parent est terminé et que le signal de terminaison se propage à ses enfants, qui ne le bloquent pas (et dans le cas où SIGKILLils ne le peuvent même pas).

peterph
la source