Запустите локальную команду после окончания сеанса ssh

9

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

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

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

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

wfaulk
источник
Я никогда не нашел исправления ... используйте telnet;) Или просто используйте отдельное окно терминала.
ewwhite
Для разового использования всегда есть двойной амперсанд. ssh 1.2.3.4 && tput smam
Хеннес
@ewwhite: Вы имеете в виду, что никогда не находили способ автоматизировать исправление? Если нет, то исправление прямо в вопросе. Кроме того, хотя я знаю, что вы шутите, коммутатор не сможет избежать взлома моего терминала только потому, что соединение не зашифровано.
wfaulk

Ответы:

8

У 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 ... Я думаю, вы можете попробовать то же самое, опросив LocalCommandppid и надеясь, что этот 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);
}
wfaulk
источник
2
Отлично! Я использовал этот скрипт на Mac и добавил еще один системный вызов, чтобы можно было запустить локальную команду заранее (пролог), а затем дождаться выполнения второй команды после сеанса (эпилог).
Кевин Ли
1
Я взял идею и немного улучшил код. Вы можете найти инструмент на GitHub
drinchev
4

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

nox: ~ $ fssh foo
foo: ~ $ id
uid = 0 (root) gid = 0 (root) groups = 0 (root)
foo: ~ $ exit
выйти
Подключение к 1.2.3.4 закрыто.
Чт, 30 октября 19:01:35 CET 2014
nox: ~ $ cat bin / fssh 
#! / Bin / Баш

eval ssh '$ @'
гс = $?
свидание
выход "$ rc"
Хрвое Шполяр
источник
2
Да, я сказал, что могу сделать это. (Чтобы быть справедливым, я думаю, что я только сказал «псевдоним», а не «сценарий оболочки».) Несмотря на это, я не уверен, почему вы хотите evalэтого. Это отбрасывает выгоду двойных кавычек $@.
wfaulk
Попробуйте это; вы по-прежнему можете использовать кавычки обычно (как одинарные, так и двойные), как если бы вы разговаривали с SSH напрямую. Я использовал eval, потому что у меня были ситуации, когда захват реального кода завершения сконструированной команды был просто невозможен, если я не выполнял eval всего сконструированного оператора.
Хрвое Шполяр