Jalankan perintah lokal setelah sesi ssh berakhir

8

Saya memiliki beberapa sakelar HP yang saya masuki melalui ssh. Switch mengirim perintah terminal untuk menonaktifkan garis bungkus ("rmam" dalam istilah terminfo), tetapi kemudian gagal untuk mengaktifkannya kembali, yang mengacaukan terminal saya setelah saya keluar dari sesi ssh. Saya dapat memperbaiki terminal dengan menjalankan tput smam.

Apakah ada cara untuk mendapatkan ssh untuk menjalankan perintah itu secara otomatis setelah sesi ssh saya berakhir?

Itu tidak akan membunuh saya untuk menjalankannya sebagai perintah otomatis shell, atau alias sshuntuk selalu menjalankan perintah itu setelah itu, tapi saya lebih suka untuk menyelesaikan masalah melalui ssh sehingga saya dapat membatasi perintah untuk hanya dijalankan setelah saya terhubung ke dikenal tuan rumah yang buruk.

Klien ssh saya adalah OpenSSH_6.2p2, tetapi saya dapat mengubah atau memperbarui jika ada fitur baru di suatu tempat.

wfaulk
sumber
Saya belum pernah menemukan perbaikan ... gunakan telnet;) Atau hanya gunakan jendela terminal terpisah.
ewwhite
Untuk sekali pemakaian sekali pakai selalu ada ampersand ganda. ssh 1.2.3.4 && tput smam
Hennes
@ewwhite: Maksud Anda, Anda tidak pernah menemukan cara untuk mengotomatiskan perbaikan? Jika tidak, perbaikannya ada di sana dalam pertanyaan. Juga, sementara saya tahu Anda bercanda, tidak seperti saklar akan menghindari retak pada terminal saya hanya karena koneksi tidak dienkripsi.
wfaulk

Jawaban:

8

OpenSSH memiliki opsi yang disebut LocalCommandyang menjalankan perintah di sisi klien ketika Anda membuat koneksi ssh. Sayangnya, ia menjalankan perintah sebelum sesi ssh dibuat, bukan sesudahnya. Tapi itu memberi saya ide bahwa saya mungkin bisa mendapatkan proses sebelumnya untuk menunggu sesi ssh berakhir. Terlepas dari kenyataan bahwa proses ssh adalah induk PID dari LocalCommand, ternyata itu masih tidak mudah.

Namun, saya memang menemukan sesuatu yang bekerja untuk saya di bawah MacOS X, dan harus bekerja pada BSD (lainnya), jika bukan Linux. Saya menulis sebuah program C kecil yang menggunakan kqueue()antarmuka untuk menunggu pada ppid sendiri dan kemudian menjalankan perintah yang disediakan setelah proses itu keluar. (Daftar kode sumber di bawah ini, untuk mereka yang tertarik.)

Sekarang saya hanya perlu merujuk program ini di ~/.ssh/configfile saya :

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

Dan ini sepertinya bekerja dengan baik. Bagi Anda di Linux ... Saya kira Anda dapat mencoba hal yang sama dengan polling untuk LocalCommandppid dan berharap pid itu tidak dapat digunakan kembali. (Lihat /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
sumber
2
Luar biasa! Saya menggunakan skrip ini di Mac dan menambahkan system call lain sehingga saya bisa menjalankan perintah lokal di muka (prolog) dan kemudian menunggu perintah kedua untuk dijalankan setelah sesi (epilog).
Kevin Lee
1
Saya mengambil ide dan sedikit memperbaiki kode. Anda dapat menemukan alat di GitHub
drinchev
4

Anda dapat membuat ssh wrapper sederhana untuk ini dan di dalamnya tentukan perintah yang harus dijalankan setelah ssh, mis

nox: ~ $ fssh foo
foo: ~ $ id
uid = 0 (root) gid = 0 (root) groups = 0 (root)
foo: ~ $ keluar
keluar
Koneksi ke 1.2.3.4 ditutup.
30 Oktober 19:01:35 CET 2014
nox: ~ $ cat bin / fssh 
#! / bin / bash

eval ssh '$ @'
rc = $?
tanggal
keluar "$ rc"
Hrvoje Špoljar
sumber
2
Ya, saya bilang saya bisa melakukan ini. (Agar adil, saya kira saya hanya mengatakan "alias" dan bukan "skrip pembungkus".) Apapun, saya tidak yakin mengapa Anda ingin evalitu. Itu membuang manfaat dari kutip ganda $@.
wfaulk
Cobalah; Anda masih dapat menggunakan tanda kutip secara normal (baik tanda kutip tunggal maupun ganda) seperti Anda berbicara dengan SSH secara langsung. Saya menggunakan eval karena saya memiliki situasi di mana menangkap kode keluar nyata dari perintah yang dibangun tidak mungkin kecuali saya melakukan eval dari seluruh pernyataan yang dibuat.
Hrvoje Špoljar