Wie kann ein Langzeitprozess für ein Udev-Ereignis ausgeführt werden?

11

Ich möchte eine PPP- Verbindung herstellen, wenn mein USB-Modem angeschlossen ist. Daher verwende ich diese udevRegel:

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

(Mein Modem erscheint in /devals ttyACM0)

newPPP.sh:

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

Problem:

Das udevEreignis wird ausgelöst und newPPP.sh wird ausgeführt, aber der newPPP.shProzess wird nach ~ 4-5 Sekunden abgebrochen. ppphat keine Zeit zum Herstellen einer Verbindung (das Zeitlimit für die Einwahl beträgt 10 Sekunden).

Wie kann ich einen langen Prozess ausführen, der nicht getötet wird?

Ich habe es versucht nohup, aber es hat auch nicht funktioniert.

System: Arch Linux

Aktualisieren

Ich fand eine Lösung hier , dank maxschlepzig .

Ich verwende at nowmeinen Job getrennt vom udev-Prozess.

Die eine Frage bleibt jedoch unbeantwortet: Warum arbeiten nohupund &nicht arbeiten?

Gemeinschaft
quelle

Antworten:

11

Wenn Sie eine anständige Distribution mit Systemd-Unterstützung ausführen, ist die Verwendung einer Geräteeinheit der einfachste und technisch sicherste Weg .

Auf diese Weise hat systemd die volle Kontrolle über das lang laufende Skript und kann den Prozess sogar ordnungsgemäß beenden, sobald das Gerät heruntergefahren / entfernt wird. Wenn Sie den Prozess trennen, geben Sie die vollständige Kontrolle über den Prozessstatus auf und seine Geschichte.

Außerdem können Sie den Status des Geräts und des angeschlossenen Dienstes durch Ausführen überprüfen systemctl status my-ppp-thing.device.

In diesem Blogbeitrag finden Sie weitere Beispiele und Details.

Elias Probst
quelle
6

Heutzutage verwendet udev cgroups, um gespawnte Aufgaben zu suchen und zu zerstören. Eine Lösung besteht darin, "at now" oder "batch" zu verwenden. Eine andere Lösung ist zu tun Doppelgabel und „relocate“ -Prozess zu einem anderen cgroup. Dies ist ein Beispiel für Python-Code (ähnlicher Code kann in jeder Sprache geschrieben werden):

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

Die Debug-Ausgabe kann beispielsweise an syslog gesendet werden.

Alexandre Kandalintsev
quelle
1
Warum sollte udev so weit gehen, um hervorgebrachte Prozesse zu zerstören?
user30747
Ich vermute, es liegt daran, dass von udev gestartete Programme den Daemon blockieren (z. B. mit einer udev-Regel, die mit dem Anschließen einer externen Anzeige verbunden ist, verhindert ein lang laufendes Programm, dass die neue Anzeige tatsächlich verwendet wird). Ich bin mir sicher, dass dies seine eigenen technischen Gründe hat, aber bedeutet, dass hervorgebrachte Prozesse wichtige Teile des Systems aufhalten können und getötet werden müssen.
tobek
2

Shell kann Befehle im Hintergrund ausführen:

(

lots of code

) &

Befehle, die durch geschweifte Klammern mit kaufmännischem Und nach ihnen gruppiert werden, werden asynchron in einer Unterschale ausgeführt. Ich verwende dies, um automatisch eine Verbindung herzustellen, wenn ein USB-Modem angeschlossen und umgeschaltet wird. Es dauert ungefähr 20 Sekunden und funktioniert gut unter udev.

user42295
quelle
In einer solchen Situation möchten Sie möglicherweise stderr, stdout und stderr umleiten.
mdpc
@mdpc hmm ... warum? Ich habe gesehen, dass usb_modeswitch Streams in diesem Szenario schließt: exec 1 <& - 2 <& - 5 <& - 7 <& -
user42295
1

Ich habe es mit setsid arbeiten lassen. Mein RUN-Teil der udev-Regel:

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

dann im Skript:

#!/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....

Der erste Aufruf des Skripts wird mit dem Exit-Status 0 zurückgegeben, der zweite Aufruf des Skripts wird jedoch weiterhin mit PPID = 1 ausgeführt.

Lebt
quelle
0

Wahrscheinlich, weil der übergeordnete Prozess beendet ist und sich das Beendigungssignal an die untergeordneten Signale weitergibt, die es nicht blockieren (und falls SIGKILLsie es überhaupt nicht können).

Peterph
quelle