Executar comando local após o término da sessão ssh

8

Eu tenho alguns switches HP nos quais faço login via ssh. Os switches enviam um comando terminal para desativar a quebra de linha ("rmam" na linguagem terminfo), mas depois não conseguem reativá-lo, o que atrapalha meu terminal depois que eu saio da sessão ssh. Eu posso consertar o terminal executando tput smam.

Existe alguma maneira de o ssh executar esse comando automaticamente após o término da minha sessão ssh?

Não me mataria executá-lo como um comando automático de shell ou alias sshpara sempre executar esse comando posteriormente, mas eu preferiria resolver o problema via ssh para que eu possa limitar o comando a ser executado apenas depois de conectar-me a conhecidos -bad hosts.

Meu cliente ssh é o OpenSSH_6.2p2, mas posso alterar ou atualizar se houver um novo recurso em algum lugar.

wfaulk
fonte
Eu nunca encontrei uma correção ... use telnet;) Ou apenas use uma janela de terminal separada.
ewwhite
Para uma vez fora de uso, há sempre o duplo e comercial. ssh 1.2.3.4 && tput smam
Hennes 30/10
@whwhite: Quer dizer que você nunca encontrou uma maneira de automatizar a correção? Caso contrário, a correção está lá na pergunta. Além disso, enquanto eu sei que você está brincando, não é como se o comutador evitasse cagar no meu terminal apenas porque a conexão não foi criptografada.
Wllulk

Respostas:

8

O OpenSSH possui uma opção chamada LocalCommandque executa um comando no lado do cliente quando você faz uma conexão ssh. Infelizmente, ele executa o comando antes que a sessão ssh seja estabelecida, não depois. Mas isso me deu a ideia de que eu poderia, de alguma forma, conseguir que o processo anterior aguarde o término da sessão ssh. Apesar do processo ssh ser o PID pai do LocalCommand, verifica-se que ainda não é tão fácil.

No entanto, encontrei algo que funciona para mim no MacOS X e deveria funcionar em (outros) BSDs, se não no Linux. Eu escrevi um pequeno programa C que usa a kqueue()interface para aguardar por conta própria o ppid e, em seguida, execute um comando fornecido assim que o processo terminar. (Código fonte listado abaixo, para aqueles que estão interessados.)

Agora eu só tenho que fazer referência a este programa no meu ~/.ssh/configarquivo:

host hp-switch*
 PermitLocalCommand yes
 LocalCommand ~/bin/wait4parent 'tput smam'

E isso parece funcionar muito bem. Aqueles de vocês no Linux ... acho que você pode tentar o mesmo tipo de pesquisa pesquisando LocalCommando ppid do sis e espero que esse pid não seja reutilizado. (Consulte /programming/1157700/how-to-wait-for-exit-of-non-children-processes )

wait4parent.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>

int main(int argc, char **argv) {
    pid_t ppid, fpid;
    struct kevent kev;
    int kq;
    int kret;
    struct timespec timeout;

    if ( argc > 2 ) {
        fprintf(stderr, "Please quote the command you want to run\n");
        exit(-1);
    }

    ppid = getppid();

    fpid = fork();
    if ( fpid == -1 ) {
        perror("fork");
        exit(-1);
    }

    if ( fpid != 0 ) {
        exit(0);
    }

    EV_SET(&kev, ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, 0);

    kq = kqueue();
    if ( kq == -1 ) {
        perror("kqueue");
        exit(-1);
    }

    kret = kevent(kq, &kev, 1, NULL, 0, NULL);
    if ( kret == -1 ) {
        perror("kevent");
        exit(-1);
    }

    timeout.tv_sec = ( 8 /*hours*/ * 60 /*minutes per hour*/ * 60 /*seconds per minute*/ );
    timeout.tv_nsec = 0;

    kret = kevent(kq, NULL, 0, &kev, 1, &timeout);
    if ( kret == -1 ) {
        perror("kevent");
        exit(-1);
    }

    if ( kret > 0 ) {
        system(argv[1]);
    }
    /* ( kret == 0 ) means timeout; don't do anything */

    exit(0);
}
wfaulk
fonte
2
Excelente! Usei esse script no Mac e adicionei outra chamada do sistema para que eu pudesse executar um comando local antecipadamente (prólogo) e aguardar o segundo comando ser executado após a sessão (epílogo).
Kevin Lee
1
Eu peguei a ideia e melhorei um pouco o código. Você pode encontrar a ferramenta no GitHub
drinchev
4

Você pode criar um wrapper ssh simples para isso e especificar comandos a serem executados após o ssh, por exemplo

nox: ~ $ fssh foo
foo: ~ $ id
uid = 0 (raiz) gid = 0 (raiz) grupos = 0 (raiz)
foo: ~ $ exit
sair
Conexão com 1.2.3.4 fechada.
Quinta-feira, 30 de outubro de 19:01:35 CET 2014
nox: ~ $ bin / fssh 
#! / bin / bash

eval ssh '$ @'
rc = $?
encontro
sair "$ rc"
Hrvoje Špoljar
fonte
2
Sim, eu disse que poderia fazer isso. (Para ser justo, acho que só disse "alias" e não "script de wrapper".) Independentemente disso, não sei por que você deseja fazer evalisso. Ele joga fora o benefício da citação dupla $@.
Wllulk # 31/14
Experimente; você ainda pode usar aspas normalmente (aspas simples e duplas) como se estivesse conversando diretamente com o SSH. Eu usei eval porque tive situações em que capturar o código de saída real do comando construído simplesmente não era possível, a menos que eu avaliasse toda a declaração construída.
Hrvoje Špoljar