Uzyskaj ssh do przekazywania sygnałów


22

Chcę mieć możliwość wysyłania sygnałów (najważniejszy jest SIGINT) przez ssh.

To polecenie:

ssh server "sleep 1000;echo f" > foo

rozpocznie tryb uśpienia na serwerze i po 1000 sekundach umieści „f \ n” w pliku foo na moim komputerze lokalnym. Jeśli nacisnę CTRL-C (tj. Wyślę SIGINT do ssh), to zabije ssh, ale nie zabije snu na zdalnym serwerze. Chcę, żeby zabiło sen na zdalnym serwerze.

Więc próbowałem:

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

Ale jeśli stdin nie jest terminalem, pojawia się ten błąd:

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

a następnie SIGINT nadal nie jest przekazywany.

Więc próbowałem:

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

Ale wtedy wyjście w foo nie jest „f \ n”, ale zamiast „f \ r \ n”, co jest katastrofalne w mojej sytuacji (ponieważ moje dane wyjściowe to dane binarne).

W powyższym przykładzie używam „sleep 1000; echo f”, ale w rzeczywistości jest on dostarczany przez użytkownika, więc może zawierać wszystko. Jeśli jednak uda nam się sprawić, że będzie działał dla „snu 1000; echo f”, najprawdopodobniej sprawimy, że będzie działał we wszystkich realistycznych sytuacjach.

Naprawdę nie dbam o to, aby uzyskać pseudo-terminal na drugim końcu, ale nie byłem w stanie znaleźć żadnego innego sposobu na uzyskanie ssh do przekazania mojego SIGINT.

Czy jest inny sposób?

Edytować:

Użytkownik może wydawać polecenia odczytujące dane binarne ze standardowego wejścia, takie jak:

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

Użytkownik może wydawać polecenia wymagające dużej mocy obliczeniowej, takie jak:

ssh server "timeout 1000 burnP6"

Edycja2:

Wydaje mi się, że wersja działa:

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

Dzięki digital_infinity za wskazanie mi właściwego kierunku.


1
Myślę, że twoje rzeczywiste użycie sshmusi być bardziej skomplikowane niż to, co pokazujesz jako przykłady, ponieważ możesz uzyskać pożądane zachowanie za pomocą prostej rearanżacji: sleep 1000 && ssh server "echo f" > foo(Musi być &&, nie ;, aby zabijanie sleepuniemożliwiało uruchomienie sshpolecenia). Jeśli ja mam rację, proszę, aby przykłady były bardziej reprezentatywne dla faktycznego wykorzystania, aby można było podać lepszą odpowiedź.
— Warren Young,

Prawidłowo: tryb uśpienia i echa to w rzeczywistości skrypty dostarczone przez użytkownika, a nie dosłownie tryb uśpienia i echa. Nie wiemy więc, co robią, i powinniśmy zakładać najgorsze.
— Ole Tange

Sooo ... wymyślisz lepsze przykładowe polecenie, prawda? Taki, w którym prosta zmiana układu nie rozwiązuje problemu? Zadajesz dobre pytanie i chciałbym, aby na nie udzielono odpowiedzi, ale jest mniej prawdopodobne, że otrzymasz odpowiedź, jeśli „więc nie rób tego, to” jest rozsądną odpowiedzią.
— Warren Young,

Och, nawiasem mówiąc ... Nie rób tego;)
— Tim

Jak wyjaśniono w pytaniu: „” „W powyższym przykładzie używam„ sleep 1000; echo f ”, ale w rzeczywistości jest on dostarczany przez użytkownika, więc może zawierać wszystko„ ”„
— Ole Tange

Odpowiedzi:


10

Krótka odpowiedź:

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

i zatrzymaj program CTRL + N.

Długie wyjaśnienie:

  1. Musisz użyć sttyopcji, intraby zmienić serwer lub lokalny znak przerwania, aby nie kolidowały ze sobą. W powyższym poleceniu zmieniłem znak przerwania serwera na CTRL + N. Możesz zmienić lokalny charakter przerwań i pozostawić serwer bez zmian.
  2. Jeśli nie chcesz, aby znak przerwania był na wyjściu (i jakikolwiek inny znak kontrolny), użyj stty -echoctl.
  3. Musisz upewnić się, że znaki kontrolne są włączone na serwerze bash wywołanym przez sshd. Jeśli nie, możesz skończyć z procesami, które wciąż się zawieszają po wylogowaniu.stty isig
  4. Właściwie łapiesz SIGINTsygnał za trap '/bin/true' SIGINTpomocą pustej instrukcji. Bez pułapki nie będziesz mieć żadnego standardowego sygnału po sygnale SIGINT na swoim końcu.

Wydaje się, że nie radzi sobie dobrze z wejściami binarnymi: seq 1000 | gzip | ssh -t -t server "stty isig intr ^ N -echoctl; trap '/ bin / true' SIGINT; sleep 1; zcat | bzip2" | bzcat> foo;
— Ole Tange

Nie możesz przerwać konsoli, jeśli ustawisz standardowe wejście dla ssh dla czegoś innego niż konsola. W takim przypadku musisz przerwać przez strumień standardowego wejścia.
— digital_infinity

Odkryłem, że to seq 1000 | gzip | ssh -tt dell-test "zcat|bzip2" | bzcat > footeż nie działa. Aby to polecenie działało, musimy je usunąć -tt. Przydział pseudo terminala prawdopodobnie wymaga pewnej ilości danych wejściowych ze standardowego wejścia
— digital_infinity

Próbowałem uuencode. W tej wersji nie działa: cat foo.gz | perl -ne 'pakiet wydruku („u”, $ _) ”| ssh -t -t server 'perl -ne "print unpack (\" u \ ", \ $ _)" | zcat | gzip | perl -ne "pakiet wydruku (\" u \ ", \ $ _)" '| perl -ne 'print unpack ("u", $ _)'> foo2.gz
— Ole Tange

1
Mam to: (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. Chociaż znak przerwania nie działa - potrzebujemy metody transmisji dla znaku przerwania, gdy standardowe wejście jest zajęte .
— digital_infinity

3

Wypróbowałem wszystkie rozwiązania i było to najlepsze:

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


Nie zatrzymuje to sleepprocesu w przypadku utraty połączenia.
— blueyed

Po utracie połączenia stdin zostaje zerwane, odblokowując kota, który zabije grupę procesów. To, czy ten sygnał przerwania jest wystarczający dla twojego zadania, jest innym pytaniem.
— Eric Woodruff,

To powinno wystarczyć sleep, prawda? Dodałem kilka date >> /tmp/killedpo cat, ale nie zostało uruchomione. Czy jest jakiś limit czasu? Używam Zsh normalnie, ale przetestowałem go również za pomocą bash jako zdalnej powłoki logowania.
— niebiesko

Myślę, że jesteś na łasce limitu czasu połączenia.
— Eric Woodruff,

Czy istnieją ustawienia, aby to kontrolować? Po stronie klienta -o ServerAliveInterval=3 -o ServerAliveCountMax=2pozwala to szybko wykryć, ale czy jest coś po stronie serwera?
— niebieskawy

2

Myślę, że możesz znaleźć PID procesu uruchomionego na serwerze i wysłać sygnał za pomocą innego sshpolecenia (takiego jak to ssh server "kill -2 PID":).

Używam tej metody do wysyłania sygnałów rekonfiguracyjnych do aplikacji działających na innym komputerze (moje aplikacje łapią SIGUSR1 i czytają plik konfiguracyjny). W moim przypadku znalezienie PID jest łatwe, ponieważ mam unikalne nazwy procesów i mogę znaleźć PID, wysyłając psżądanie za pośrednictwem ssh.


Nie widzę kuloodpornego sposobu znalezienia PID programu uruchamianego na odległość. Pamiętaj, że podany przez użytkownika. Może to być: ssh server 'exec $ (echo fyrrc 1000 | / usr / games / rot13)'
— Ole Tange

1

Rozwiązanie rozwinęło się w 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

----- polecenie.sh

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

----- na lokalnym terminalu

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

Cześć! Myślę, że możesz uczynić swoją odpowiedź o wiele bardziej przydatną, wyjaśniając, tak szczegółowo, jak uznasz to za istotne, jak to działa. Nie wahaj się go edytować, aby wstawić nowe informacje.
— dhag
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.