Exécuter la commande locale après la fin de la session ssh

8

J'ai des commutateurs HP auxquels je me connecte via ssh. Les commutateurs envoient une commande de terminal pour désactiver le retour à la ligne ("rmam" dans le langage terminfo), mais ne parviennent pas à le réactiver, ce qui fout mon terminal après avoir quitté la session ssh. Je peux réparer le terminal en exécutant tput smam.

Existe-t-il un moyen pour que ssh exécute automatiquement cette commande après la fin de ma session ssh?

Cela ne me tuerait pas de l'exécuter en tant que commande automatique du shell ou alias sshpour toujours exécuter cette commande par la suite, mais je préférerais résoudre le problème via ssh afin que je puisse limiter la commande à être exécutée après que je me suis connecté à connu -hôtes désagréables.

Mon client ssh est OpenSSH_6.2p2, mais je peux changer ou mettre à jour s'il y a une nouvelle fonctionnalité quelque part.

wfaulk
la source
Je n'ai jamais trouvé de solution ... utilisez telnet;) Ou utilisez simplement une fenêtre de terminal séparée.
ewwhite
Pour une utilisation unique, il y a toujours la double esperluette. ssh 1.2.3.4 && tput smam
Hennes
@ewwhite: Vous voulez dire que vous n'avez jamais trouvé de moyen d'automatiser le correctif? Sinon, le correctif est là dans la question. De plus, même si je sais que vous plaisantez, ce n'est pas comme si le commutateur éviterait de craquer sur mon terminal simplement parce que la connexion n'est pas cryptée.
wfaulk

Réponses:

8

OpenSSH a une option appelée LocalCommandqui exécute une commande côté client lorsque vous établissez une connexion ssh. Malheureusement, il exécute la commande avant l'établissement de la session ssh, pas après. Mais cela m'a donné l'idée que je pourrais d'une manière ou d'une autre obtenir le processus précédent d'attendre la fin de la session ssh. Malgré le fait que le processus ssh soit le PID parent de LocalCommand, il s'avère que ce n'est toujours pas si simple.

Cependant, j'ai trouvé quelque chose qui fonctionne pour moi sous MacOS X, et qui devrait fonctionner sur (d'autres) BSD, sinon Linux. J'ai écrit un petit programme C qui utilise l' kqueue()interface pour attendre son propre ppid, puis exécuter une commande fournie une fois ce processus terminé. (Liste de code source ci-dessous, pour ceux qui sont intéressés.)

Il ne me reste plus qu'à référencer ce programme dans mon ~/.ssh/configfichier:

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

Et cela semble fonctionner très bien. Ceux d'entre vous sous Linux… Je suppose que vous pouvez essayer le même genre de chose en interrogeant LocalCommandle ppid de et en espérant que ce pid ne soit pas réutilisé. (Voir /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
la source
2
Excellent! J'ai utilisé ce script sur Mac et ajouté un autre appel système afin de pouvoir exécuter une commande locale en amont (prologue), puis attendre la deuxième commande pour exécuter après la session (épilogue).
Kevin Lee
1
J'ai pris l'idée et amélioré un peu le code. Vous pouvez trouver l'outil sur GitHub
drinchev
4

Vous pouvez créer un wrapper ssh simple pour cela et spécifier des commandes à exécuter après ssh, par exemple

nox: ~ $ fssh foo
foo: ~ $ id
uid = 0 (racine) gid = 0 (racine) groupes = 0 (racine)
foo: ~ $ exit
Se déconnecter
Connexion à 1.2.3.4 fermée.
Jeu. 30 oct. 19:01:35 CET 2014
nox: ~ $ cat bin / fssh 
#! / bin / bash

eval ssh '$ @'
rc = $?
Date
quitter "$ rc"
Hrvoje Špoljar
la source
2
Ouais, j'ai dit que je pouvais faire ça. (Pour être honnête, je suppose que je n'ai dit que "alias" et non "script wrapper".) Quoi qu'il en soit, je ne sais pas pourquoi vous voulez evalcela. Il jette l'avantage de la double cotation $@.
wfaulk
Essaye le; vous pouvez toujours utiliser des guillemets normalement (guillemets simples et doubles) comme si vous parliez directement avec SSH. J'ai utilisé eval parce que j'ai eu des situations où la capture du vrai code de sortie de la commande construite n'était tout simplement pas possible à moins que j'aie fait eval de toute la déclaration construite.
Hrvoje Špoljar