Ejecute el comando local después de que finalice la sesión ssh

8

Tengo algunos conmutadores HP en los que inicio sesión a través de ssh. Los interruptores envían un comando de terminal para deshabilitar el ajuste de línea ("rmam" en terminfo parlance), pero luego no pueden volver a habilitarlo, lo que arruina mi terminal después de salir de la sesión ssh. Puedo arreglar la terminal ejecutando tput smam.

¿Hay alguna forma de hacer que ssh ejecute automáticamente ese comando después de que finalice mi sesión de ssh?

No me mataría ejecutarlo como un sshcomando automático de shell, o un alias para ejecutar siempre ese comando después, pero preferiría resolver el problema a través de ssh para poder limitar el comando para que se ejecute después de conectarme a anfitriones malos.

Mi cliente ssh es OpenSSH_6.2p2, pero puedo cambiar o actualizar si hay una nueva característica en alguna parte.

wfaulk
fuente
Nunca he encontrado una solución ... use telnet;) O simplemente use una ventana de terminal separada.
ewwhite
Por una vez fuera de uso siempre existe el doble ampersand. ssh 1.2.3.4 && tput smam
Hennes
@ewwhite: ¿Quieres decir que nunca encontraste una manera de automatizar la solución? Si no, la solución está ahí en la pregunta. Además, si bien sé que estás bromeando, no es como si el conmutador evitaría la basura en mi terminal solo porque la conexión no está encriptada.
wfaulk

Respuestas:

8

OpenSSH tiene una opción llamada LocalCommandque ejecuta un comando en el lado del cliente cuando realiza una conexión ssh. Desafortunadamente, ejecuta el comando antes de que se establezca la sesión ssh, no después. Pero eso me dio la idea de que de alguna manera podría lograr que el proceso anterior espere a que termine la sesión ssh. A pesar de que el proceso ssh es el PID principal del LocalCommand, resulta que todavía no es tan fácil.

Sin embargo, encontré algo que funciona para mí en MacOS X, y debería funcionar en (otros) BSD, si no en Linux. Escribí un pequeño programa en C que usa la kqueue()interfaz para esperar en su propio ppid y luego ejecuta un comando provisto una vez que el proceso finaliza. (Código fuente a continuación, para aquellos que estén interesados).

Ahora solo tengo que hacer referencia a este programa en mi ~/.ssh/configarchivo:

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

Y esto parece funcionar bien. Aquellos de ustedes en Linux ... Supongo que pueden probar el mismo tipo de sondeo buscando LocalCommandel ppid y esperando que ese pid no se reutilice. (Ver /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
fuente
2
¡Excelente! Utilicé este script en Mac y agregué otra llamada al sistema para poder ejecutar un comando local por adelantado (prólogo) y luego esperar al segundo comando para que se ejecute después de la sesión (epílogo).
Kevin Lee
1
Tomé la idea y mejoré un poco el código. Puede encontrar la herramienta en GitHub
drinchev
4

Podría hacer un contenedor ssh simple para esto y en él especificar los comandos que se ejecutarán después de ssh, por ejemplo

nox: ~ $ fssh foo
foo: ~ $ id
uid = 0 (raíz) gid = 0 (raíz) grupos = 0 (raíz)
foo: ~ $ salir
cerrar sesión
Conexión a 1.2.3.4 cerrada.
Jue 30 oct 19:01:35 CET 2014
nox: ~ $ cat bin / fssh 
#! / bin / bash

eval ssh '$ @'
rc = $?
fecha
salir "$ rc"
Hrvoje Špoljar
fuente
2
Sí, dije que podía hacer esto. (Para ser justos, supongo que solo dije "alias" y no "script de envoltura"). De todos modos, no estoy seguro de por qué quieres evaleso. Desecha el beneficio de la doble cita $@.
wfaulk
Pruébalo; todavía puede usar comillas normalmente (comillas simples y dobles) como si estuviera hablando directamente con SSH. Usé eval porque he tenido situaciones en las que capturar el código de salida real del comando construido simplemente no era posible a menos que haya evaluado toda la declaración construida.
Hrvoje Špoljar