Fully automatic backup/sync script with Unison

I’ve been searching for something to replace offline files in Linux. It’s a great feature that Linux just doesn’t have where files on a share can be stored locally and synced when back on the network. A Dropbox like solution seems like a close enough alternative, but these programs are expensive and can’t be centrally managed. So I made my own, albeit less fully featured. Unison is an open source bidirectional sync tool. It can be set to use time based conflict resolution without notifying the user. Let’s hope the clocks are correct.

One problem with Unison is deploying it automatically. I have a file server that I mount with pam_mount. I mount it to ~/.whatever so it stays hidden to the user. Next I put a script to insert it into crontab. Now all the user has to do is run that script and they files are backed up. libnotify even tells them so. The script also takes care of the initial server to local sync. If we didn’t do this unison would think we wanted to delete all files on the server (don’t worry it would throw an error unless you used a specific argument). So here it is.

[python]import os

# Place this in a cron job for say every 2 minutes. To script this use
# crontab -l | { cat; echo "0 0 0 0 0 some entry"; } | crontab –

# You may also want to run ntpd on all clients to keep the time in sync.

# Array of locations of local and remote locations. I recommend mounting remote folders in
# Example ((‘/home/user/Documents’, ‘/remotehostname/somefolder’),)
sync_locations = (
("/home/david/local", "/home/david/server"),
)
# Check if host is up
check_host = "localhost"

# Only allow this program to run once!
try:
import socket
s = socket.socket()
host = socket.gethostname()
port = 35636 #make sure this port is not used on this system
s.bind((host, port))
except:
exit()
if not os.path.exists(os.getenv("HOME") + ‘/.unison_backup’):
os.mkdir(os.getenv("HOME") + ‘/.unison_backup’)

if os.path.exists(sync_locations[0][0]) and 0 == os.system(‘ping -c 1 ‘ + check_host):
if not os.path.isfile(os.getenv("HOME") + "/.unison_backup/first_sync_complete"):
os.system(‘notify-send "Unison Backup" "Starting Initial Sync. You will be notified when finished."’)
for sync_location in sync_locations:
exit_code = os.system(‘rsync -r ‘ + sync_location[1] + "/ " + sync_location[0])
if exit_code != 0:
os.system(‘notify-send "Could not sync!"’)
exit()
open(os.getenv("HOME") + ‘/.unison_backup/first_sync_complete’, ‘w’).close()
os.system(‘notify-send "Unison Backup" "Initial Sync Complete"’)

# Run Unison
for sync_location in sync_locations:
os.system(‘unison %s %s -batch -prefer newer -times=true’ % (sync_location[0], sync_location[1]))
[/python]

By David

I am a supporter of free software and run Burke Software and Consulting LLC. I am always looking for contract work especially for non-profits and open source projects. Open Source Contributions I maintain a number of Django related projects including GlitchTip, Passit, and django-report-builder. You can view my work on gitlab. Academic papers Incorporating Gaming in Software Engineering Projects: Case of RMU Monopoly in the Journal of Systemics, Cybernetics and Informatics (2008)

3 comments

  1. I am ubuntu user. I want to syncronize between 2 laptops/pc with the same ubuntu OS. What should I do with your script above? Should I copy it and then what can I do?

    Like

Leave a comment