backup-zfs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #!/bin/bash
  2. set -euo pipefail
  3. IFS=$'\n\t'
  4. #
  5. # Backup a ZFS Filesystem.
  6. #
  7. # Uses ZFS `send` and `receive` to perform incremental backups for a filesystem
  8. # and its descendents. Snapshots created to facilitate this are formatted as
  9. # "manualbackup-YYYY-MM-DD".
  10. #
  11. usage="Usage: ${0##*/} target_filesystem backup_filesystem"
  12. fsFrom=${1:?$usage}
  13. fsTo=${2:?$usage}
  14. # Check that filesystems exist. Also checks that `zfs` exists.
  15. zfs list -Hd 0 $fsFrom > /dev/null
  16. zfs list -Hd 0 $fsTo > /dev/null
  17. echo "Source: $fsFrom"
  18. echo "Destination: $fsTo"
  19. snapPrefix="manualbackup"
  20. # Look for a previous snapshot created by this script.
  21. snapList=$(zfs list -Ht snapshot | grep $snapPrefix || true)
  22. prevSnap=$(echo $snapList | head -n 1 | sed 's/.*@\([^ ]*\)\ *.*/\1/')
  23. echo "Prev Snapshot: ${prevSnap:-none}"
  24. # Next snapshot will be marked with today's date.
  25. nextSnap=$snapPrefix-$(date +%Y-%m-%d)
  26. echo "Next Snapshot: $nextSnap"
  27. echo ""
  28. # Same snapshot? Nothing to do.
  29. [[ $prevSnap == $nextSnap ]] && echo "Not backing up." && exit
  30. # pv check: displays transfer speed during backup.
  31. hasPv=$(which pv || true)
  32. [[ -z $hasPv ]] && echo "Note: Install \`pv\` for transfer speed during backup."
  33. # tmux check: helps avoid accidentally stopping the backup process.
  34. if [[ -z ${TMUX:-} ]]; then
  35. echo "Backing up can take a while! You really should run this in \`tmux\`."
  36. echo "Type 'No need for tmux' to run anyway, or press Enter to exit."
  37. read ANS
  38. [[ $ANS != "No need for tmux" ]] && exit
  39. fi
  40. echo "Ready. Proceed? (y/n)"
  41. read ANS
  42. [[ $ANS != "y" ]] && exit
  43. echo "Creating snapshot $fsFrom@$nextSnap"
  44. zfs snapshot -r $fsFrom@$nextSnap || true
  45. # Previous snapshot exists?
  46. # No = perform an initial full backup.
  47. # Yes = perform an incremental backup.
  48. if [[ -z $prevSnap ]]; then
  49. echo "Initial full backup starting..."
  50. if [[ -n $hasPv ]]; then
  51. zfs send -R $fsFrom@$nextSnap | pv | zfs receive -F $fsTo
  52. else
  53. zfs send -R $fsFrom@$nextSnap | zfs receive -F $fsTo
  54. fi
  55. else
  56. echo "Incremental backup starting..."
  57. if [[ -n $hasPv ]]; then
  58. zfs send -R -i $fsFrom@$prevSnap $fsFrom@$nextSnap | pv | zfs receive -F $fsTo
  59. else
  60. zfs send -R -i $fsFrom@$prevSnap $fsFrom@$nextSnap | zfs receive -F $fsTo
  61. fi
  62. fi
  63. echo "ZFS Sending/Receiving done."
  64. if [[ -n $prevSnap ]]; then
  65. echo $'\nDestroy previous snapshot and finalise backup? (y/n)'
  66. read ANS
  67. if [[ $ANS == "y" ]]; then
  68. zfs destroy -R $fsFrom@$prevSnap
  69. zfs destroy -R $fsTo@$prevSnap
  70. fi
  71. fi