zfs-backup 2.4 KB

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