Using CRON to Control TimeMachine Backups
Sep 2nd, 2009 by mark
My office setup includes two Macintosh computers, a Mac Pro and a MacBook Pro. I have a 500 GB FireWire drive attached to the Mac Pro that I use for TimeMachine backups. Through the power of a DNS entry for the Mac Pro, and this article on Network Time Machine backups to another Mac, I am able to backup the MacBook Pro, wirelessly, to the TimeMachine drive on the Mac Pro.
The only problem with this arrangement is that the MacBook Pro attempts to back itself up regardless of my location. When I’m at home at it is connected to our home network it can locate my work computer (via the DNS entry) and it tries to use our less-than-significant upload bandwidth to backup once an hour. The simple solution is to turn TimeMachine off when I am at home. Of course that means remembering to turn it back on again the next day I’m at work. On occasion the simple solution has meant the MacBook Pros backups are a week or more behind.
A better solution would be a script or automated action that would turn TimeMachine on or off. Since I work relatively stable hours a cron job coupled with code to activate or deactivate TimeMachine would suffice.
You can turn TimeMachine on or off via Terminal using this defaults command:
defaults write /Library/Preferences/com.apple.TimeMachine AutoBackup -boolean [YES|NO]
I created two bash scripts, one to turn TimeMachine on:
#!/bin/bash defaults write /Library/Preferences/com.apple.TimeMachine AutoBackup -boolean YES
And another to turn it off:
#!/bin/bash defaults write /Library/Preferences/com.apple.TimeMachine AutoBackup -boolean NO
The final step is to create two cron entries, one for 8 am Monday through Friday to run the “on” script from above. And the second for 5 pm Monday through Friday to run the “off” script from above. Crontab entries are in this order: minute hour day-of-month month day-of-week what-to-do. The day-of-week entry uses either 0 or 7 for Sunday, with Monday as 1, Tuesday as 2, and so forth. So the “on” script entry would look like this: 0 8 * * 1-5 ~/bin/timeMachineon.sh and the “off” script entry would look like this: 0 8 * * 1-5 ~/bin/timeMachineoff.sh.
Here’s my completed crontab:
# minute hour day-of-month month day-of-week what # activate TimeMachine zero minutes past 8 am M-F 0 8 * * 1-5 ~/bin/timeMachineon.sh # deactivate TimeMachine zero minutes past 5 pm (17) M-F 0 17 * * 1-5 ~/bin/timeMachineoff.sh
Now TimeMachine only runs during working hours when I am (presumably) on the work network.
Update 1: The evening cron job fails to run when the laptop is closed, i.e., sleeping, when 5 pm rolls around. Cron is a useful tool but it has to be awake to run. I’ve changed the evening cron time to 4 pm, a time I am almost always still at work. I am considering adding a second evening crontab entry, say for 7 or 8 pm in case the 4 o’clock instance is missed for some reason. A better solution would be a network aware triggering of the scripts, running the on script only when the work network is detected, and the off script for all other networks.
Update 2: Here’s the latest solution, based on Josh’s comments.
I created a script called login-hook.sh, which is the target of:
sudo defaults write com.apple.loginwindow LoginHook ~/bin/login-hook.sh
This script tests to see if a TimeMachine control script is running at every login, and starts it if necessary:
#!/bin/bash # login-hook.sh if [ "$(ps ax | grep tm-control.sh | grep -vc grep)" -lt 1 ]; then sudo -u mhn /Users/mhn/bin/tm-control.sh & fi
And tm-control.sh runs the Python script Josh supplied every 30 minutes (1800 seconds), in effect simulating a cron job, but leveraging the network awareness of the Python script. Here’s tm-control.sh:
#!/bin/bash # tm-control.sh while [ 1 ]; do python ~/bin/TM_off_on.py sleep 1800 done
Update 3: Getting LoginHook to work is a bit finicky. By using defaults read com.apple.loginwindow LoginHook, you can display the current setting, if any, this attribute has. defaults delete com.apple.loginwindow LoginHook will allow you to remove the setting. Make sure you have your login-hook.sh, and the script it calls in place prior to establishing the hook and you should be okay.
Two thoughts:
1) Run your cron job every 15 minutes. Those bash scripts consume next to no resources, is completely invisible, and doesn’t require you to have your laptop open at (such) a specific time of day.
*/15 8-16 * * 1-5 ~/bin/timeMachineon.sh
*/15 0-7,17-23 * * * 1-5 ~/bin/timeMachineoff.sh
2) Here’s a Python script I wrote that does the same toggle, but based on some logic:
http://dpaste.com/hold/88981/
Save it somewhere, and then run this in Terminal:
sudo defaults write com.apple.loginwindow LoginHook /path/to/script.py
This creates a login hook that will execute the Python script every time you login (and just the once). The script fetches your IP address, if it can, and checks if that’s in the “129.130″ range. Failing that, it’ll fall back to your day and time logic, and toggles TimeMachine one way or the other.
I haven’t *really* tested this, but I think it’ll work. Moreover, I’m not sure if the IP thing will work so close to “login”, but I think so (I often hear the “New Mail” sound long before I get my password typed in).
Of course my LoginHook above won’t work, because you can’t directly call a Python script, so you’ll have to wrap it in a shell script instead. Something as simple as:
#!/bin/bash
python ~/bin/TM_off_and_on.py
Make sure that file is executable, and set *it* as the target of the LoginHook code above. Seems to work for me.