Run local command after ssh session ends
I have some HP switches that I log into via ssh. The switches send a terminal command to disable line wrap ("rmam" in terminfo parlance), but then fail to reenable it, which screws up my terminal after I exit the ssh session. I can fix the terminal by running tput smam
.
Is there any way to get ssh to automatically run that command after my ssh session ends?
It wouldn't kill me to run it as a shell autocommand, or alias ssh
to always run that command afterwards, but I'd prefer to solve the problem via ssh so that I can limit the command to just be run after I connect to known-bad hosts.
My ssh client is OpenSSH_6.2p2, but I can change or update if there's a new feature somewhere.
OpenSSH has an option called LocalCommand
that runs a command on the client side when you make an ssh connection. Unfortunately, it runs the command before the ssh session is established, not afterwards. But that gave me the idea that I might somehow be able to get that preceding process to wait for the ssh session to end. Despite the fact that the ssh process is the parent PID of the LocalCommand, it turns out that it's still not all that easy.
However, I did find something that works for me under MacOS X, and ought to work on (other) BSDs, if not Linux. I wrote a small C program that uses the kqueue()
interface to wait on its own ppid and then run a supplied command once that process exits. (Source code listing below, for those who are interested.)
Now I just have to reference this program in my ~/.ssh/config
file:
host hp-switch*
PermitLocalCommand yes
LocalCommand ~/bin/wait4parent 'tput smam'
And this seems to work just fine. Those of you on Linux … I guess you can try the same sort of thing by polling for LocalCommand
's ppid and hope that that pid doesn't get reused. (See 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);
}
You could make simple ssh wrapper for this and in it specify commands to be ran after ssh, e.g.
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"