Wednesday, August 26, 2009

Empty Turns "Hard" Into "Not-So-Hard"

Some things should be personal, even when you're at a computer.

Logging in, for example.

Good, Linux, command-line tools read from standard in and write to standard out, which are connected, by default, to the keyboard and screen. I try out programs by typing at them. When I'm convinced I understand how they work, I can redirect I/O, to give them input from a file and capture their output in a second.

The upside-down is true, too: I can automate things I typically do interactively, just by having the programs do I/O to files instead of terminals. I've written automated test suites for screen editors with this trick.

Logging-in is different. When the login program prompts you for your name and password, it puts the prompts directly on the screen and reads the answer from the keyboard. Stdin and stdout aren't part of the picture.

This not only makes it hard to automate, it's supposed to make it hard to automate. It's hard to make robots to batter down the system's doors, trying user name after user name and password after password for days on end.

It's a security feature. When a program seems not to be taking input from stdin, I think, "Is this like logging in?"

So, how do you automate those un-automatable jobs?

Don Libes, at NIST, in Gaithersburg, Maryland, gave us the first, good solution: Expect. Expect creates a pseudo-terminal whose virtual keyboard and screen are FIFOs that you can write to and read from. Expect programs are mostly lists of the strings you expect to see, like login:, paired with the responses you want Expect to send when it sees those strings.

It's wonderful. I've used Expect for everything from testing printers to creating a make replacement that drives builds on Tandem's archaic Guardian OS from Unix machines running Expect scripts.

Unfortunately, Don picked the wrong horse. Don built Expect on Tcl, a popular programming language in the early nineties, and used Tcl's syntax. Today, Tcl is no longer in fashion; for most folks, writing Expect is like writing Latin.

Nowadays, Perl, Java, and other languages, have Expect-like extensions, too, but they all feel fragile and hard to use.

Yesterday, I needed to automate an sftp session, without any way to install public keys on the target machine. I thought about Tcl, winced, then looked at empty, which is supposed to offer the same magic in shell scripts.

Installation was just this:

$ sudo apt-get install empty-expect
The program I wrote was short, simple, and it worked. The meat was these lines, trivial modifications of examples in the man page:
# set up a session
empty -f -i in.fifo -o out.fifo -p empty.pid -L $log sftp $username@$remote_machine
empty -w -i out.fifo -o in.fifo password: $password'\n'
# transfer the file
empty -w -i out.fifo -o in.fifo sftp "get $remotefile $localfile"'\n'
For things that should be personal but can't be, I recommend empty. At least, on your computer.

No comments: