Komenda ssh nieoczekiwanie jest kontynuowana w innym systemie po zakończeniu ssh


11

Korzystam z poniższego polecenia i monitoruję plik wyjściowy w innym systemie:

ssh $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

Jeśli zabiję komendę ssh za pomocą ^Club po prostu zabijając terminal, na którym jestem zalogowany, oczekiwałbym, że zdalne polecenie również się zakończy. Tak się jednak nie dzieje: /tmp/countniezależnie pobiera wszystkie liczby 1–5 i ps -ejHpokazuje, że powłoka i jej sleepdziecko nadal działają.

Czy jest to oczekiwane zachowanie i czy jest gdziekolwiek udokumentowane? Czy mogę to wyłączyć? Po przeczytaniu, spodziewałem się, że będę musiał wyraźnie włączyć takie zachowanie bez nohup, nie żeby było to ustawienie domyślne.

Przejrzałem strony podręcznika dla ssh i sshd, ale nie zauważyłem niczego oczywistego, a Google wskazuje mi instrukcje dotyczące włączania tego zachowania, a nie wyłączania go.

Korzystam z systemu Red Hat Enterprise Linux 6.2 z loginem root i powłoką bash na obu systemach.

Odpowiedzi:


11

Odpowiedź Uthera nakazuje alokować terminal, ale nie wyjaśnia, dlaczego. Przyczyna nie jest specyficzna dla ssh, jest to kwestia generowania i propagacji sygnału. Zapraszam do lektury Co powoduje wysyłanie różnych sygnałów? po więcej tła.

Na zdalnym hoście istnieją dwa odpowiednie procesy:

  • instancja ssh daemon ( sshd), która przekazuje dane wejściowe i wyjściowe programu zdalnego do terminala lokalnego;
  • powłoka, która uruchamia tę forpętlę.

Powłoka może umrzeć w naturalny sposób, gdy osiągnie koniec pętli lub wystąpi błąd krytyczny, lub na sygnał. Pytanie brzmi: dlaczego pocisk miałby odbierać sygnał?

Jeśli zdalna powłoka jest podłączona do sshdpotoków, co dzieje się, gdy podasz polecenie w sshwierszu poleceń, to umrze z SIGPIPE, jeśli sshdwyjdzie, a powłoka spróbuje zapisać na potoku. Dopóki powłoka nie zapisuje do potoku, nie otrzyma SIGPIPE. Tutaj powłoka nigdy nie zapisuje niczego na standardowym wyjściu, więc może żyć wiecznie.

Możesz przekazać -topcję ssh, aby nakazała emulować terminal po stronie zdalnej i uruchomić określone polecenie w tym terminalu. Następnie, jeśli klient SSH zniknie, sshdzamyka połączenie i wychodzi, niszcząc terminal. Gdy urządzenie końcowe zniknie, każdy działający w nim proces otrzymuje SIGHUP . Jeśli więc zabijesz klienta SSH (za pomocą killlub przez zamknięcie terminala, w którym działa klient), zdalna powłoka zostanie ZWIĘKSZONA.

Po przejściu -topcji SSH przekazuje również SIGINT . Jeśli naciśniesz Ctrl+ C, zdalna powłoka otrzyma SIGINT.


Użyj -ttzamiast, -tjeśli sam ssh nie ma przydzielonego tty. SSH nie otrzyma przydzielonego tty, jeśli ssh zostanie natychmiast uruchomione w tle po wywołaniu za pomocą opcji takich jak -flub -n.
Miron V

3

Spróbuj przydzielić sshkomendę psuedo-tty .

ssh -t $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

Po odłączeniu sesji ssh proces powinien zostać zakończony.

Ponieważ jest to pseudo-tty, inicjalizacja powłoki prawdopodobnie nie spowoduje źródłowych plików konfiguracyjnych, pozostawiając polecenie w bardzo czystym środowisku. Może być konieczne skonfigurowanie .ssh/environmentpliku, który definiuje zmienne środowiskowe, takie jak PATH. Odman 1 ssh

Additionally, ssh reads ~/.ssh/environment, and adds lines of the format 
“VARNAME=value” to the environment if the file exists and users are allowed
to change their environment.  For more information, see the 
PermitUserEnvironment option in sshd_config(5).

2

Alternatywą do użycia -topcji, sshaby zdalne polecenie zakończyło się po sshwyjściu klienta (lub zabiciu), nazwanego potoku można użyć do konwersji „EOF na SIGHUP”, gdy standardowe wejście sshdjest zamknięte (patrz Bug 396 - sshd osierocone procesy, gdy nie ma przydzielonego pty ).

# sample code in Bash
# press ctrl-d for EOF
ssh localhost '
TUBE=/tmp/myfifo.fifo
rm -f "$TUBE"
mkfifo "$TUBE"
#exec 3<>"$TUBE"

<"$TUBE" sleep 100 &  appPID=$!

# cf. "OpenSSH and non-blocking mode", 
# http://lists.mindrot.org/pipermail/openssh-unix-dev/2005-July/023090.html
#cat >"$TUBE"
#socat -u STDIN "PIPE:$TUBE"
dd of="$TUBE" bs=1 2>/dev/null
#while IFS="" read -r -n 1 char; do printf '%s' "$char"; done > "$TUBE"

#kill -HUP -$appPID 
kill $appPID

rm -f "$TUBE"
'

1

To najlepszy sposób, w jaki udało mi się to zrobić. Chcesz czegoś po stronie serwera, które próbuje odczytać standardowe wejście, a następnie zabija grupę procesów, gdy to się nie powiedzie, ale chcesz również standardowe wejście po stronie klienta, które blokuje się, dopóki proces po stronie serwera nie zostanie zakończony i nie pozostawi długotrwałych procesów takich jak <( nieskończoność snu).

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

Wydaje się, że tak naprawdę nigdzie nie przekierowuje standardowego wejścia, ale działa jako wejście blokujące i pozwala uniknąć przechwytywania naciśnięć klawiszy.

Odpowiedni błąd openssh: https://bugzilla.mindrot.org/show_bug.cgi?id=396#c14


0

Jeśli chcesz wyłączyć to (pozornie domyślne zachowanie), musisz włączyć ssh-keep-alive po stronie klienta lub serwera.

Jeśli spojrzysz na opcje ssh-keep-alive na stronach podręcznika man, zobaczysz, że są one domyślnie wyłączone.


0

Moja odpowiedź jest oparta na teru. Potrzebuję skryptu pomocniczego ~/helperna serwerze server.ip:

#!/bin/bash
TUBE=/tmp/sshCoLab_myfifo.$$;
mkfifo "$TUBE"
( <"$TUBE" "$@" ; rm "$TUBE" ; kill -TERM 0 ) &  
cat >"$TUBE" ;
rm "$TUBE" ;
kill -TERM 0 ;

Jeśli nazywa się to np. Za pomocą

ssh server.ip ~/helper echo hello from server

i wykonuje się echo hello from serverna server.ip, a następnie klient ssh zostanie zakończony.

Jeśli nazywa się to np. Za pomocą

ssh server.ip ~/helper sleep 1000 &
CHID=$!

kill -9 $CHIDzatrzyma również skrypt na serwerze. Dla mnie kill -INT $CHIDnie działa, ale nie wiem dlaczego.

W odpowiedzi teru polecenie ssh będzie czekać wiecznie po zakończeniu polecenia zdalnego, ponieważ catnigdy się nie kończy.

Wszystkie odpowiedzi z ssh -t nie działały dla mnie kill, ale tylko z Ctrl-C.

Edycja: Dowiedziałem się, że działało to od nowego Ubuntu 14.01 do starszego naukowego systemu Linux - ale nie na odwrót. Dlatego myślę, że nie ma ogólnego rozwiązania. Dziwne.

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.