ssh continua inesperadamente em outro sistema após o término do ssh

9

Estou executando o comando abaixo e monitorando o arquivo de saída no outro sistema:

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

Se eu matar o comando ssh usando ^C ou apenas matando o terminal em que estou logado, esperaria que o comando remoto terminasse também. Isso não acontece, no entanto: /tmp/count obtém todos os números 1–5 independentemente, e ps -ejH mostra o shell e seu sleep child continua em execução.

Esse comportamento é esperado e está documentado em algum lugar? Posso desabilitá-lo? Da leitura ao redor, eu esperava ter que habilitar explicitamente esse tipo de comportamento com nohup, não para que fosse o padrão.

Eu dei uma olhada nas man pages para ssh e sshd, mas não vi nada óbvio, e o Google me aponta as instruções para ativar esse comportamento, não para desativá-lo.

Estou rodando o Red Hat Enterprise Linux 6.2, com login root e shell bash nos dois sistemas.

    
por me_and 29.05.2012 / 16:47

6 respostas

9

uther's answer diz para você alocar um terminal, mas não explica por quê. A razão não é específica do ssh, é uma questão de geração e propagação de sinais. Convido-vos a ler O que faz com que vários sinais sejam enviados ? para mais informações.

No host remoto, há dois processos relevantes:

  • uma instância do daemon ssh ( sshd ), que está transmitindo a entrada e a saída do programa remoto para o terminal local;
  • um shell, que está executando esse for loop.

O shell pode morrer naturalmente quando atinge o final do loop ou passa por um erro fatal ou por um sinal. A questão é, por que o shell receberia um sinal?

Se o shell remoto estiver conectado a sshd over pipes, que é o que acontece quando você especifica um comando na linha de comando ssh , ele morrerá de um SIGPIPE se sshd sair e o shell tentar gravar no pipe. Enquanto o shell não estiver gravando no pipe, ele não receberá um SIGPIPE. Aqui, o shell nunca está escrevendo nada para sua saída padrão, então ele pode viver para sempre.

Você pode passar a opção -t para ssh, para dizer-lhe para emular um terminal no lado remoto e executar o comando especificado neste terminal. Então, se o cliente SSH desaparecer, sshd fecha a conexão e sai, destruindo o terminal. Quando o dispositivo de terminal desaparece, qualquer processo em execução nele recebe um SIGHUP . Portanto, se você matar o cliente SSH (com kill ou fechando o terminal em que o cliente está sendo executado), o shell remoto será SIGHUPped.

Se você passar a opção -t , o SSH também transmitirá SIGINT . Se você pressionar Ctrl + C , o shell remoto receberá uma SIGINT.

    
por 30.05.2012 / 02:39
3

Tente alocar um psuedo-tty com seu comando ssh .

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

Quando você desconecta a sessão ssh, o processo deve terminar.

Como esta é uma pseudo-tty, a inicialização de seu shell provavelmente não irá originar arquivos de configuração, deixando seu comando com um ambiente muito vazio. Talvez seja necessário configurar um arquivo .ssh/environment que define variáveis de ambiente, como PATH. De man 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).
    
por 29.05.2012 / 17:14
2

Como alternativa ao uso da opção -t para ssh para fazer com que o comando remoto termine quando o cliente ssh sair ou (ser eliminado), um canal nomeado pode ser usado para converter "EOF para SIGHUP" quando o stdin de sshd está sendo fechado (veja Bug 396 - sshd orphans processa quando nenhum pty é alocado ).

# 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"
'
    
por 06.05.2013 / 17:23
1

Esta é a melhor maneira que encontrei para fazer isso. Você quer algo no lado do servidor que tenta ler stdin e depois mata o grupo de processos quando isso falha, mas você também quer um stdin no lado do cliente que bloqueia até que o processo do lado do servidor seja feito e não deixe processos remanescentes como < (dormir infinito) pode.

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

Na verdade, ele não parece redirecionar o stdout para qualquer lugar, mas funciona como uma entrada de bloqueio e evita a captura de pressionamentos de teclas.

Erro openssh relevante: link

    
por 05.10.2014 / 02:59
0

Se você quiser desabilitar isso (comportamento aparentemente padrão), é necessário ativar ssh-keep-alive no cliente ou no lado do servidor.

Se você olhar para as opções ssh-keep-alive nas páginas man, você pode ver que elas estão desabilitadas por padrão.

    
por 29.05.2012 / 22:16
0

Minha resposta é baseada em teru. Eu preciso de um script de ajuda ~/helper no servidor server.ip:

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

Se for chamado, e. com

ssh server.ip ~/helper echo hello from server

e executa echo hello from server no server.ip e, em seguida, o cliente ssh será finalizado.

Se for chamado, e. com

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

kill -9 $CHID também interromperá o script no servidor. Para mim, kill -INT $CHID não funciona, mas não sei porquê.

Em resposta, o comando ssh irá esperar para sempre quando o comando remoto terminar, porque cat nunca termina.

Todas as respostas com ssh -t não funcionaram para mim com kill , mas apenas com Ctrl-C.

Edit: Eu descobri que isso funcionou a partir de um novo Ubuntu 14.01 para uma antiga caixa científica linux - mas não o contrário. Assim, acho que não há solução geral. Estranho.

    
por 24.01.2017 / 21:03