Two years ago I wrote about a shell script that I used with cron to keep ‘critical’ applications running. Some of the commenters suggested that I “should” be using launchd. There are times when I still prefer cron over launchd but there are two reasons why I have started using launchd more often. The first is Lingon, and the second is learning more about what launchd can do.
Lingon & the Mac App Store: A Mini-Rant
Lingon 3 is a US$3 app which makes writing and managing launchd plists easy. Lingon has been a ‘nerd tool’ for a long time. A long time ago there was a version available for free. When the Mac App Store opened, Lingon 2 was released for $US5. This naturally enraged some people who believe that software developers have the ability to feed themselves on sandwiches made from air and good feelings.
To make matters worse, Lingon ran into the new “sandboxing” restrictions for the Mac App Store.
Briefly stated, sandboxing rules now limit what any Mac App Store application can do. These restrictions are imposed by Apple for other developers, even though Apple allows its own software to do many things which aren’t possible with sandboxing restrictions. If you have noticed apps leaving the Mac App Store recently, there’s a good chance sandboxing is the reason. Sandboxing is a good idea, but right now it is so restrictive that it is causing more problems than it solves. Hopefully this situation will get better as Apple increases what sandboxed apps can do, but for now developers are left with little choice.
Peter Borg, Lingon’s developer, was faced with a choice: either neuter Lingon 2 to fit sandboxing requirements, or release a new version of Lingon. This was a bit of a “no-win” situation that many developers are facing. Updating Lingon 2 to comply with sandboxing requirements would mean that users who had purchased Lingon 2 and then updated to the newer version would lose features they had paid for. Creating a new version of Lingon would allow the developer to make sure that it complied with sandboxing requirements, but customers who bought Lingon 2 would have to pay for Lingon 3 because the Mac App Store does not have any way for developers to offer upgrade pricing to existing customers.
He chose to make a new version of Lingon (version 3) priced at $3 instead of $5, which makes sense because it could do less than Lingon 2. For those who still want Lingon 2, it is still available as a separate app. Despite having made a reasonable choice between two less-than-ideal options, the Mac App Store reviews call it “horrible” and “useless” for not having the features that Apple won’t let the developer include. All of which is fairly ridiculous, especially when you realize that you’re talking about two versions of an app which, together, cost $8.
launchd, KeepAlive, and SuccessfulExit
Apple released launchd as part of Mac OS X 10.4 (“Tiger”) in 2005, and has steadily improved it ever since. There is no shortage of documentation for it, including Creating Launch Daemons and Agents and the launchd.plist Manual Page, but it’s easy to get overwhelmed with the amount of information available.
Personally, I find it a lot easier to look at working examples, and see how and why they work. Here’s a fairly generic template that I created for you to use:
If you want to use that, click/tap on the ‘raw’ link and it will load in your browser, then save it to your computer.
To modify it, just change the two parts written in ALL CAPS. Replace “YOUR.NAME.HERE” with anything you want. It just has to be unique on your system.
The “KeepAlive” key tells launchd to restart the process if it stops for any reason. This ensures that the program will be available all the time, but there’s a problem: what happens when there’s a new version of the app and you want to install the update? You can quit the app, but launchd is just going to restart it. That’s where SuccessfulExit comes in. By setting that to ‘false’ we are telling launchd to only restart this program if the app does not exit successfully. So if you quit the app yourself for some reason, launchd assumes that you want to keep it off until you restart the application, reboot your Mac, or log out and then back in.
Then replace “/PATH/TO/PROGRAM/YOU/WANT/TO/KEEP/RUNNING” to the path on your system. Note that if you want to keep an app running, you have to include the path all the way to the executable file, not just the “.app” so if you wanted to keep Dropbox running all the time, the path would be /Applications/Dropbox.app/Contents/MacOS/Dropbox and not just /Applications/Dropbox.app!
There are two other potential problems:
Spaces in path names
Sometimes what you want to keep running isn’t obvious at first.
I’m going to address both of those using a plist that I use to keep Keyboard Maestro’s helper engine running:
You’ll notice that I don’t want to keep Keyboard Maestro running. I want to keep “Keyboard Maestro Engine” running. If you aren’t sure what the correct path is, you can go into Terminal.app and type:
ps auxww | fgrep -i ‘WORD’ | fgrep -v fgrep
Replace “WORD” with whatever word you want to search for: iTunes, Evernote, Hazel, etc. Look for words such as “Watcher” or “Helper” — those are often the ones that you might want to keep running.
If the path you find has spaces it in (like Keyboard Maestro Engine does), try it without using either quotes or back-slashes () first, and see if it works. If it doesn’t work, try adding backslashes before each space or before any punctuation that isn’t a period or a slash.
Once you have your plist created, save it to ~/Library/LaunchAgents/ and then load it using launchctl load like this:
launchctl load ~/Library/LaunchAgents/your.name.here.plist
or just log out/reboot.
Note: it is a good idea to use the same name for the filename as you chose for the label (YOUR.NAME.HERE) but make sure to add the “.plist” in the filename.
Lingon makes it easier
Now you know how to plists by hand, but I suspect most people would prefer an easier way. Enter Lingon.
Launch Lingon and it will show you all of your existing launchd plists in ~/Library/LaunchAgents/:
Don’t be surprised if there several already in there. Click the plus (+) at the top-left and Lingon will prompt you to save:
Now, I know it might seem counter-intuitive to have “save” be your first step, but you’ll see why in a moment. Once you choose a name, Lingon will expand to show you this:
Let’s take a closer look at that front panel:
Lingon has already filled in the “Name” field based on the filename you chose for the “Save As” command. Smart! Now you just have to choose what app or program you want to keep running. I’m going to choose Dropbox.
Notice that I have only selected the Dropbox.app itself.
“But wait!” you cry, “Didn’t you say before that you need to select the app binary, not just the app wrapper?” Yes, I did. But Lingon is smart enough to add the “Contents/MacOS/Dropbox” even though I just selected Dropbox.app.
See?
Now that you have chosen a program, you need to tell Lingon when you want to run it. Note that I have chosen both “Keep Running” and “At login and at load.” Now in my experience, I have not needed to to specify “At login and at load” but the launchd.plist Manual Page says that ‘[SuccessfulExit] implies that “RunAtLoad” is set to true, since the job needs to run at least once before we can get an exit status.’ So I select both. Fortunately launchd is smart enough not to launch two of them.
When you’re finished, click ‘Save & Load’ and Lingon will show you your new plist in the list:
Voil