zr, for your ZFS pleasure
04 April 2019

Though I, of course, use version control for any kind of serious development, and configuration management to build my hosts, I still find ZFS snapshots invaluable. I have a script I wrote well over ten years ago which snapshots every dataset on my machine, and I often find myself digging something out of a snapshot.

To make this easier, I wrote zr, and I’ve found it so useful that I thought I’d share it. Let’s have a quick demo.

zr Restores Files

Say you accidentally delete Slaapkamers met Slagroom. I know. Nightmare, right?

$ ls -1
$ rm 01.sonic_youth.slaapkamers_met_slagroom.flac
$ ls -1
$ zr 01.sonic_youth.slaapkamers_met_slagroom.flac
   current file      unknown mtime                    unknown size
 0 sunday               2018-06-06 08:17:14 +0000           130711565
 1 april                2018-06-06 08:17:14 +0000           130711565
 2 friday               2018-06-06 08:17:14 +0000           130711565
 3 march                2018-06-06 08:17:14 +0000           130711565
 4 tuesday              2018-06-06 08:17:14 +0000           130711565
 5 thursday             2018-06-06 08:17:14 +0000           130711565
 6 monday               2018-06-06 08:17:14 +0000           130711565
 7 wednesday            2018-06-06 08:17:14 +0000           130711565
 8 saturday             2018-06-06 08:17:14 +0000           130711565
choose file to promote [add 'd' for diff, 'k' to keep] > 0
promoting /storage/flac/.zfs/snapshot/sunday/eps/sonic_youth.slaapkamers_met_slagroom/\
$ ls -1

As you can see, when it’s given a filename, zr offers you a list of files of the same name in any snapshots of the file’s parent dataset. I’m not normally a big fan of coloured output from commands, but here I find it useful. Blue files are different from the “real” one. In this case, they’re all blue because the real one doesn’t exist any more.

All you do is enter the number of the file you want to recover, and zr will pop it back where it was, replacing or overwriting the “real” one.

If you’ve deleted a file and just want the newest snapshotted version back, you can run zr -a <filename> and zr will automatically recover it for you.

If the real file still exists, zr will show you the modification time and byte size of what it calls the “current file”, then a list of all the similarly named files it finds in snapshots. Any versions of the file which look the same as the live one are struck through, to suggest you ignore them. (I chose not to simply omit identical files because that would suggest there aren’t any snapshotted versions, which would confuse the user.)

zr considers files identical if they have the same modification time and size. I originally wrote it when I was trying various transcoding methods on a bunch of massive Bluray rips, which were very time-consuming to SHA sum.

$ zr inspector.d
   current file      2019-02-12 16:39:47 +0000       723
 0 thursday             2019-02-12 16:39:47 +0000           723
 1 tuesday              2019-02-12 16:39:47 +0000           723
 2 monday               2019-02-12 16:39:47 +0000           723
 3 saturday             2019-02-12 16:39:47 +0000           723
 4 april                2019-02-12 16:39:47 +0000           723
 5 march                2019-02-12 16:39:47 +0000           723
 6 wednesday            2019-02-12 16:39:47 +0000           723
 7 friday               2019-02-12 16:39:47 +0000           723
 8 sunday               2019-02-12 16:39:47 +0000           723
 9 february             2019-01-22 16:31:33 +0000           665

If you want to see how a snapshot file differs from the live one, append d to its number, and the two copies will be run through diff(1).

You can promote a file from a snapshot without getting rid of the existing one. Append k to the number, and the original will have .orig appended to its name.

zr can accept multiple arguments, and will loop through the files, showing you the restoration candidates for each one. It can recover plain files or entire directories.

zp Promotes Files

Complementary to zr, is zp. This is useful if you are digging around in your .zfs/snapshot directories for something. When you find the thing you want, zp it back to life.

$ ls /storage/flac/eps/quickspace.superplus
ls: cannot access '/storage/flac/eps/quickspace.superplus': No such file or directory
$ pwd
$ ls -d quickspace.superplus
$ zp quickspace.superplus
restoring quickspace.superplus to /storage/flac/eps
$ ls /storage/flac/eps/quickspace.superplus
01.quickspace.superplus.flac  03.quickspace.scubaplus.flac   front.jpg
02.quickspace.proplus.flac    04.quickspace.standard_8.flac

zp only works in a snapshot directory.

$ pwd
$ zp broadcast.microtronics_volume_01
ERROR: /storage/flac/eps is not a snapshot. Skipping.

zr and zp are written in Ruby. They don’t need anything beyond stdlib, and work with 2.3 upwards.

Other Friends

zr and zp live in a pretty ancient Github repo with some shell scripts I wrote in the mid-late 2000s. They all work great – I’ve been using them for over a decade – but please don’t judge me on them!