Sky Watch

Wallpaper in a Encrypted Volume

The Problem

I have three volumes in my Mac. I decided to encrypt the two non-boot volumes just for the sake of it. So I did that.

The next time I booted into the OS, I was greeted by an ultra-friendly dialog box asking for passwords. I did not want to do that every time I restart, so I let it remember the passwords in keychain. And the next time I restarted, I found my fine wallpaper was replaced by the default galaxy-in-space image, which I did not really fancy.

Solution Number One

I knew the reason was that the encrypted volumes were mounted after the desktop was loaded. And given the stuborn-ness of Mac OS, it is probably humanly impossible to change that order. So I looked for an alternative — writing a script to kill the Dock application, which automatically reloads the desktop, and somehow running this script when I log in. If I am lucky enough, the script might be run after the encrypted volume is mounted. Here is the script,

:::Bash
#!/bin/sh
exec killall Dock

I ran it to confirm its correctness. Then I added it to my “Login Items” (try a better name next time, Apple). But, it did not work. Apparently it was executed before the volume was mounted.

Solution Number Two

I had to search on the web to start my second attempt. This time it was a more apple-ish method. One can attach a script to a directory in Mac by setup a “folder action”, so that when there are some changes to that directory, the script gets to run. So in principle I could do this to /Volumes, and when a volume is mounted, the folder action should be done automatically. The problem is I do not like my desktop to flick all the time, so I need to know the mounted volume has a specific name. Noticing “Shared” being the name, I wrote an applescript for that,

:::Applescript
on adding folder items to this_folder after receiving MountedVolumes
    repeat with Volume in MountedVolumes
        if name of Volume is "Shared" then
            quit application "Dock"
        end if
    end repeat
end adding folder items to

I did not know if this is correct. I did not even read it a second time, and I suggest you avoid doing that as well. Applescripts are so purely ugly, one would have nightmares after reading too many of them. If one insists on getting some nightmares, I recommend Peskin — at least it has much more contents.

So I attached the script to /Volumes, and tried to unmount and mount the encrypted volume. Nothing happened (well, I mean besides the volume being unmounted and mounted...). Awesome. I did not like this method in the first place.

Solution Number Three

So I did more search on the web, and found that the daemon launcher in Mac was launchd. It has a bunch of interfaces. One may use launchctl to start or stop a daemon, to list all daemons alive, to list all daemons available, and much more. Daemons are defined with XML files. A feature particularly useful in my scenario is the ability to run a daemon when a volume is mounted. So I created the following launchd job, and saved it as a plist under ~/Library/LaunchAgents,

:::XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>org.darksair.refreshdesktop</string>
    <key>ProgramArguments</key>
    <array>
      <string>/Users/corsair/programs/refresh-desktop.sh</string>
    </array>
    <key>KeepAlive</key>
    <false/>
    <key>StartOnMount</key>
    <true/>
    <key>LaunchOnlyOnce</key>
    <true/>
  </dict>
</plist>

And refresh-desktop.sh ran like thus

:::Bash 
#!/bin/sh

FileVolList=/tmp/volume-list.txt

if [ ! -e ${FileVolList} ]; then
    touch ${FileVolList}
fi      
if ! grep '^Shared' ${FileVolList} > /dev/null; then
    ls -1 /Volumes > ${FileVolList}
    if grep '^Shared' ${FileVolList} > /dev/null; then
        # Shared is mounted.
        exec killall Dock
    fi  
fi      
ls -1 /Volumes > ${FileVolList}

Then I restarted the machine, and found that several seconds after the encrypted volume was mounted, the desktop flickered, and the correct wallpaper was loaded. Another stupid problem solved!