sshセッションの終了後にローカルコマンドを実行する


8

ssh経由でログインするHPスイッチがいくつかあります。スイッチはターミナルコマンドを送信してラインラップ(terminfoの用語では "rmam")を無効にしますが、再度有効にできず、sshセッションを終了した後に端末がねじ込まれます。を実行して端末を修正できますtput smam

sshセッションが終了した後、sshにそのコマンドを自動的に実行させる方法はありますか?

それをシェルの自動コマンドとして実行することは私を殺したりssh、常にそのコマンドを後で実行するエイリアスを殺したりはしませんが、既知に接続した直後に実行されるようにコマンドを制限できるように、sshを介して問題を解決したいと思います-悪いホスト。

私のsshクライアントはOpenSSH_6.2p2ですが、新しい機能がどこかにあれば、変更または更新できます。


私は修正を見つけたことがありません... telnetを使用してください;)または、別の端末ウィンドウを使用してください。
ewwhite 2014年

1回限りの使用では、常に2つのアンパサンドがあります。ssh 1.2.3.4 && tput smam
Hennes、2014年

@ewwhite:修正を自動化する方法が見つからなかったということですか?そうでない場合、問題の修正はそこにあります。また、あなたが冗談を言っていることはわかっていますが、接続が暗号化されていないからといって、スイッチが私の端末でのバタバタを避けるのとは異なります。
wfaulk 2014年

回答:


8

OpenSSHには、LocalCommandssh接続を行うときにクライアント側でコマンドを実行するというオプションがあります。残念ながら、sshセッションが確立される前ではなく、にコマンドを実行します。しかし、これにより、前のプロセスでsshセッションが終了するのを待つことができたのではないかと考えました。sshプロセスがLocalCommandの親PIDであるという事実にもかかわらず、それはまだそれほど簡単ではないことが判明しました。

ただし、MacOS Xで動作するものを見つけたため、Linuxでなくても(その他の)BSDで動作するはずです。kqueue()インターフェイスを使用して独自のppidを待機し、そのプロセスが終了したら指定されたコマンドを実行する小さなCプログラムを作成しました。(興味のある方のために、以下のソースコードリスト)

今、私は自分の~/.ssh/configファイルでこのプログラムを参照する必要があります:

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

そして、これはうまく機能するようです。Linuxをお使いLocalCommandの方… のppidをポーリングして同じ種類のことを試すことができ、そのpidが再利用されないことを願っています。(/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);
}

2
優秀な!Macでこのスクリプトを使用し、別のシステムコールを追加して、ローカルコマンドを前もって実行(プロローグ)し、セッションの後に2番目のコマンドが実行されるのを待ちます(エピローグ)。
Kevin Lee

1
私はアイデアを取り入れて、コードを少し改善しました。このツールはGitHubで
drinchev

4

このための単純なsshラッパーを作成し、sshの後に実行するコマンドを指定できます。

nox:〜$ fssh foo
foo:〜$ id
uid = 0(ルート)gid = 0(ルート)groups = 0(ルート)
foo:〜$ exit
ログアウト
1.2.3.4への接続が閉じられました。
2014年10月30日(木)19:01:35 CET
nox:〜$ cat bin / fssh 
#!/ bin / bash

eval ssh '$ @'
rc = $?
日付
「$ rc」を終了

2
うん、できると言った。(公平を期すために、「ラッパースクリプト」ではなく、「エイリアス」とだけ言ったと思います。)とにかく、なぜそれをしたいのかわかりませんeval。それは二重引用符の利点を捨て$@ます。
wfaulk 2014年

やってみて; SSHと直接やり取りしていたように、引用符を通常どおり(単一引用符と二重引用符の両方)使用できます。構築されたステートメント全体のevalを行わない限り、構築されたコマンドの実際の終了コードをキャプチャすることが不可能な状況にあったため、evalを使用しました。
HrvojeŠpoljar2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.