April 2009 Archives

One quick command, "rm *.c" and three hours of work was gone. Sure I know that I meant to write "rm *.o", however there isn't any undo for stupidity or carelessness.

One of the many new feature in Mac OS X Leopard was Time Machine, however as I usually work on a laptop I've never had consistent success with backing up to a Time Machine drive across the network. I also create full system backups using SuperDuper, but only weekly at best, so it also is of no help when I erase the source code I've been working on for the past three hours with a careless command.

Shortly after my current MacBook Pro arrived, I repartitioned the hard drive so that I would have about 128GB for the OS and Applications and 160GB for a ZFS slice. So for months now I've been reminding myself to setup ZFS to take snapshots.

So after the truly horrid feeling of losing work, and the fear that someday I could lose even more, I decided to automate the ZFS snapshots before it's too late.

Requirements

• Mac OS X 10.5 • ZFS for Mac OS X 10.5 • I'm assuming that if you have ZFS installed on your machine that you can figure out how to get the put the below script into a file and make it executable.

Other Software

Lingon (I always think of Klingon first...)

zfsSnaphost.sh

[update 5 Sept 2009 - Take a look at my updated PHP script that is ever so smarter.] My zfsSnaphost.sh script below is based off of another script, of which I am unable to find the original. It is likely to have originated on a ZFS related blog or the ZFS mailing lists.

#! /bin/bash

## As I call this every 30 mins, I will have
##  24 hours worth of system running time worth of backups...
keepThisMany=48;

echo "zfsSnaphost.sh : Starting ZFS snapshots"
fileSystemList=`zfs list -o name -t filesystem | sed 1d`
for full_dir_path in $fileSystemList
do
    zfs snapshot ${full_dir_path}@$(date +%FT%T)

    ## As a note, in the years after 2099 the below line
    ##  will need to be updated as the @20 will need to be @21
    snaps=($(zfs list| grep ${full_dir_path}@20 | cut -f 1 -d ' '))
    numberToKeep=$(( ${#snaps[@]} - ${keepThisMany} ))

    i=0
    while [ $i -lt $numberToKeep ]
    do
        zfs destroy ${snaps[$i]}
        let "i = $i + 1"
        done
done
echo "zfsSnaphost.sh : Finished ZFS snapshots"

Automating

Use Lingon to setup a new "User Daemon" (or "User Agent" or "My Agent" if you prefer although I have not tested either) as shown below, adjusting for the time increment that you would like. For my testing purposes I currently have been taking a snapshot every five minutes but will likely change it back to every 30 mins soon. Lingon - zfsSnapshot.sh Setup

Things to keep in mind

Snapshots do take drive space, however it's not a significant amount. Rather, if you have a high use filesystem where you create a lot of large files and then delete them it will take a while before that drive space is actually free as your snapshots will retain all that old data until the snapshots that still contained those large files are deleted.

How to go back in time

Let's say you just now did something really foolish, like deleting that file you've been working on for three hours. Instead of getting that sick feeling you think "hey, I'm glad I planned for something like this!" and you then start the fairly painless recovery process.

This process might someday be even easier as it is in OpenSolaris, but ".zfs" is not implemented in the Mac OS X port of ZFS (yet we all hope).

First, we need to clone the snapshot, so run

zfs list -t snapshot

and you will see a list something like...

NAME                         USED  AVAIL  REFER  MOUNTPOINT
Dawson@2009-04-17T19:39:00  10.4M      -   137G  -
Dawson@2009-04-17T19:44:01  9.31M      -   137G  -
Dawson@2009-04-17T19:48:59  9.24M      -   137G  -
[[ snip ]]
Dawson@2009-04-18T00:38:29  12.8M      -   137G  -
Dawson@2009-04-18T00:43:28  8.77M      -   137G  -

Pick the one that is as close to right before your blunder. The worst case you can do this process multiple times to find the most recent version saved. Remember that in my setup I create a new snapshot every 5 minutes and I keep 48, so your configuration will vary.

Now, to get to the data inside the snapshot you need to clone the snapshot, below I am cloning the second to last as seen in the above snapshot list, which creates a new zfs filesystem.

zfs clone Dawson@2009-04-18T00:38:29 Dawson/Example

You can then browse to that folder and you will see all the contents just as it was at the time of the snapshot. Once you have found the file(s) that you needed, don't forget to destroy the clone that you made, as it will take a small amount of space and it's no longer needed anyhow.

zfs destroy Dawson/Example

And that is what I wish I had done before Friday evening... At least I've learned to take more precautions.