September 02, 2009
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.