Kill-Prozess, der von ssh ausgelöst wird, wenn ssh stirbt

23

Dies ist eine Frage, die nicht nur hier, sondern auch an anderen Stellen des Stack-Exchange-Netzwerks mehrfach angesprochen wurde (z. B. wie man ssh veranlasst, den Remote-Prozess zu beenden, wenn ich ssh selbst unterbreche? ). Ich kann jedoch keine der Lösungen für mich arbeiten lassen.

Ich führe einen Befehl über ssh aus. Immer wenn ich ssh beende, möchte ich, dass der Befehl ebenfalls stirbt. Dieser Befehl ist ein Daemon namens ktserver, der auf unbestimmte Zeit ausgeführt wird, bis Sie Strg-C drücken.

Ich führe es folgendermaßen aus: ssh -t compute-0-1 ktserverWenn ich Strg-C drücke, wird der Vorgang ordnungsgemäß beendet und die SSH-Sitzung wird beendet.

Wenn ich jedoch nicht Strg-C drücke, sondern den ssh-Prozess mit dem killBefehl beende (z. B. SIGINT oder SIGHUP senden), ktserverbleibt der Prozess am Leben.

Wie kann ich das ktserverSterben immer unabhängig davon machen, wie sshes getötet wird?

BEARBEITEN : Wenn ktserverich stattdessen etwas völlig anderes ausführe, wie zum Beispiel gedit, funktioniert alles wie ein Zauber (dh gedit stirbt, wenn die Verbindung unterbrochen wird). Daher ist möglicherweise etwas mit dem Prozess selbst nicht in Ordnung. Zum Beispiel dachte ich, dass es SIGHUP oder SIGINT ignorieren könnte. Wenn ich jedoch kill -1 ktserveroder kill -2 ktserverstarte, stirbt der Prozess wie erwartet.

EDIT2 : Wie Mark Plotnick betont , hängt das Problem damit zusammen, dass auf dem SSH-Kanal keine Kommunikation zirkuliert. Ich habe bestätigt, indem ich ssh -t <host> readden ssh-Prozess anschließend ausgeführt und beendet habe. readwar noch am Leben und trat.

GermanK
quelle
Hast du es versucht kill -9 ktserver?
@HermanTorjussen Klar, das funktioniert. Das Problem ist, dass dieser Befehl in einem anderen Prozess ausgeführt wird und ich möglicherweise nicht die Kontrolle über die vielen Möglichkeiten habe, die dazu führen können, dass mein Prozess abstürzt, und daher die SSH-Sitzung damit. Ich brauche also einen zuverlässigen Weg, um sicherzugehen, dass ktserver immer mit ihnen abstirbt, wenn mein Prozess abstirbt.
GermanK
Meine Erfahrung mit Linux ist, dass, wenn der Remote-Befehl keine E / A für die tote TCP-Verbindung ausführt, er weiter ausgeführt wird. Ich habe ssh example.com dd ...Aufträge ausgeführt, die auch Stunden nach dem sshUnterbrechen der Verbindung aufgrund von Netzwerkproblemen vollständig ausgeführt wurden. Wenn Sie ktserverdie Option ändern können , ab und zu etwas auszugeben, kann dies eine Problemumgehung sein.
Mark Plotnick
@MarkPlotnick In der Tat habe ich versucht, readauf dem Remote-Computer zu laufen, und nachdem ich die SSH-Verbindung beendet habe, bin ich readnicht gestorben. Leider kann ich ktserver nicht ändern, um etwas auszugeben. Gibt es dann keine Lösung?
GermanK
2
Ich gehe davon aus, dass beim Tod von ssh auch Ihre Shell stirbt. Sie können Ihre Shell so konfigurieren, dass beim Beenden ein Signal -1 (SIGHUP) gesendet wird. ( shopt -s huponexit). Können Sie testen, ob dies bei Ihnen funktioniert?
Hennes

Antworten:

13

Normalerweise stirbt die Shell auch, wenn die SSH-Verbindung unterbrochen wird. Sie können Ihre Shell so konfigurieren, dass sie ein Signal -1 (SIGHUP) sendet, wenn sie an alle untergeordneten Elemente terminiert.

Für Bash können Sie diese Option über den eingebauten Befehl shopt konfigurieren . ( shopt -s huponexit).

Für zsh willst du .setoptHUP

Hennes
quelle
Ich dachte, dies wäre die Antwort auf mein aktuelles Problem, aber es scheint nicht zu funktionieren. Ich führe aus: ssh $ host "scp LargeFile.dat $ OtherHost: / tmp" & pid = $! und dann versuchen, diese Übertragung zu stoppen mit: shopt -s huponexit; töte $ pid, aber der scp hört nicht auf, wenn ich den ssh töte, den ich gestartet habe. Irgendwelche Gedanken?
David Doria
Können Sie mit den festgelegten Shell-Optionen testen, bevor Sie den Befehl scp starten? Oder indem Sie eine Shell starten, shopt setzen und scp starten?
Hennes
2
Dies funktioniert für mich, aber ich musste zuerst sicherstellen, dass ich ssh -t -t( -tzweimal beachten !) Verwendet habe , was die Zuweisung von tty erzwingt, anstatt nur pty.
Nicolas Wu
13

Ich fand das einfach -t -tals Argument, um sshes zum Laufen zu bringen. Ich musste huponexitweder auf die ursprüngliche noch auf die entfernte Shell setzen.

Ich habe das wie folgt getestet:

Funktioniert nicht:

ssh user@remote sleep 100
^C

Dadurch wurde die SSH-Sitzung beendet, aber ich kann sehen, dass der Ruhezustand auf dem Remotehost noch ausgeführt wird (wird ps -ef | grep sleepangezeigt).

Funktioniert:

ssh -t -t user@remote sleep 100
^C

Dadurch wird die SSH-Sitzung beendet und der Remote-Schlafvorgang wurde ebenfalls beendet. Ich habe auch überprüft, dass das Signal, das an den Remote-Prozess gesendet wird, ist, SIGINTwenn Sie Control- verwenden C. Ich habe auch überprüft, dass SIGKILL (-9), das auf den sshProzess angewendet wurde, auch den Remote-Prozess beendet.

EDIT 1:

Das galt für sleep... für hartnäckigere Remote-Prozesse. Ich fand, dass ssh^ C anders gehandhabt wird als SIGINT. Ctrl- hat Cfunktioniert, aber kill -INT $pidnicht

Folgendes habe ich schließlich für meine eigentliche Bewerbung gefunden (aus den anderen Antworten stehlen).

ssh -t -t -i id_rsa user@mic0 "/bin/sh -O huponexit -c 'sleep 100'"

Beachten Sie die geschachtelte Verwendung von doppelten und einfachen Anführungszeichen. Beachten Sie, dass Ihr Remote-Prozess auf SIGHUP reagieren MUSS, indem er tatsächlich beendet wird!

Mark Lakata
quelle
Dies funktionierte am besten für mich, aber zur Info, es verursachte auch das Durchsickern von Terminal-Steuerzeichen, was zu lustigen Ausgaben führen kann. In meinem Fall bestand die einfache Problemumgehung darin, aufgerufene Befehle umzubrechen und ihre Ausgabe weiterzuleiten cat. Zum Beispielssh -ttq user@host '{ cmd; cmd; } | cat'
Droj
Ctrl-Cist NICHT immer gleichbedeutend mit kill -INT $pid, siehe meine Antwort auf unix.stackexchange.com/questions/377191/… und eine andere auf stackoverflow.com/questions/8398845/… für die blutigen Details ;-)
thecarpy
@thecarpy - Ihre erste Antwort besagt, dass Strg-C mit SIGINT verwandt ist , und die andere Antwort besagt, dass ^CSIGINT gesendet wird . Was ist der genaue Unterschied, wenn sie nicht gleichwertig sind?
Mark Lakata
1

Wenn ssh keine Signale verbreitet, empfängt es was würden Sie von ihm erwarten?

UPD. (speziell für JosephR): Es handelt sich offensichtlich um einen Fehler, der sich aus einem Missverständnis ergibt - "Kill-Prozess, der von ssh ausgelöst wird, wenn ssh stirbt". SSH erzeugt normalerweise keine Prozesse (manchmal schon, aber das ist eine andere Geschichte), SSHD hingegen, wenn wir uns die andere Seite der Verbindung ansehen. SSH stützt sich lediglich auf die Pseudo-Terminal-Abstraktion, die der Remote-Server hat. Deshalb kann nur die Fähigkeit des Terminals helfen, Signale an die angeschlossenen Prozesse zu senden. Dies ist für jedes UNIX-ähnliche System etwas sehr grundlegend.

Poige
quelle
1
Dies gibt keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klarstellung zu bitten, hinterlassen Sie einen Kommentar unter seinem Beitrag.
Anthon
@Anthon, das ist eine Erklärung. Aber niemand sagt, dass dies die einzig richtige Antwort sein sollte. Vielen Dank für Ihren Kommentar unten.
Poige
1
@poige Vielleicht die Erklärung ausarbeiten, damit es dem OP und anderen von Nutzen sein kann.
Joseph R.
@ JosephR., Ok, nur für dich.
Poige
1
Wenn ich sage "Kill-Prozess, der von sshd erzeugt wird, wenn die ssh-Verbindung unterbrochen wird", würde es für Sie besser klingen? Ich glaube nicht, dass eine Neuformulierung mein Problem in irgendeiner Weise löst.
GermanK
0

Die hier gepostete Lösung hat bei mir nicht funktioniert, aber da diese Frage zuerst auftauchte, als ich nach einer Lösung für ein ähnliches Problem suchte und hier auch ein -t -tTrick erwähnt wurde, werde ich eine Lösung posten, die bei mir funktioniert hat, damit andere es versuchen.

ssh -t -t -o ControlMaster=auto -o ControlPath='~/test.ssh' your_remote_ip_goes_here "your_long_running_command" &
sleep 100
ssh -o ControlPath='~/test.ssh' -O exit your_remote_ip_goes_here

Mein Langzeitbefehl wurde nicht mehr ausgeführt, als die Verbindung auf diese Weise beendet wurde.

Greg0ry
quelle