Symlink corruption on Mac OS X

Mac OS X on my desktop computer (a newish 27″ iMac, using a Promise Thunderbolt disk array for the root filesystem) seems to be having filesystem troubles. I notice it through symlinks going awry, though I’m sure they’re not the only victim. I tidied all the errant symlinks up two weeks ago, hoping it was a temporary glitch, but they’re back again today. Here’s an example:

> find -L /System -type l -print0 |xargs -0 ls -l
lrwxr-xr-x  1 root  wheel  24 15 Jan 09:42 /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers -> >File</string>????<key>L
lrwxr-xr-x  1 root  wheel  24 15 Jan 09:42 /System/Library/Frameworks/ApplicationServices.framework/Frameworks/HIServices.framework/Headers -> ?6?s?A??]h?_?:d9?r?
lrwxr-xr-x  1 root  wheel  24 15 Jan 09:42 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Headers -> >File</string>????<key>L
lrwxr-xr-x  1 root  wheel  24 15 Jan 09:42 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Headers -> ?6?s?A??]h?_?:d9?r?
lrwxr-xr-x  1 root  wheel  24 15 Jan 09:42 /System/Library/Frameworks/ApplicationServices.framework/Versions/Current/Frameworks/CoreGraphics.framework/Headers -> >File</string>????<key>L
lrwxr-xr-x  1 root  wheel  24 15 Jan 09:42 /System/Library/Frameworks/ApplicationServices.framework/Versions/Current/Frameworks/HIServices.framework/Headers -> ?6?s?A??]h?_?:d9?r?

Each of those symlinks are pointing to some garbage. (Interestingly, the garbage quite often looks like the partial contents of a plist file.)

Here’s another example, and this is one I remember fixing last time:

lrwxr-xr-x  1 root  wheel  27 12 Nov 19:06 /System/Library/Frameworks/JavaVM.framework/Frameworks -> Versions/Current/Frameworks
lrwxr-xr-x  1 root  wheel  24 15 Jan 09:43 /System/Library/Frameworks/JavaVM.framework/Headers -> Versions/Current/Headers
lrwxr-xr-x  1 root  wheel  23 12 Nov 19:06 /System/Library/Frameworks/JavaVM.framework/JavaVM -> Versions/Current/JavaVM
lrwxr-xr-x  1 root  wheel  26 15 Jan 09:45 /System/Library/Frameworks/JavaVM.framework/Resources -> Versions/Current/Resources
lrwxr-xr-x  1 root  wheel   1  8 Jan 14:57 /System/Library/Frameworks/JavaVM.framework/Versions/Current -> c

The problem here isn’t the first four symlinks – they’re all pointing to the right places – but the last one (which they’re all pointing through) which is pointing to ‘c’, not ‘A’ like it should.

The symlink targets all seem to be the right length, just the wrong characters.

How do I go about communicating with Apple about the problem so I can get it resolved? It doesn’t really seem the sort of thing I can take to a Genius Bar…

Running tmux in Mac OS X Terminal

I’ve been a fan of screen for … a while now. But since I like being one of the cool kids, I’ve been using tmux for the past year or so. Last week, I noticed that every time I launch a new terminal, I wind up typing tmux attach-session. Let’s streamline, a little bit.

In Mac OS X’s Terminal.app, you can change the shell that it runs. Here’s how I did it:

  • Open Preferences, and choose the Settings tab.

  • Duplicate your existing settings (since sometimes you might not want tmux after all). Pick your default session (mine’s “Pro”) and select “Duplicate settings” from the tool menu at the bottom. Name the new settings “Tmux” or something along those lines.

  • In the shell tab for your settings, select “Run command” and enter /usr/local/bin/tmux attach-session. Deselect “Run inside shell” since you don’t really need to. Since you’re not running inside a shell, /usr/local/bin probably isn’t in your $PATH so you’ll need to specify the full path name. Of course, if your tmux binary lives somewhere other than /usr/local/bin you’ll need to change the path.

  • If you’ve selected “Only if there are processes other than” for “Prompt before closing”, then you’ll probably want to add tmux to that list.

  • In the “Window” tab, I set “Scrollback” to limit the number of rows to ’0′, since tmux provides scroll back, and the Terminal one isn’t terribly useful when tmux is running inside it.

  • Make sure your Tmux session is set as the default one by clicking the “Default” button at the bottom of the settings lists while it’s selected.

That’s it. Close your existing terminal sessions and launch a new one. You should be launched into (one of) your existing tmux sessions. If tmux wasn’t already running, then this assumes that your ~/.tmux.conf sets up at least one session (which I think it required anyway). If you’ve got more than one tmux session running, I’ve no idea which one, offhand, it’ll choose, but you can always switch to the one you’re looking for with C-a s. (You have rebound the prefix to C-a, right?)

There’s (at least) one time where you don’t want tmux as your shell. That’s when you’re attempting to interact with launchd. I suspect it’s to do with launchd checking that you’re a child process as part of its permissions when you’re asking it to do stuff, where tmux works by detaching itself from its parent process so it’s not killed when the parent is. (Total guess, BTW.) Still, when you want to use launchctl, you’ll need to do it somewhere other than a tmux session. In Terminal, choose the Shell menu, choose “New Window” (or “New Tab”) and select one of the other settings profiles.

Pimpin’ TextMate (aka Top 5 TextMate Plugins, 2011 Edition)

All the cool kids are using Vim these days. That’s fine, y’all go right ahead, but sorry, it’s not really my thing. I’m perfectly happy with TextMate, thanks.

Don’t get me wrong; I’ve been using various flavours of Vi for 17 years now. I’m reasonably proficient at it, and it’s my tool of choice when I’m, say, editing server configuration files. I can plan and execute a series of changes to a file like a boss, when I already know what I’m doing. The trouble occurs when I’m coding, and what I’m trying to achieve isn’t yet a fully crystallised thought. Then, with Vi, I feel boxed in and a bit blinkered.

It’s just me, I know. Maybe the root of the problem is that I code before thinking. :)

So I still use TextMate, where I feel just a little more free and creative.

Anyway, this isn’t a post about Vim vs TextMate (there’s enough of them already!), I just wanted to get that off my chest.

I seem to be going through a phase of setting up fresh installs of my various desktop and laptop computers again (blame Lion). Instead of blindly installing all the same tools as I’m used to, I figured I’d reassess the landscape and see what’s out there. Here are a few plugins for TextMate I’ve tried, and liked.

  • PeepOpen is a file finder from the lovely folks at PeepCode. It replaces the default “Go to file…” (⌘-T) pane with one that’s a good deal smarter. Instead of matching just on the filename, it’ll match on the entire path. This is invaluable if your project has 300 files called show.html.erb. If I’m looking for, say, an article’s show template in a Rails project, typing avartsh (app/views/articles/show.html.erb) will get me there quickly.

    PeepOpen is $12, but it’s free as part of your PeepCode Unlimited subscription which you’d be crazy not to have anyway, right?

  • EGOTextMateFullScreen is a plugin that gives you native full screen support on Mac OS X Lion. On my desktop computer, a 27″ iMac, I didn’t really the point of full screen support (I much prefer a few windows tiled with the assistance of Sizeup). But then I got my hands on a Macbook Air and suddenly it made a whole lot more sense.

  • If you’re making use of the full screen support, then there’s one small snag: the drawer isn’t visible. I quite like the drawer; not to find files – because PeepOpen does a much better job – but to remind me of the context I’m in. When you’re editing a file, and need a reminder of the context, hit ctrl-⌘-R and your current file will be highlighted in the project tree.

    So if, like me, you’d miss the drawer in full screen mode, the old standby is the MissingDrawer plugin. This turns the drawer into a sidebar, which is part of the main window and, therefore, still visible in full screen mode.

  • Finally, project-wide search. The default Find in Project is a little … slow. And a bit beachball-y. For a while I’d been using a bundle that replaces the default Find in Project with one powered by Ack. Much faster, and a little more flexible too. When I went searching for it this time around, though, I discovered AckMate, a plugin which provides a more integrated experience. It’s fast. It can show you the context of the search result. It even allows you to constrain the results to particular file types. In short, it’s awesome. Be sure to read the instructions on how to set the shortcut key to the default “Find in Project…” one.

There’s one final plugin that I’m planning on evaluating, but haven’t quite gotten around to yet. The one, single, feature I liked in my brief affair with RubyMine was the ability to jump to a method definition. I’ve got a similar mechanism set up in Vim using exuberant ctags which works really well. (And back in the days before Mac OS X when Emacs was my hammer – and every C file a thumb – I lived by my TAGS files.) How I’d love project-wide “Go to symbol…”. There’s a plugin out there called TmCodeBrowser that appears to do exactly what I’m after. I’m slightly wary as it hasn’t been updated in quite some time, but perhaps that’s because it still just works. I’ll evaluate it soon and update this post when I do.

There’s one plugin I wish existed, but doesn’t seem to: split windows. I’ve got plenty of screen real estate. It would be crazy awesome to be able to have my model and its tests sitting side by side with a vertical split. If it’s possible to write a TextMate plugin that realises this, I would happily pay $12 for it (same price point as PeepOpen). Just so you know. ;-)

That’s it. I still love TextMate and I spend several hours working in it most days. Thanks for making code editing a lovely experience, Allan!

Converging your Home Directory with Chef

In this tutorial, I’ll take you through using Chef and Homebrew to manage your home directory in Mac OS X. I’ve also included a neat cookbook which will allow you to use Homebrew as your native packaging system in Chef.

TL;DR

  • Chef is awesome.

  • You can grab the cookbook to use Homebrew as the native packaging system for Chef on GitHub at chef-homebrew.

  • Managing your configuration isn’t just for servers.

  • If you spend any time at a command line, you owe it to yourself to use tmux (or screen).

  • The formatting of the code samples on this post is a work in progress… Sorry.

Getting Started with Chef

Mac OS X, and the current breed of open source developer tools (notably Homebrew and RVM) introduce an interesting possibility when it comes to managing one’s home directory. These mechanisms allow you to install arbitrary packages, owned and run by your own user.

So, you’ve got a package manager which installs software and allows you to start/stop services. You’ve got a bunch of configuration files, both for those services, and dotfiles in your home directory. What’s the best way to manage these? With some sort of configuration management tool, of course! There’s plenty to choose from (including lcfg, cfengine and Puppet) but the one I’ve been working with on and off for the past couple of years is Chef.

How do you get started? Well, personally, I’d just choose one piece of configuration to manage. Let’s say, for example, that you want to manage your tmux configuration. Let’s create a cookbook for that. Start with a repository:

mkdir personal-chef
cd personal-chef
touch README
git init
git add .
git commit -m "First post."

I like to use bundler to manage gem dependencies. There’s only one dependency right now — chef — but we might as well start out sensibly. Create a Gemfile in the root of your repository and give it the following content:

source :rubygems
gem 'chef'

Save that and run:

bundle

which will install chef & its dependencies. You might want to noodle around with a .rvmrc to get an isolated gemset for the project too (I do), but that’s very much a personal taste thing (that I’ll cover in another post).

Now let’s create a really basic configuration for chef-solo to allow it to put things in the right place, and to find its roles & cookbooks. Create a config folder in your new repository and add the following to config/solo.rb:

root_path = File.expand_path(File.join(File.dirname(__FILE__), '..'))
 
cookbook_path   File.join(root_path, 'cookbooks')
role_path       File.join(root_path, 'roles')
 
# Move all the state stuff from /var/chef. I wish there was a single config
# variable for this!
state_root_path = File.expand_path('~/.chef/state')
file_cache_path  "#{state_root_path}/cache"
checksum_path    "#{state_root_path}/checksums"
sandbox_path     "#{state_root_path}/sandbox"
file_backup_path "#{state_root_path}/backup"
cache_options[:path] = file_cache_path

I haven’t caught all the paths pointing to /var/chef but it has been enough for chef to stop whining at me so far. ;-)

Now let’s create ourselves some data that tells chef what we want to do with ourselves. As the configuration grows larger, I’m probably going to want to introduce roles, but let’s keep it simple for now. Create config/mathie.json (adjust to taste!) and fill it in with the following:

{
  "run_list": [ "recipe[tmux]" ]
}

Very simple for now. The final bit of context we’re going to want before we get to the interesting bits is a quick script to run chef. Here’s one I prepared earlier, called converge.sh:

#!/bin/bash
chef-solo -c config/solo.rb -j config/mathie.json $*

(That should probably be bundle exec chef-solo but it failed the time I tried it, and I haven’t yet tracked down why.) Make it executable:

chmod +x ./converge.sh

Add that lot to your git repository and commit if you haven’t been doing so already (little and often!). The last thing we need to do before we can verify the machinery is working is create a skeleton for the cookbook itself:

mkdir -p cookbooks/tmux/recipes
touch cookbooks/tmux/recipes/default.rb

All being well, the next thing we can do is test that it’s all wired up correctly:

./converge.sh

which should spit out ~6 lines from chef saying that it’s starting, finishing and tidying up. If that doesn’t work so well, try:

./converge.sh -l debug

(which is why we stuck the $* on the end of the chef-solo invocation in there!) and see if you can see what’s going wrong. If you can’t, drop me a comment and I’ll see if I can help!

Converging on tmux

So, we’ve got the infrastructure in place. Next thing we need to figure out is installing packages. Chef has some neat separation between what it refers to as ‘resources’ and ‘providers’ so that, in your recipes, you can say:

package 'tmux'

and it will do the right thing, no matter what platform you’re on. Unfortunately, Chef doesn’t ship with the ability to manage packages with Homebrew. That’s why I come in. I’ve put together a cookbook which will install homebrew if it doesn’t already exist, keep it up to date and, most importantly, hook into Chef to use Homebrew as the native package manager. Let’s pull that wonderful cookbook in using git’s subtree merge strategy (which, since we’re DevOps Ninjas, in this situation, is pretty much the way forward):

git remote add -f homebrew git://github.com/mathie/chef-homebrew.git
git merge -s ours --no-commit homebrew/master
git read-tree --prefix cookbooks/homebrew -u homebrew/master
git commit -m "Pull in mathie's awesome Homebrew cookbook."

(If I’ve just lost you, or you’re not using Git, head to https://github.com/mathie/chef-homebrew and stick the contents of that repository in cookbooks/homebrew.)

Now we should be good to go with getting tmux installed through Homebrew. Edit cookbooks/tmux/recipes/default.rb so that it contains:

include_recipe 'homebrew'
package 'tmux'

Save and commit (early and often!). Now run ./converge.sh. It should bumble around for a bit, installing Homebrew if you haven’t got it already, and installing tmux using Homebrew. Run it again, and it shouldn’t do a whole lot. Win.

Converging a tmux configuration

Last thing we’re going to do here, just to demonstrate managing configuration too, is installing a managed ~/.tmux.conf file. Add the following to cookbooks/tmux/recipes/default.rb:

template "#{ENV['HOME']}/.tmux.conf" do
  source "tmux.conf.erb"
end

and create cookbooks/tmux/templates/default/tmux.conf with your favourite tmux configuration. Let’s say, for example, that you’re on Mac OS X and you want to know the current battery level in your status bar:

set -g status-right "#[fg=green]#(pmset -g ps |awk 'BEGIN { FS=\"\t\" } /InternalBattery/ { print $2 }')"

(kinda useful, huh?) Now run:

    ./converge.sh

and your tmux configuration will magically be installed into ~/.tmux.conf. Neat, huh?

Conclusion

Chef isn’t just for managing your massively scaled production infrastructure. You can use it to manage lots of other things too, including your home directory. The win here is magnified with each computer you work with (home desktop, work desktop and a laptop while you’re out and about?).

So, have you tried using Chef to manage your home directory? How did you find it? Good stuff? Bad stuff? What other strategies have you tried?

Update In addition to publishing the Cookbook on Github as chef-homebrew I’ve also uploaded it to the Opscode Cookbooks. Get it here: homebrew.

Apple's most exciting WWDC announcement

OK, so nobody else seems to care as far as I can see from wading through my feeds since the WWDC keynote, but the most exciting feature I noticed was buried at the bottom of the preview of xcode 3.0:

Many such Xray instruments leverage the open source DTrace, now built into Mac OS X Leopard.

They’ve incorporated DTrace into Mac OS X! Perhaps I’m biased because I’ve been following Solaris development a bit lately, but this is really exciting news. DTrace seems to me (I’ve never actually used it, just read other people’s experiences) to be a fantastic tool for debugging and profiling both development and production systems. I’m really looking forward to using it (for example, dtrace on rails).

But that’s not what I’m getting really excited about. I’m getting really excited about something that was hinted a while ago and hasn’t, as far as I can see, been mentioned. Something else from the same open source codebase that would suit being integrated into Mac OS X. ZFS!