bcvi - run vi over a 'back-channel'

If you use SSH, you might find bcvi useful. This article attempts to describe what it is and why you might use it. Let's start with what it is:

bcvi is a command-line tool that works with SSH to provide a 'back-channel' from the server you have connected to, back to your workstation.

You typically use SSH because you want to send commands from your workstation to a server, but bcvi works in the opposite direction - allowing you to send commands from the server back to your workstation. To understand why this is useful, lets look at a few examples.

Our example user Sally will use SSH from her workstation gecko to connect to the server pluto:

Example network

Example One

Sally connects to the server pluto and at the shell prompt, types a command to edit a file:

Example 1 screenshot

As you can see from the screenshot, Sally typed the command:

vi factory.rb

and through the magic of bcvi, the result is that the file is opened for editing in a gvim editor window on Sally's workstation. Note, this does not use X-forwarding. The GUI editor process is running on Sally's workstation. The file is copied transparently to and from the server pluto using scp (via gvim's 'netrw' network transport layer), but the shell command to launch the editor was entered on the server pluto.

Compared to running vim on the remote server in the terminal window, bcvi provides these advantages to Sally:

  • gvim on Sally's workstation has all her preferred key mappings, custom macros, plugins and scripts
  • gvim is a GUI app that responds to mouse input for scrolling, selecting text, copying and pasting
  • gvim knows when Sally is pasting so it disables autoindent automatically and avoids the dreaded stair-step effect often seen when pasting into vim in a terminal window
  • because gvim is running locally (rather than via X-forwarding) the application loads quickly and is responsive to user input
  • no GUI apps or libraries need to be installed on the server*

*You might argue that bcvi itself will need to be installed on the server, but Sally can do that from her workstation with one simple command (and no need for root access):

~$ bcvi --install pluto
Creating ~/bin directory on pluto
Copying bcvi to remote bin directory on pluto
Creating plugins directory on pluto
Copying plugin files to pluto
Added bcvi commands to /home/sally/.bashrc

How Example One Worked

The bcvi utility was not responsible for copying files to and from the server 'pluto' (gvim can already do that). Rather, bcvi was used to establish a communications channel from 'pluto' back to Sally's workstation. This back channel was used to send a message triggering the launching of gvim and the loading of the specified file.

The example above assumed:

  • a bcvi 'listener' process had been launched by Sally's X session startup scripts
  • the ssh command used to connect to 'pluto' was actually a shell alias that set up the environment and invoked the real ssh command with additional parameters for port forwarding the 'back channel'
  • Sally's login script on 'pluto' invoked bcvi to unpack the environment and set up the required authentication key
  • the vi command used to edit the file on pluto was actually a shell alias that invoked bcvi to pass a message over the backchannel to the listener process on Sally's workstation
  • the listener process unpacked the message to extract the hostname and filename information needed to launch this command:
    gvim scp://pluto//home/sally/.bashrc
    

bcvi components

Example Two

Our friend Sally is logged on to the server 'pluto' and is trying to configure the 'Acme CRM' package. She explores the filesystem and locates a useful file in the documentation directory:

Example 2 screenshot

In the final command above, Sally used the command:

bcp manual.pdf

to copy the PDF file back to the desktop on her workstation. Then she was able to simply double-click the desktop icon to open it in her PDF viewer.

How Example Two Worked

This second example used all the same infrastructure as the first (listener process, shell aliases and port forward) but added the command bcp. Once again, this is a shell alias that invokes bcvi to send a message back to the listener process. The only difference is that this time the message instructs the listener process to run this command:

scp -q pluto:/usr/share/doc/acmecrm/manual.pdf /home/sally/Desktop

Note, for security reasons, the bcvi process running on pluto is not allowed to specify the command that gets executed on the workstation. It simply sends a request which includes hostname and filename details. The listener process determines which types of requests it will accept and which commands it will run to handle them.

Example Three

Sally is now making progress setting up the Acme CRM package. The next step is to restore a database dump. This will take some time and Sally has other things to get on with so she kicks off this command (actually, two commands separated by a semicolon):

sally@pluto:~$ pg_restore -d acmecrm crm.pgdump; bnotify 'DB is restored!'

Sally then minimises her shell/ssh window and gets on with some other important work. Some minutes later (when the restore command has finished), a desktop notification window pops up on her screen:

Example 3 screenshot

How Example Three Worked

Once again, this example used all the same back channel infrastructure used by the previous examples, but this one also used bcvi plugins.

The bcvi script itself uses only core Perl modules, but the interface to the desktop notifications API requires the Desktop::Notify module from CPAN. It also requires a small 'plugin' module to provide the glue between the listener process and the additional modules. Plugins are described in more detail in App::BCVI::Plugins.

Installing BCVI

The bcvi program is a standalone script with no companion modules and no non-core dependencies. To install it, simply copy the bin/bcvi file from the distribution to a directory in your search PATH.

Alternatively, you can use the standard CPAN installation procedure to install the script to your site bin directory:

perl Makefile.PL
make
make test
make install

The 'back channel' protocol requires a client and a server - the bcvi script performs both roles. The server runs on your workstation and is typically launched by adding a command to your X session startup. For example under Ubuntu/GNOME you might select System ‣ Preferences ‣ Startup Applications and add the command: bcvi --listener:

Listener setup screenshot

If you start a listener manually from a shell window you'll probably want to append an ampersand (&) to put the command in the background.

When connecting to a server you'll want to use this command to wrap the SSH command and add the required port forwarding options:

bcvi --wrap-ssh -- hostname

It is probably more convenient to set up an alias so that this happens on every SSH connection. Use this command to add the appropriate aliases to your bash startup scripts:

bcvi --add-aliases

Now that you have the server set up and ssh connection wrapping in place, you need to install bcvi on the machine you will ssh to:

bcvi --install HOSTNAME

At this point it should all work. When you log in to the machine using SSH, a number of shell aliases will be available to you:

vi
Invokes gvim on your workstation, passing it an scp://... URL of the file(s) you wish to edit
suvi
Same as above, but uses sudoedit so system files (requiring root access) can be edited too
bcp
Copies the named file back to your workstation desktop

Plugins can install additional aliases (such as the bnotify alias installed by the App::BCVI::NotifyClient plugin).

Tuning Your SSH Config

To make the most of bcvi, you need to make sure you have the basics of SSH sorted out first.

If you get prompted for a password every time you connect to a host, you'll need to set up secure password-less logins before trying to use bcvi.

You can't chain together bcvi back-channels, so if you need to SSH into one host and then SSH from there to another host, then you'll need to set up transparent multi-hop SSH.

If you're using slow network links or connecting to old/slow servers you may find that it takes a few seconds to establish an SSH connection. If this happens every time you save a file in your editor it will start to get annoying. You can avoid the connection overhead by reusing the SSH connection that your shell session is using.

Integration with SSHMenu

SSHMenu does not use shell aliases to establish SSH connections, so the back-channel will not be established. Don't despair though - bcvi integration is baked right into SSHMenu.

If SSHMenu detects bcvi in your search PATH, an extra checkbox will be added to the Host Connection dialog:

SSHMenu/bcvi screenshot

Simply tick the box if you've installed bcvi on the target server.

Further References

For more information on downloading and installing bcvi from CPAN, see: App::BCVI.

For details of the plugin API, see: App::BCVI::Plugins.

The source code is available at http://github.com/grantm/bcvi.

Sally's awesome Gecko desktop wallpaper was created by the amazing Vladstudio.

Desktop wallpaper from Vladstudio