Safe handling of FileVault volumes with SleepWatcher

Owing to a recent corruption of my usual Time Capsule-based local network backup (which seems to be fairly common), a month or two ago I started backing things up to a local USB 3 drive attached to my Cinema Display. This is probably a stopgap until I decide to redo my Time Capsule backup, but I wanted to get a bit of backup history under my belt before I wipe the old one.

(By the way, I also use CrashPlan for offsite backup of all our data. I’ve happily been using them on three machines for over a year now.)

The only problem is, I work on a laptop that usually has its lid closed by way of using said external display along with a Bluetooth keyboard and trackpad. Previously, when I would head out of the house, I’d just unplug the three cables (power to cause sleep, then USB and display) from the side of the laptop. Then, I’d put the laptop in my bag and be off!

However, now with the USB drive attached, this would cause an unsafe volume unmount, which probably was fairly harmless, but would still scold me once I’d wake the computer and was ready to work again. Talk about a buzzkill.

There seem to be more than a couple recommended ways to combat this, but the one suggesting using SleepWatcher seemed the simplest and most UNIX-y, and therefore, up my alley.

Another problem, though: I want to remount the disk on wake when relevant, but my backup disk is encrypted with FileVault, so mounting it requires use of a password. I store this password in my OS X keychain, so that when I’m logged in and authenticated and the disk is plugged in, it mounts automatically. But if I try to do this with a script, how could I safely access the password?

Here’s how I solved this little puzzle.

Install SleepWatcher

SleepWatcher is a handy utility that runs as a daemon on your Mac, executing commands in ~/.sleep and ~/.wakeup scripts as appropriate, helping you automate these tasks. You can grab it on the linked page, or, since it’s no longer the Stone Age, install it with Homebrew.

$ brew install sleepwatcher

Follow the post-install instructions around symlinking some things at /usr/local/opt/sleepwatcher and loading up the daemon the first time with /bin/launchctl.

Bonus: you can now sleep your system at will:

$ /usr/local/sbin/sleepwatcher --now

Create a ~/.sleep script

This script will run whenever you sleep the computer. At that point, I want to eject my volume, which is named Elrond.

#!/bin/sh

osascript -e 'tell application "Finder" to eject disk "Elrond"'

Here, we’re using the handy /usr/bin/osascript, which lets us run AppleScript commands and easily tap into Finder’s scripting abilities for known volumes.

Result: sleep the computer and Elrond is ejected!

Technically, my original problem is solved at this point, since the disk gets safely ejected when the system sleeps. But what I’d really like is for it to be remounted automatically when USB is plugged back in at home. Unfortunately, since the power to the disk was never removed, OS X thinks I want it to remain ejected. It would require either a disk power cycle or launching Disk Utility and some clickity-click in order to mount the drive.

Create a ~/.wakeup script

I figured out how to create a wake up script that:

  1. Checks if Elrond is plugged in and available
  2. Finds its FileVault password in my keychain
  3. Passes it securely to a mount command to mount the disk

Here’s what it looks like:

#!/bin/sh

UUID=`diskutil coreStorage info Elrond | grep UUID: | \
  sed -n 1p | awk '{ print $2 }'`

if [ ! -z "$UUID" ]; then
  security find-generic-password -a $UUID -w | \
    diskutil coreStorage unlockVolume $UUID -stdinpassphrase
  DISK=`diskutil coreStorage info Elrond | \
    grep 'Device Identifier:' | awk '{ print $3 }'`
  diskutil mount $DISK
fi

First, it uses /usr/sbin/diskutil to get some info about Elrond in the form of its Core Storage UUID. It only proceeds if this UUID is found, meaning Elrond is attached and powered up.

Next, it looks for an associated disk password by using /usr/bin/security, which is OS X’s way of interacting with the keychain (among other things). The -w flag sends the password to STDOUT, which is chained with diskutil and the -stdinpassphrase flag to unlock the encrypted volume.

Last, it again uses diskutil both to determine the disk’s device name (e.g. disk3, its /dev entry) as well as to mount said now-unlocked disk.

End result

The whole thing doesn’t require too much scripting, but automatically and safely unmounts on sleep and remounts on wake my encrypted backups if present. Yay OS X and UNIX!