Jak uruchomić długi proces na zdarzeniu Udev?

11

Chcę uruchomić połączenie ppp, gdy mój modem USB jest podłączony, więc używam tej udevreguły:

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

(Mój modem pojawia się /devjako ttyACM0)

newPPP.sh:

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

Problem:

W udevZdarzenie, a newPPP.sh jest uruchomiony, ale newPPP.shproces jest zabity po ~ 4-5s. pppnie ma czasu na połączenie (limit czasu wynosi 10 sekund na połączenie dial-up).

Jak mogę uruchomić długi proces, który nie zostanie zabity?

Próbowałem użyć nohup, ale to też nie działało.

System: Arch Linux

Aktualizacja

Tutaj znalazłem rozwiązanie , dzięki maxschlepzig .

Używam at nowdo uruchamiania mojej pracy odłączonej od procesu udev.

Ale jedno pytanie pozostaje bez odpowiedzi: dlaczego działają nohupi &nie działają?

Społeczność
źródło

Odpowiedzi:

11

Jeśli prowadzisz przyzwoitą dystrybucję ze wsparciem systemowym, najłatwiejszym i najbezpieczniejszym technicznie sposobem jest użycie urządzenia .

W ten sposób systemd będzie miał pełną kontrolę nad długo działającym skryptem, a nawet będzie mógł poprawnie zakończyć proces po zamknięciu / usunięciu urządzenia - odłączenie procesu oznacza, że ​​rezygnujesz z pełnej kontroli stanu procesu i jego historia.

Oprócz tego będziesz mógł sprawdzić status urządzenia i podłączonej usługi, uruchamiając systemctl status my-ppp-thing.device.

Zobacz także ten post na blogu, aby uzyskać więcej przykładów i szczegółów.

Elias Probst
źródło
6

W dzisiejszych czasach udev używa cgroups do wyszukiwania i niszczenia spawnowanych zadań. Jednym z rozwiązań jest użycie „na teraz” lub „partii”. Innym rozwiązaniem jest wykonanie podwójnego rozwidlenia i „przeniesienie” procesu do innej grupy. To jest przykładowy kod python (podobny kod można napisać w dowolnym języku):

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

Dane wyjściowe debugowania można wysłać np. Do syslog.

Alexandre Kandalintsev
źródło
1
Dlaczego udev miałby tak bardzo dążyć do niszczenia spawnowanych procesów?
user30747,
Zgaduję, że dzieje się tak, ponieważ programy uruchamiane przez udev blokują demona (np. Gdy reguła udev jest podłączona do podłączania zewnętrznego wyświetlacza, długo działający program zapobiegnie faktycznemu użyciu nowego ekranu). Jestem pewien, że ma to swoje uzasadnienie techniczne, ale oznacza, że ​​odradzane procesy mogą pomieścić główne części systemu i muszą zostać zabite.
tobek
2

Shell ma możliwość uruchamiania poleceń w tle:

(

lots of code

) &

Polecenia pogrupowane według nawiasów klamrowych po nich będą wykonywane asynchronicznie w podpowłoce. Używam tego do automatycznego łączenia, gdy modem USB jest podłączony i przełączany. To zajmuje około 20 sekund i działa dobrze pod udev.

użytkownik42295
źródło
W takiej sytuacji możesz chcieć przekierować stderr, stdout i stderr.
mdpc
@mdpc hmm ... dlaczego? Widziałem, że usb_modeswitch zamyka strumienie w tym scenariuszu: exec 1 <& - 2 <& - 5 <& - 7 <& -
user42295
1

Mam go do pracy z Setsem. Moja RUN część reguły udev:

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

następnie w skrypcie:

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

Pierwsze wywołanie skryptu powraca ze statusem wyjścia 0, ale drugie wywołanie skryptu nadal działa z PPID = 1.

Żyje
źródło
0

Prawdopodobnie dlatego, że proces macierzysty został zakończony, a sygnał zakończenia propaguje się do jego dzieci, które go nie blokują (a SIGKILLnawet jeśli nie mogą).

Peter
źródło