Sunday, 3 March 2013

Truecrypt under FreeBSD

Truecrypt does work under FreeBSD, but it's not always as smooth an experience as on Linux.

A common problem is receiving an "Operation not permitted" error when trying to mount your volume. In my case, has almost always been attributable to an unclean filesystem.

1. How to get access to your data.

Mount the volume with read-only disabled, and with do-not-mount enabled. This gives you a decrypted virtual device under /dev. You can obtain the device path with:

# truecrypt -l

You're now in a position to run a fsck:

# fsck -t <filesystem> /dev/<device>

NB: If you can't remember the filesystem type, you may find testdisk's Analyze mode useful.

Assuming that the fsck completes successfully (probably returning ***** FILE SYSTEM MARKED CLEAN *****) you can remount normally:

# mount -t <filesystem> -w /dev/<device> /mnt

2. How to prevent it reoccurring.

Follow these three steps:
  • Always unmount before rebooting/removing the media. 
  • Ensure all unmounts are successful (e.g., they shouldn't fail with "Device busy").
  • If you have Gamin running, then use a mountpoint under /media or /mnt
The third point is important. gam_server has a tendency to set up a large number of directory and file watches with nautilus. If you're stuck with umount returning the "Device busy" error, check what's preventing umount:

# lsof +D <mountpoint>
COMMAND     PID USER FD  TYPE DEVICE SIZE/OFF     NODE NAME
gam_serve 33424  ace 48r VDIR  0,176     1024        2 /export/d1
gam_serve 33424  ace 49r VDIR  0,176      512        3 /export/d1/.snap
gam_serve 33424  ace 50r VDIR  0,176      512 62507008 /export/d1/2011 

In such a case, Killing gam_server (Gamin) should work. The problem with this is that Gamin is restarted instantly once killed. And Gamin doesn't appear, at a glance, to be awfully configurable in terms of directory exclusions and suchlike.

Your best bet is to try to get a umount in just after killing the process:

# kill 33424 && umount <mountpoint>

That rarely works, since Gamin is restarted so quickly. But sometimes you can just beat it and get your umount in. Running a simple script, something like this (note that this hack only handles one PID), should manage to umount eventually. It's always worked in my case. It may take some time though - be prepared to let it run for a half hour or so before giving up.

# false || while [[ $? -ne 0 ]] ; do kill -9 $(lsof +D <mountpoint> 2>/dev/null | grep gam_serv | awk '{ print $2 }' | uniq) && umount <mountpoint>; done

So the moral of the story is, if you're running Gamin, mount to a mountpoint which is under one of Gamin's preconfigured exclude directories. And as far as I'm aware (without checking the source code), the only two preconfigured exclude directories are /media and /mnt.