Skip to content

Instantly share code, notes, and snippets.

@skrajewski
Last active December 19, 2023 14:54
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save skrajewski/a8b43ce3e5f0fe0971887bac7c45fe18 to your computer and use it in GitHub Desktop.
Save skrajewski/a8b43ce3e5f0fe0971887bac7c45fe18 to your computer and use it in GitHub Desktop.
Automate your macOS backup to Backblaze B2 using Restic and launchd.
#!/bin/bash
PID_FILE=~/.restic_backup.pid
TIMESTAMP_FILE=~/.restic_backup_timestamp
if [ -f "$PID_FILE" ]; then
if ps -p $(cat $PID_FILE) > /dev/null; then
echo $(date +"%Y-%m-%d %T") "File $PID_FILE exist. Probably backup is already in progress."
exit 1
else
echo $(date +"%Y-%m-%d %T") "File $PID_FILE exist but process " $(cat $PID_FILE) " not found. Removing PID file."
rm $PID_FILE
fi
fi
if [ -f "$TIMESTAMP_FILE" ]; then
time_run=$(cat "$TIMESTAMP_FILE")
current_time=$(date +"%s")
if [ "$current_time" -lt "$time_run" ]; then
exit 2
fi
fi
if [[ $(networksetup -getairportnetwork en0 | grep -E "Home-Network|Work-Network") == "" ]]; then
echo $(date +"%Y-%m-%d %T") "Unsupported network."
exit 3
fi
if [[ $(pmset -g ps | head -1) =~ "Battery" ]]; then
echo $(date +"%Y-%m-%d %T") "Computer is not connected to the power source."
exit 4
fi
echo $$ > $PID_FILE
echo $(date +"%Y-%m-%d %T") "Backup start"
export B2_ACCOUNT_ID=$(security find-generic-password -s backup-restic-b2-accound-id -w)
export B2_ACCOUNT_KEY=$(security find-generic-password -s backup-restic-b2-account-key -w)
export RESTIC_REPOSITORY=$(security find-generic-password -s backup-restic-repository -w)
export RESTIC_PASSWORD_COMMAND='security find-generic-password -s backup-restic-password-repository -w'
/usr/local/bin/restic backup --verbose -o b2.connections=20 --files-from ~/backup.txt
echo $(date +"%Y-%m-%d %T") "Backup finished"
echo $(date -v +6H +"%s") > $TIMESTAMP_FILE
rm $PID_FILE
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
<key>Label</key>
<string>pl.skrajewski.restic_backup</string>
<key>Program</key>
<string>/Users/szymon/scripts/backup.sh</string>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>300</integer>
<key>WorkingDirectory</key>
<string>/Users/szymon/</string>
<key>StandardOutPath</key>
<string>/Users/szymon/Library/Logs/pl.skrajewski.restic_backup.out.log</string>
<key>StandardErrorPath</key>
<string>/Users/szymon/Library/Logs/pl.skrajewski.restic_backup.error.log</string>
</dict>
</plist>
@porteusconf
Copy link

porteusconf commented Aug 26, 2022

Note: https://szymonkrajewski.pl/macos-backup-restic/ explains reasoning of script in detail. And has following restic code to create a binary executable backup_wrapper for"MacOS Catalina: Dealing with System Integrity Protection (SIP) and new permissions"

import Foundation
import os

let task = Process()

task.launchPath = "/bin/bash"
task.arguments = ["/Users/szymon/scripts/backup.sh"]

do{
    try task.run()
}
catch{
    os_log("error")
}

task.waitUntilExit()

@colindensem
Copy link

Thank you for the work on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment