123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- #!/bin/sh
- ##### This is my (demuredemeanor) borgbackup wrapper script.
- # Blog Post: https://demu.red/blog/2017/02/backups-revisited/
- # Source Code: https://notabug.org/demure/scripts/src/master/borg_wrap.sh
- # Uses tabstop=4; shiftwidth=4 tabs; foldmarker={{{,}}};
- #
- # This is a script to run my borg backups.
- # It has basic config error checking, and verifies I am on my home network.
- # Usage: borg_wrap.sh [-q|--quiet]
- #
- # Note: I run this as root, and have a /etc/sudoers.d/ file granting permissions.
- #
- # Note: I run this via crontab
- # 0 */1 * * * sudo /usr/local/sbin/borg_wrap.sh -q
- #
- # Note: pruning:
- # Keep last last 24h, one per day of last week, one per week of last month, one per month.
- # borg prune -v --list --dry-run -d=7 -w=4 -m=-1 --keep-within=1d /path/to/repo
- ### Conf ### {{{
- ## Set Repo location
- export BORG_REPO='ssh://demure@10.0.0.10:500/mnt/borg/doom-x270'
- ## Set the right ssh key
- ## Note, use with the following in the destination ssh authorized_keys
- ## command="borg serve --restrict-to-path /path/to/repo",no-pty,no-agent-forwarding,no-port-forwarding,no-X11-forwarding,no-user-rc ssh-rsa AAAAB3[...]
- export BORG_RSH="ssh -i $HOME/.ssh/borg_id_ed25519"
- ## Pull Repo passwd
- export BORG_PASSPHRASE="$(pass cli/borg 2>/dev/null)"
- ## Path to log file
- Log_Path="$HOME/.config/borg/log"
- ## Temp file for log pruning
- Log_tmp="/tmp/borg_log.tmp"
- ## Define remote MAC addr, for security check.
- MAC_addr="24:5e:be:0d:b4:04"
- ## Define remote address, for testing.
- Host="10.0.0.10"
- ## Define User for chmod fix (due to running with sudo)
- User="demure"
- ### End Conf ### }}}
- ### Conf Check ### {{{
- ## Exit if BORG_REPO not specified.
- if [ "${BORG_REPO}" = "" ]; then
- echo 'No repo specified.'
- exit 78
- fi
- ## Exit if no log file specified.
- if [ "${Log_Path}" = "" ]; then
- echo 'No log file specified.'
- exit 78
- fi
- ## Exit if no router MAC specified.
- if [ "${MAC_addr}" = "" ]; then
- echo 'No router MAC specified.'
- exit 78
- fi
- ## Exit if storage address specified.
- if [ "${Host}" = "" ]; then
- echo 'No storage address specified.'
- exit 78
- fi
- ## Exit if no chown user specified.
- if [ "${User}" = "" ]; then
- echo 'User for chown not set.'
- exit 78
- fi
- ### End Conf Check ### }}}
- ### Startup Check ### {{{
- ### Augment Check ### {{{
- if [ $# -gt 1 ]; then
- echo 'Too many augments.'
- exit 1
- fi
- ## Initialize Variables
- Quiet=0 ## Default, not quite
- VERBOSE='-v --stats -p' ## Default, verbose output
- Prune=0 ## Default, not prune mode
- DRY='' ## Default, not dry
- if [ ! -z "${1}" ]; then
- if [ "${1}" = '-q' ] || [ "${1}" = '--Quiet' ]; then
- VERBOSE=""
- Quiet=1
- elif [ "${1}" = '--prune' ]; then
- Prune=1
- elif [ "${1}" = '--dry-prune' ]; then
- Prune=1
- DRY='--dry-run'
- else
- echo 'Bad augments.'
- exit 1
- fi
- fi
- ### End Augment Check ### }}}
- ### Network Check ### {{{
- ## Check for host, then check if MAC addr matches
- ping -c 3 ${Host} 1>/dev/null
- if [ ! $? = 0 ]; then
- if [ ${Quiet} -eq 0 ]; then
- echo "Can't reach host."
- fi
- Error='NoPing'
- else
- check_mac="$(/bin/ip neigh | awk -v HOST=${Host} '$0~HOST{print $5}')"
- if [ ! "${MAC_addr}" = "${check_mac}" ]; then
- if [ ${Quiet} -eq 0 ]; then
- echo "Not on home network."
- fi
- Error='BadNet'
- fi
- fi
- ### End Network Check ### }}}
- ### Passwd Load Check ### {{{
- if [ -z "${BORG_PASSPHRASE}" ]; then
- if [ ${Quiet} -eq 0 ]; then
- echo "Password failed to load."
- fi
- Error='NoPass'
- fi
- ### End Passed Load Check ### }}}
- ### End Startup Check ### }}}
- ### Prune Mode ### {{{
- ## Note: prune mode shouln't need sudo
- if [ "${Prune}" -eq 1 ]; then
- if [ ! -z ${Error} ]; then
- echo "Error: ${Error}"
- exit 1
- fi
- borg prune ${DRY} -v -s --list -d=7 -w=4 -m=-1 --keep-within=1d
- exit 0
- fi
- ### End Prune Mode ### }}}
- ## If no errors, run.
- ## Note: Will need sudo if backing up system wide files
- ## A suggested naming convntion
- ## ::'{hostname}_{now:%Y-%m-%d_%H%M}' \
- if [ -z $Error ]; then
- borg create ${VERBOSE} -C lz4 \
- ::'doom-x270_{now:%Y-%m-%d_%H%M}' \
- / \
- --exclude-caches \
- -e /dev \
- -e /media/ \
- -e /mnt/ \
- -e /proc \
- -e /run \
- -e /sys \
- -e /tmp \
- -e /var/cache \
- -e '/var/tmp/*' \
- -e '/var/db/*' \
- -e '/home/*/Downloads/' \
- -e '/home/*/temp/' \
- -e '/home/*/vault' \
- -e '/home/*/.config/chromium' \
- -e '/home/*/.local/share/mana/updates' \
- -e '*.cache' \
- -e '*.mail' \
- -e '*.thumbnails'
- ## Catch exit code
- Error=$?
- fi
- ## Log pass/fail state
- if [ ! $Error = "0" ]; then
- echo "$(date '+%F %T')\tfailed\t${Error}" | cat >> ${Log_Path}
- else
- echo "$(date '+%F %T')\tpassed" | cat >> ${Log_Path}
- fi
- ## This prunes the log, leaving last 30 days.
- ## If no passed backups in 30 days, also leaves lasted passed entry.
- ## You can comment out to disable
- awk -v cutoff="$(date -d"-30 days" +%F)" 'BEGIN{pchk=0} {a[i++]=$0} END{for(j=i-1;j>=0;j--) if(a[j] >= cutoff || pchk==0 && a[j] ~ /passed/){if(a[j] ~ /passed/){pchk=1}; b[k++]=a[j]};{for(l=k-1;l>=0;l--) print b[l]}}' ${Log_Path} > ${Log_tmp} && mv ${Log_tmp} ${Log_Path}
- ## Fix borg permissions so that things like `borg list` work without sudo
- chown -R ${User}:${User} ${HOME}/.config/borg ${HOME}/.cache/borg
|