borg_wrap.sh 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #!/bin/sh
  2. ##### This is my (demuredemeanor) borgbackup wrapper script.
  3. # Blog Post: https://demu.red/blog/2017/02/backups-revisited/
  4. # Source Code: https://notabug.org/demure/scripts/src/master/borg_wrap.sh
  5. # Uses tabstop=4; shiftwidth=4 tabs; foldmarker={{{,}}};
  6. #
  7. # This is a script to run my borg backups.
  8. # It has basic config error checking, and verifies I am on my home network.
  9. # Usage: borg_wrap.sh [-q|--quiet]
  10. #
  11. # Note: I run this as root, and have a /etc/sudoers.d/ file granting permissions.
  12. #
  13. # Note: I run this via crontab
  14. # 0 */1 * * * sudo /usr/local/sbin/borg_wrap.sh -q
  15. #
  16. # Note: pruning:
  17. # Keep last last 24h, one per day of last week, one per week of last month, one per month.
  18. # borg prune -v --list --dry-run -d=7 -w=4 -m=-1 --keep-within=1d /path/to/repo
  19. ### Conf ### {{{
  20. ## Set Repo location
  21. export BORG_REPO='ssh://demure@10.0.0.10:500/mnt/borg/doom-x270'
  22. ## Set the right ssh key
  23. ## Note, use with the following in the destination ssh authorized_keys
  24. ## 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[...]
  25. export BORG_RSH="ssh -i $HOME/.ssh/borg_id_ed25519"
  26. ## Pull Repo passwd
  27. export BORG_PASSPHRASE="$(pass cli/borg 2>/dev/null)"
  28. ## Path to log file
  29. Log_Path="$HOME/.config/borg/log"
  30. ## Temp file for log pruning
  31. Log_tmp="/tmp/borg_log.tmp"
  32. ## Define remote MAC addr, for security check.
  33. MAC_addr="24:5e:be:0d:b4:02"
  34. ## Define remote address, for testing.
  35. Host="10.0.0.10"
  36. ## Define User for chmod fix (due to running with sudo)
  37. User="demure"
  38. ### End Conf ### }}}
  39. ### Conf Check ### {{{
  40. ## Exit if BORG_REPO not specified.
  41. if [ "${BORG_REPO}" = "" ]; then
  42. echo 'No repo specified.'
  43. exit 78
  44. fi
  45. ## Exit if no log file specified.
  46. if [ "${Log_Path}" = "" ]; then
  47. echo 'No log file specified.'
  48. exit 78
  49. fi
  50. ## Exit if no router MAC specified.
  51. if [ "${MAC_addr}" = "" ]; then
  52. echo 'No router MAC specified.'
  53. exit 78
  54. fi
  55. ## Exit if storage address specified.
  56. if [ "${Host}" = "" ]; then
  57. echo 'No storage address specified.'
  58. exit 78
  59. fi
  60. ## Exit if no chown user specified.
  61. if [ "${User}" = "" ]; then
  62. echo 'User for chown not set.'
  63. exit 78
  64. fi
  65. ### End Conf Check ### }}}
  66. ### Startup Check ### {{{
  67. ### Augment Check ### {{{
  68. if [ $# -gt 1 ]; then
  69. echo 'Too many augments.'
  70. exit 1
  71. fi
  72. if [ ! -z "$1" ]; then
  73. if [ "$1" = '-q' ] || [ "$1" = '--Quiet' ]; then
  74. VERBOSE=""
  75. Quiet=1
  76. else
  77. echo 'Bad augments.'
  78. exit 1
  79. fi
  80. else
  81. VERBOSE='-v --stats -p'
  82. Quiet=0
  83. fi
  84. ### End Augment Check ### }}}
  85. ### Network Check ### {{{
  86. ## Check for host, then check if MAC addr matches
  87. ping -c 3 $Host 1>/dev/null
  88. if [ ! $? = 0 ]; then
  89. if [ $Quiet -eq 0 ]; then
  90. echo "Can't reach host."
  91. fi
  92. Error='NoPing'
  93. else
  94. check_mac="$(/bin/ip neigh | awk -v HOST=${Host} '$0~HOST{print $5}')"
  95. if [ ! "$MAC_addr" = "$check_mac" ]; then
  96. if [ $Quiet -eq 0 ]; then
  97. echo "Not on home network."
  98. fi
  99. Error='BadNet'
  100. fi
  101. fi
  102. ### End Network Check ### }}}
  103. ### Passwd Load Check ### {{{
  104. if [ -z "$BORG_PASSPHRASE" ]; then
  105. if [ $Quiet -eq 0 ]; then
  106. echo "Password failed to load."
  107. fi
  108. Error='NoPass'
  109. fi
  110. ### End Passed Load Check ### }}}
  111. ### End Startup Check ### }}}
  112. ## If no errors, run.
  113. ## A suggested naming convntion
  114. ## ::'{hostname}_{now:%Y-%m-%d_%H%M}' \
  115. if [ -z $Error ]; then
  116. borg create ${VERBOSE} -C lz4 \
  117. ::'doom-x270_{now:%Y-%m-%d_%H%M}' \
  118. / \
  119. --exclude-caches \
  120. -e /dev \
  121. -e /media/ \
  122. -e /mnt/ \
  123. -e /proc \
  124. -e /run \
  125. -e /sys \
  126. -e /tmp \
  127. -e /var/cache \
  128. -e '/var/tmp/*' \
  129. -e '/home/*/Downloads/' \
  130. -e '/home/*/temp/' \
  131. -e '/home/*/vault' \
  132. -e '/home/*/.config/chromium' \
  133. -e '/home/*/.local/share/mana/updates' \
  134. -e '*.cache' \
  135. -e '*.mail' \
  136. -e '*.thumbnails'
  137. ## Catch exit code
  138. Error=$?
  139. fi
  140. ## Log pass/fail state
  141. if [ ! $Error = "0" ]; then
  142. echo "$(date '+%F %T')\tfailed\t${Error}" | cat >> ${Log_Path}
  143. else
  144. echo "$(date '+%F %T')\tpassed" | cat >> ${Log_Path}
  145. fi
  146. ## This prunes the log, leaving last 30 days.
  147. ## If no passed backups in 30 days, also leaves lasted passed entry.
  148. ## You can comment out to disable
  149. 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}
  150. ## Fix borg permissions so that things like `borg list` work without sudo
  151. chown -R ${User}:${User} ${HOME}/.config/borg ${HOME}/.cache/borg