Warum erlaubt "su -c <Befehl> &" scheinbar, dass ein Befehl im Hintergrund ausgeführt wird, ohne aufzulegen

11

Ich half einem Kollegen, der Probleme mit einem Hintergrundprozess hatte, der zeitweise starb.

Ich fand heraus, dass sie den Hintergrundprozess starteten, indem sie sich beim Server anmeldeten und Folgendes ausführten:

su - <user> -c '<command>' &

"Aha", rief ich aus. "Wenn Sie einen Befehl mit" & "starten, wird er beim Verlassen des steuernden Terminals aufgelegt. Sie müssen so etwas wie nohup verwenden, um dies zu erreichen. Dieser Prozess muss wirklich die Ausführung als Daemon unterstützen, tut tut."

Wir haben den obigen Befehl getestet, um meinen Standpunkt zu demonstrieren, und ... es schien zu funktionieren: Der mit dem Befehl gestartete Prozess wurde nicht beendet, als wir das Terminal verließen, auf dem der obige Befehl ausgeführt wurde.

Befehl ist ein benutzerdefiniertes Python-Skript, dessen Ausgabe in eine Datei geht. Soweit ich das beurteilen kann, gibt es im Skript keine intelligente "Daemonize" -ähnliche Funktion. Es werden keine der Dinge ausgeführt, die erforderlich sind, um als Daemon ausgeführt zu werden, der auf der Wikipedia: Daemon (Computing): Creation- Seite aufgeführt ist.

Das Ausführen des Befehls verhält sich wie erwartet:

<command> &
exit

Im obigen Fall wird der durch den Befehl gestartete Hintergrundprozess beendet, wenn wir das Terminal verlassen.

Meine Frage lautet:

  1. Was passiert, wenn wir "su - -c &" hinzufügen, das verhindert, dass der Prozess beendet wird, wenn unser Terminal beendet wird? Ich möchte in Bezug auf das steuernde Terminal, die Standardeingabe und -ausgabe usw. im Detail verstehen.

  2. Ist dies ein vernünftiger Weg, um das Ziel zu erreichen, diesen Befehl als Hintergrundprozess auszuführen? Wenn nicht warum, nicht?

Ich möchte Best Practices in meinem Unternehmen verbreiten, muss jedoch in der Lage sein, meine Empfehlungen zu demonstrieren und zu unterstützen.

Ich möchte auch verstehen, was genau los ist.

Sam Elstob
quelle

Antworten:

12

Es gibt verschiedene Möglichkeiten, wie ein Prozess aufgrund eines sterbenden Terminals abgebrochen werden kann.

  1. Die erste Möglichkeit ist , dass die Terminal - Treiber im Kernel ein SIGHUP Signal senden an den Steuerungsprozess , für den das Endgerät die ist kontrollierende Endgerät . In den meisten Fällen ist der Steuerungsprozess die Shell, die anfänglich im Terminal gestartet wird, und das steuernde Terminal ist dasjenige, mit dem stdin, stdout und stderr verbunden sind. Ein Prozess wird beim Aufrufen vom steuernden Terminal getrennt setsid.

  2. Die zweite Möglichkeit besteht darin, dass die Shell beim Empfang von SIGHUP dieses Signal erneut an ihre Unterprozesse sendet - genauer an ihre Hintergrundjobs. Einige Shells (ksh, bash, zsh) verfügen über eine integrierte disownFunktion, die der Shell anweist, kein SIGHUP an einen bestimmten Job zu senden.

  3. Wenn das Terminal nicht mehr funktioniert und ein Programm versucht, daraus zu lesen, wird es über einen Dateiende-Zustand (oder möglicherweise über EIO für einen Hintergrundjob) informiert. Wenn das Terminal verschwindet und ein Programm versucht, darauf zu schreiben, wird der Schreibvorgang mit einem EIO-Fehler zurückgegeben. Dies kann dazu führen, dass das Programm beendet wird.

Was susich hier also ändert, ist, dass (2) normalerweise dazu führen würde, dass die anfängliche Shell den Hintergrundjob beendet. Da dieser Hintergrundprozess jedoch als ein anderer Benutzer ausgeführt wird, kann das Signal nicht geliefert werden und der Hintergrundprozess lebt weiter.

Gilles 'SO - hör auf böse zu sein'
quelle
Ich habe Root-Benutzer gesehen chroot --userspec root:root / sh -c "exec some_forever_process" &. Der Job wird als derselbe Benutzer ausgeführt, ohne nohupvorher oder disownspäter explizit . Wie kommt es also, dass das Signal in diesem Fall beim Term Exit nicht geliefert werden kann?
Toddius Zho
@ToddiusZho Presumable some_forever_processsollte für immer ausgeführt werden (ein Daemon) und schützt sich so vor dem Empfang von SIGHUP von einem Terminal-Exit (durch Ausführen in einer eigenen Prozessgruppe).
Gilles 'SO - hör auf böse zu sein'
bash / tail schützt nicht vor SIGHUP, aber das funktioniert immer noch: `` `local $ ssh root @ REMOTE_HOST remote # chroot --userspec root: root / sh -c" exec bash -c 'tail -f / dev / null '"& [1] 6376 remote # ps -p $! --no-Heading -o pid, uid, Befehl -ww 6376 0 tail -f / dev / null remote # lokale $ ssh root beenden @ REMOTE_HOST remote # ps -p 6376 --no-Heading -o pid, uid, Befehl -ww 6376 0 tail -f / dev / null `` `
Toddius Zho