Назад | Перейти на главную страницу

Запустить локальную команду после завершения сеанса ssh

У меня есть несколько коммутаторов HP, в которые я вхожу по ssh. Коммутаторы отправляют команду терминала для отключения переноса строки («rmam» на языке terminfo), но затем не могут включить его повторно, что приводит к зависанию моего терминала после выхода из сеанса ssh. Я могу исправить терминал, запустив tput smam.

Есть ли способ заставить ssh автоматически запускать эту команду после завершения сеанса ssh?

Меня бы не убило запускать его как автокоманду оболочки или псевдоним ssh чтобы всегда запускать эту команду после этого, но я бы предпочел решить проблему через ssh, чтобы я мог ограничить команду запуском только после подключения к заведомо неисправным хостам.

Мой ssh-клиент - OpenSSH_6.2p2, но я могу изменить или обновить его, если где-нибудь появится новая функция.

В OpenSSH есть опция под названием LocalCommand который запускает команду на стороне клиента, когда вы устанавливаете ssh-соединение. К сожалению, он запускает команду перед сеанс ssh установлен, а не потом. Но это натолкнуло меня на мысль, что я мог бы каким-то образом заставить предыдущий процесс дождаться завершения сеанса ssh. Несмотря на то, что процесс ssh является родительским PID для LocalCommand, оказывается, что это все еще не так просто.

Однако я нашел кое-что, что работает для меня под MacOS X, и должно работать с (другими) BSD, если не с Linux. Я написал небольшую программу на C, которая использует kqueue() интерфейс, чтобы дождаться своего собственного ppid, а затем запустить предоставленную команду после выхода из этого процесса. (Список исходного кода ниже, для тех, кому интересно.)

Теперь мне просто нужно сослаться на эту программу в моем ~/.ssh/config файл:

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

И это, кажется, работает нормально. Те из вас, кто работает в Linux ... Думаю, вы можете попробовать то же самое, опросив LocalCommandpid и надеемся, что этот pid не будет использоваться повторно. (Видеть https://stackoverflow.com/questions/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);
}

Вы можете сделать для этого простую оболочку ssh и в ней указать команды, которые будут запускаться после ssh, например

nox:~$ fssh foo
foo:~$ id
uid=0(root) gid=0(root) groups=0(root)
foo:~$ exit
logout
Connection to 1.2.3.4 closed.
Thu Oct 30 19:01:35 CET 2014
nox:~$ cat bin/fssh 
#!/bin/bash

eval ssh '$@'
rc=$?
date
exit "$rc"