CodeGnome Consulting, LTD

Programming - DevOps - Project Management - Information Security

Enabling Scheduled Jobs on OS X Mavericks

| Comments

Apple is known for cool hardware. Apparently, they should also be known for replacing perfectly good Unix utilities with XML-based abominations like launchd. Systems administrators have been automating tasks with crond and atd since the Epoch, and nobody loves XML except for Java programmers and the W3C.

So, what can one do if you’re on a recent version of OS X and want to run scheduled jobs? Fear not, gentle reader; Cupertino has not yet destroyed all that is good in BSD userland.

Cron Daemon

Apparently, all that’s necessary for cron to work is for at least one valid crontab to exist. The easiest way to make that happen is to put an empty crontab in the root of your home directory.

enable crond
1
2
touch   ~/.crontab
crontab ~/.crontab

OS X will then place a copy of that crontab into a system directory as /usr/lib/cron/tabs/$LOGNAME, and launchd will then start the cron daemon. Sadly, you still won’t be able to use standard cron commands like crontab -e or crontab -l to edit or list your crontab. Doing so will result in mystifying errors like:

$ crontab -e
crontab: temp file must be edited in place

Instead, you have to edit ~/.crontab with your text editor of choice, and then re-run crontab ~/.crontab every time you want the system to notice the change.

Apple really “thought differently” about this one, but at least it’s manageable.

At Daemon

The at daemon is a little trickier. In order to enable atd while launchd is already running, you need to modify some OS X settings.

enable atd
1
2
sudo launchctl unload -F /System/Library/LaunchDaemons/com.apple.atrun.plist
sudo launchctl load   -w /System/Library/LaunchDaemons/com.apple.atrun.plist

This will force atd to start immediately, but if you want to ensure that atd stays enabled across reboots, you’ll need to edit the actual plist XML. For example:

modify atrun plist
1
2
3
4
sudo sed \
     -i '' \
     -e 's!\(<key>\)Disabled\(</key>\)!\1Enabled\2!' \
     /System/Library/LaunchDaemons/com.apple.atrun.plist

Once you’ve done these things, the at command will work as you expect, even across reboots. For example:

test atd by touching file
1
2
3
4
5
6
# NB: By default, atd runs at 30 second intervals. The sleep command
# just ensures we give the daemon time to run and for our example to
# work. See the StartInterval key in the plist XML to change this.
echo 'touch /tmp/at-command-works' | at now
sleep 35
ls -l /tmp/at-command-works

Putting It All Together

If you don’t care about the details, just run the following script:

$HOME/bin/enable_crond_and_atd.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env bash

# Enable atd and crond on OS X Mavericks, because they're disabled by
# default in favor of launchd.

touch   ~/.crontab
crontab ~/.crontab

sudo sed \
     -i '' \
     -e 's!\(<key>\)Disabled\(</key>\)!\1Enabled\2!' \
     /System/Library/LaunchDaemons/com.apple.atrun.plist

sudo launchctl unload -F /System/Library/LaunchDaemons/com.apple.atrun.plist
sudo launchctl load   -w /System/Library/LaunchDaemons/com.apple.atrun.plist

Comments