Zabij proces spawnowany przez ssh, gdy ssh umiera

23

To pytanie zostało poruszone kilka razy, nie tylko tutaj, ale także w innych witrynach sieci wymiany stosów (np. Jak zrobić ssh, aby zabijał zdalny proces, gdy przerywam sam ssh? ). Nie mogę jednak sprawić, by którekolwiek z tych rozwiązań działało dla mnie.

Uruchamiam polecenie przez ssh. Ilekroć wychodzę z ssh, chcę, aby polecenie również zginęło. To polecenie to demon o nazwie ktserver, który działa bez końca, dopóki nie naciśniesz Ctrl-C.

Uruchamiam to w następujący sposób: ssh -t compute-0-1 ktserveri rzeczywiście, kiedy naciskam Ctrl-C, proces kończy się z wdziękiem i kończy się sesja ssh.

Jeśli jednak zamiast naciskać Ctrl-C, zabijam proces ssh za pomocą killpolecenia (na przykład wysyłając SIGINT lub SIGHUP), ktserverproces pozostaje aktywny.

Jak sprawić, by ktserverzawsze umierali niezależnie od tego, jak sshzostanie zabity?

EDYCJA : Jeśli zamiast ktserveruruchomić coś zupełnie innego, na przykład geditwszystko działa jak urok (tzn. Gedit umiera, gdy połączenie się kończy). Dlatego może być coś nie tak z samym procesem. Na przykład myślałem, że może to ignorować SIGHUP lub SIGINT. Jednak po uruchomieniu kill -1 ktserverlub kill -2 ktserverproces umiera zgodnie z oczekiwaniami.

EDYCJA 2 : Jak zauważa Mark Plotnick, problem związany jest z faktem, że na kanale ssh nie ma komunikacji. Potwierdziłem, uruchamiając ssh -t <host> readi zabijając później proces ssh. readwciąż żył i kopał.

Niemiecki K.
źródło
Próbowałeś kill -9 ktserver?
@HermanTorjussen Pewnie, że działa. Problem polega na tym, że to polecenie jest uruchamiane z innego procesu i mogę nie mieć kontroli nad wieloma możliwościami, które mogą spowodować śmierć mojego procesu, a zatem i sesji ssh z nim. Potrzebuję więc pewnego niezawodnego sposobu, aby mieć pewność, że za każdym razem, gdy mój proces - a zatem i tak - zginie, ktserver umrze razem z nimi.
GermanK
Moje doświadczenie z Linuksem polega na tym, że jeśli zdalne polecenie nie wykona żadnych operacji we / wy do martwego połączenia TCP, będzie działać. Miałem ssh example.com dd ...pracy biec do końca, nawet po godzinach sshmatryc połączeń ze względu na problemy z siecią. Jeśli możesz zmienić ktserveropcję, aby od czasu do czasu wypisać coś, może to być obejście problemu.
Mark Plotnick,
@MarkPlotnick Rzeczywiście, próbowałem uruchomić się readna komputerze zdalnym i po zabiciu połączenia ssh readnie umarłem. Niestety nie mogę zmienić ktserver na cokolwiek wyjściowego. Nie ma więc rozwiązania?
GermanK
2
Zakładam, że kiedy ssh umiera, twoja skorupa również umiera. Możesz skonfigurować swoją powłokę, aby wysyłała sygnał -1 (SIGHUP), kiedy się zakończy. ( shopt -s huponexit). Czy możesz sprawdzić, czy to działa dla Ciebie?
Hennes

Odpowiedzi:

13

Zwykle, gdy połączenie ssh umiera, powłoka również umiera. Możesz skonfigurować swoją powłokę, aby wysyłała sygnał -1 (SIGHUP), gdy kończy się na wszystkich swoich potomkach.

W przypadku basha możesz skonfigurować tę opcję za pomocą wbudowanego polecenia shopt . ( shopt -s huponexit).

Dla zsh chcesz .setoptHUP

Hennes
źródło
Myślałem, że to jest odpowiedź na mój obecny problem, ale wydaje się, że to nie działa. Pracuję: ssh $ host "scp LargeFile.dat $ OtherHost: / tmp" & pid = $! a następnie próbuje zatrzymać ten transfer za pomocą: shopt -s huponexit; kill $ pid, ale scp nie zatrzymuje się, gdy zabijam ssh, który uruchomiłem. jakieś pomysły?
David Doria,
Czy możesz przetestować z ustawionymi opcjami powłoki przed uruchomieniem polecenia scp? Lub uruchamiając powłokę, ustawiając shopt i uruchamiając scp?
Hennes,
2
To działa dla mnie, ale najpierw musiałem się upewnić, że używam ssh -t -t(zauważ -tdwa razy!), Który wymusza alokację tty, a nie tylko pty.
Nicolas Wu,
13

Przekonałem się, że po prostu użyłem tego -t -targumentu, aby sshdziałał. Nie musiałem ustawiać huponexitani początkowej, ani zdalnej powłoki.

Testowałem to w następujący sposób:

Nie działa:

ssh user@remote sleep 100
^C

To zabiło sesję ssh, ale widzę, że proces uśpienia wciąż działa na zdalnym hoście ( ps -ef | grep sleeppokazuje).

Działa:

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

To zabija sesję ssh i proces zdalnego uśpienia również został zabity. Sprawdziłem również, że sygnał wysyłany do zdalnego procesu jest, SIGINTjeśli używasz Control- C. Sprawdziłem również, że SIGKILL (-9) zastosowany do sshprocesu zabije również proces zdalny.

EDYCJA 1:

Tak było w przypadku sleep... dla bardziej upartych procesów zdalnych, zauważyłem, że sshobsługuje ^ C inaczej niż SIGINT. Ctrl- Cpracował, ale nie kill -INT $pidzrobił

Oto, co w końcu wymyśliłem, co zadziałało dla mojej faktycznej aplikacji (kradzież z innych odpowiedzi).

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

Zwróć uwagę na zagnieżdżone użycie podwójnych cudzysłowów i pojedynczych cudzysłowów. Pamiętaj, że twój zdalny proces MUSI odpowiedzieć na SIGHUP, faktycznie wychodząc!

Mark Lakata
źródło
To działało dla mnie najlepiej, ale dla twojej wiadomości spowodowało również krwawienie znaków kontrolujących terminal, co może powodować zabawne wyniki. Tak więc w moim przypadku łatwym obejściem było zawijanie wywoływanych poleceń i przesyłanie ich wyników cat. Na przykładssh -ttq user@host '{ cmd; cmd; } | cat'
Droj
Ctrl-CNIE zawsze jest równoważne z kill -INT $pid, zobacz moją odpowiedź na unix.stackexchange.com/questions/377191/... i kolejną na stackoverflow.com/questions/8398845/... dla krwawych szczegółów ;-)
thecarpy
@ thehecarpy - twoja pierwsza odpowiedź mówi, że Ctrl-C jest podobny do SIGINT , a druga odpowiedź mówi, że ^Cwysyła SIGINT . Jaka jest dokładna różnica, jeśli nie są równoważne?
Mark Lakata
1

Jeśli ssh nie propaguje sygnałów, otrzymuje to, czego się od niego oczekuje?

UPD. (specjalne dla JosephR): to oczywiście sam błąd, który wynika z nieporozumienia - „Zabij proces odradzany przez ssh, gdy ssh umiera”. SSH zwykle nie spawnuje procesów (czasem tak jest, ale to inna historia), zamiast tego SSHD robi to, gdy patrzymy na drugą stronę połączenia. SSH opiera się jedynie na abstrakcji pseudoterminalnej. Dlatego jedyną rzeczą, która może pomóc, jest zdolność terminalu do wysyłania sygnałów do dołączonych procesów. Jest to nieco bardzo podstawowe dla każdego systemu podobnego do UNIX.

poige
źródło
1
To nie daje odpowiedzi na pytanie. Aby skrytykować lub poprosić autora o wyjaśnienia, zostaw komentarz pod postem.
Anthon
@Anthon, to wyjaśnienie. Ale nikt nie twierdzi, że to powinna być jedyna poprawna odpowiedź. Dziękuję za komentarz poniżej.
poige
1
@poige Może doprecyzuj to wyjaśnienie, aby było przydatne dla OP i innych.
Joseph R.
@JosephR., Ok, tylko dla ciebie.
poige
1
Jeśli powiem „Zabij proces spawnowany przez sshd, gdy połączenie ssh zostanie utracone”, czy brzmiałoby to lepiej? Nie sądzę, że przeredagowanie w jakikolwiek sposób rozwiązuje mój problem.
GermanK
0

Rozwiązanie opublikowane tutaj nie działało dla mnie, ale ponieważ to pytanie pojawiło się jako pierwsze, gdy szukałem rozwiązania podobnego problemu, a także -t -twspomniano tutaj sztuczkę, opublikuję rozwiązanie, które działało dla mnie, aby inni mogli spróbować.

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

Moje długo działające polecenie już nie działało, gdy połączenie zostało zakończone w ten sposób.

Greg0ry
źródło