Lass ssh Signale weiterleiten


22

Ich möchte in der Lage sein, über ssh Signale zu senden (SIGINT ist das wichtigste).

Dieser Befehl:

ssh server "sleep 1000;echo f" > foo

wird den Schlafmodus auf dem Server starten und nach 1000 Sekunden 'f \ n' in die Datei foo auf meinem lokalen Computer einfügen. Wenn ich STRG-C drücke (dh SIGINT an ssh senden), wird ssh beendet, der Schlaf auf dem Remote-Server wird jedoch nicht beendet. Ich möchte, dass es den Schlaf auf dem Remote-Server beendet.

Also habe ich versucht:

ssh server -t "sleep 1000;echo f" > foo

Aber wenn stdin kein Terminal ist, bekomme ich diese Fehlermeldung:

Pseudo-terminal will not be allocated because stdin is not a terminal.

und dann wird SIGINT immer noch nicht weitergeleitet.

Also habe ich versucht:

ssh server -t -t "sleep 1000;echo f" > output

Aber dann ist die Ausgabe in foo nicht 'f \ n', sondern 'f \ r \ n', was in meiner Situation katastrophal ist (da es sich bei meiner Ausgabe um Binärdaten handelt).

In der obigen Beschreibung verwende ich "sleep 1000; echo f", aber in Wirklichkeit wird dies vom Benutzer bereitgestellt und kann daher alles enthalten. Wenn wir es jedoch für "sleep 1000; echo f" zum Laufen bringen können, können wir es höchstwahrscheinlich für alle realistischen Situationen zum Laufen bringen.

Es ist mir wirklich egal, ob ich ein Pseudo-Terminal am anderen Ende bekomme, aber ich konnte keinen anderen Weg finden, um ssh dazu zu bringen, mein SIGINT weiterzuleiten.

Gibt es eine andere Art und Weise?

Bearbeiten:

Der Benutzer könnte Befehle geben, die Binärdaten aus stdin lesen, wie zum Beispiel:

seq 1000 | gzip | ssh server "zcat|bzip2; sleep 1000" | bzcat > foo

Der Benutzer kann Befehle geben, die CPU-intensiv sind, wie zum Beispiel:

ssh server "timeout 1000 burnP6"

Edit2:

Die Version, die für mich zu funktionieren scheint, ist:

your_preprocessing |
  uuencode a | ssh -tt -oLogLevel=quiet server "stty isig -echoctl -echo ; uudecode -o - |
your_command |
  uuencode a" | uudecode -o - |
your_postprocessing

Vielen Dank an digital_infinity für den Hinweis in die richtige Richtung.


1
Ich denke, Ihr tatsächlicher Gebrauch von sshmuss komplizierter sein als das, was Sie als Beispiele zeigen, weil Sie das gewünschte Verhalten durch eine einfache Neuanordnung erreichen können: sleep 1000 && ssh server "echo f" > foo(Das muss &&nicht ;so sein, dass das Töten sleepdie sshAusführung des Befehls verhindert .) Wenn ich Bitte machen Sie Ihre Beispiele repräsentativer für Ihre tatsächliche Verwendung, damit eine bessere Antwort gegeben werden kann.
Warren Young

Richtig: Schlaf und Echo sind tatsächlich vom Benutzer bereitgestellte Skripte und nicht buchstäblich Schlaf und Echo. Wir wissen also nicht, was sie tun und sollten das Schlimmste annehmen.
Ole Tange

Sooo ... du wirst dir einen besseren Beispielbefehl einfallen lassen, oder? Eine, bei der eine einfache Neuanordnung das Problem nicht behebt? Sie stellen eine gute Frage, und ich würde sie gerne beantwortet sehen, aber es ist weniger wahrscheinlich, dass Sie eine Antwort erhalten, wenn Sie eine vernünftige Antwort erhalten, wenn Sie dies nicht tun.
Warren Young

Oh übrigens ... Tu das nicht;)
Tim

Wie in der Frage elabrated: "" Im obigen verwende ich "sleep 1000; echo f", aber in Wirklichkeit, die vom Benutzer geliefert wird, so kann es alles enthalten ""
Ole Tange

Antworten:


10

Kurze Antwort:

ssh -t fs "stty isig intr ^N -echoctl ; trap '/bin/true' SIGINT; sleep 1000; echo f" > foo

und beenden Sie das Programm mit STRG + N.

Lange Erklärung:

  1. Sie müssen die sttyOption verwenden intr, um den Server oder das lokale Interrupt-Zeichen so zu ändern , dass sie nicht miteinander kollidieren. Im obigen Befehl habe ich das Server-Interrupt-Zeichen in STRG + N geändert. Sie können Ihr lokales Interrupt-Zeichen ändern und das des Servers unverändert lassen.
  2. Wenn Sie nicht möchten, dass das Interrupt-Zeichen in Ihrer Ausgabe (und in jedem anderen Steuerzeichen) enthalten ist, verwenden Sie stty -echoctl.
  3. Sie müssen sicherstellen, dass Steuerzeichen in der von sshd aufgerufenen Server-Bash aktiviert sind. Wenn dies nicht der Fall ist, kann es vorkommen, dass Prozesse nach dem Abmelden immer noch hängen bleiben.stty isig
  4. Sie fangen das SIGINTSignal tatsächlich trap '/bin/true' SIGINTmit einer leeren Anweisung ab. Ohne die Falle haben Sie kein stdout nach SIGINT-Signal an Ihrem Ende.

Es scheint nicht gut mit Binäreingaben umzugehen: seq 1000 | gzip | ssh -t -t server "stty isig intr ^ N -echoctl; trap '/ bin / true' SIGINT; sleep 1; zcat | bzip2" | bzcat> foo;
Ole Tange

Sie können nicht über die Konsole unterbrechen, wenn Sie die Standardeingabe für ssh für etwas anderes als die Konsole festlegen. In diesem Fall müssen Sie durch den stdin-Stream unterbrechen.
digital_infinity

Ich fand, dass das seq 1000 | gzip | ssh -tt dell-test "zcat|bzip2" | bzcat > fooauch nicht funktioniert. Damit dieser Befehl funktioniert, müssen wir ihn entfernen -tt. Die Zuordnung der Pseudo-Terminals wird also wahrscheinlich von stdin
digital_infinity am

Ich habe den Uuencode ausprobiert. In dieser Version funktioniert es nicht: cat foo.gz | perl -ne 'print pack ("u", $ _)' | ssh -t -t server 'perl -ne "print entpacken (\" u \ ", \ $ _)" | zcat | gzip | perl -ne "print pack (\" u \ ", \ $ _)" '| perl -ne 'print entpacken ("u", $ _)'> foo2.gz
Ole Tange

1
Ich habe dies: (sleep 1; seq 1000 ) | gzip | uuencode bin | ssh -tt dell-test "stty isig intr ^N -echoctl -echo ; trap '/bin/true' SIGINT; sleep 1; uudecode -o /dev/stdout | zcat |bzip2 | uuencode bin2 " | uudecode -o /dev/stdout | bzcat >foo. Obwohl die Interrupt - Zeichen funktioniert nicht - brauchen wir eine Übertragungsmethode für die Interrupt - Zeichen während stdin ist besetzt .
digital_infinity

3

Ich habe alle Lösungen ausprobiert und dies war das Beste:

ssh host "sleep 99 < <(cat; kill -INT 0)" <&1

/programming/3235180/starting-a-process-over-ssh-using-bash-and-then-killing-it-on-sigint/25882610#25882610


Dies stoppt den sleepVorgang nicht, falls die Verbindung unterbrochen wird.
bläulich

Wenn die Verbindung unterbrochen wird, wird die stdin unterbrochen und die Katze wird freigegeben, wodurch die Prozessgruppe getötet wird. Ob dieses INTerrupt-Signal für Ihre Aufgabe gut genug ist, ist eine andere Frage.
Eric Woodruff

Es sollte gut genug für die sein sleep, nicht wahr? Ich habe einige date >> /tmp/killednach dem hinzugefügt cat, aber es wurde nicht ausgelöst. Ist eine Auszeit erforderlich? Ich benutze Zsh normalerweise, habe es aber auch mit bash als Remote-Login-Shell getestet.
bläulich

Ich denke, Sie sind dem Verbindungs-Timeout ausgeliefert.
Eric Woodruff

Gibt es Einstellungen, um dies zu steuern? Für die Client-Seite -o ServerAliveInterval=3 -o ServerAliveCountMax=2ermöglicht es, es schnell zu erkennen, aber gibt es etwas für die Server-Seite?
bläulich

2

Ich denke, Sie könnten die PID des Prozesses finden, den Sie auf dem Server ausführen, und ein Signal mit einem anderen sshBefehl senden (wie folgt:) ssh server "kill -2 PID".

Ich verwende diese Methode zum Senden von Rekonfigurationssignalen an Anwendungen, die auf einem anderen Computer ausgeführt werden (meine Anwendungen erfassen SIGUSR1 und lesen eine Konfigurationsdatei). In meinem Fall ist es einfach, eine PID zu finden, da ich eindeutige Prozessnamen habe und die PID durch Senden einer psAnfrage über finden kann ssh.


Ich sehe keinen kugelsicheren Weg, um die PID des Programms zu finden, das auf Remote ausgeführt wird. Denken Sie daran, dass es vom Benutzer angegeben wird. Es könnte sein: ssh server 'exec $ (echo fyrrc 1000 | / usr / games / rot13)'
Ole Tange

1

Die Lösung entwickelte sich zu http://www.gnu.org/software/parallel/parallel_design.html#Remote-Ctrl-C-and-standard-error-stderr

$SIG{CHLD} = sub { $done = 1; };
$pid = fork;
unless($pid) {
    # Make own process group to be able to kill HUP it later
    setpgrp;
    exec $ENV{SHELL}, "-c", ($bashfunc."@ARGV");
    die "exec: $!\n";
}
do {
    # Parent is not init (ppid=1), so sshd is alive
    # Exponential sleep up to 1 sec
    $s = $s < 1 ? 0.001 + $s * 1.03 : $s;
    select(undef, undef, undef, $s);
} until ($done || getppid == 1);
# Kill HUP the process group if job not done
kill(SIGHUP, -${pid}) unless $done;
wait;
exit ($?&127 ? 128+($?&127) : 1+$?>>8)

0

----- command.sh

#! /bin/sh
trap 'trap - EXIT; kill 0; exit' EXIT
(sleep 1000;echo f) &
read ans

----- am lokalen Terminal

sleep 864000 | ssh -T server command.sh > foo

Hallo! Ich denke, Sie könnten Ihre Antwort viel nützlicher machen, indem Sie so detailliert erklären, wie Sie es für relevant halten. Zögern Sie nicht, es zu bearbeiten, um neue Informationen einzufügen.
Dhag
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.