Last active
January 18, 2021 01:50
-
-
Save InternetUnexplorer/9213c0327a664e042d57efb80a1c8cb7 to your computer and use it in GitHub Desktop.
My current backup "solution". Both source and destination filesystems are btrfs. This will be replaced eventually; you should use btrfs-send or similar instead.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
################################ | |
BLOCK_DEVICE=/dev/disk/by-label/Backup | |
DM_NAME=cryptbackup | |
MOUNT_POINT=/mnt/backup | |
################################ | |
color() { echo -n "$(tput bold)$(tput setaf ${1})${2}$(tput sgr 0)" ; } | |
abort() { echo "$(color 1 'ERROR:') $(color 7 "${@}")"; exit 1 ; } | |
warn() { echo "$(color 3 'WARN:') $(color 7 "${@}")" ; } | |
info() { echo "$(color 4 'INFO:') $(color 7 "${@}")" ; } | |
step() { echo "$(color 4 '::') $(color 7 "${@}")" ; } | |
################################ | |
set -euo pipefail | |
DM_PATH="/dev/mapper/${DM_NAME}" | |
SRC="/" | |
PARENT="${MOUNT_POINT}/$(hostname)" | |
DEST="${PARENT}/latest" | |
SNAPSHOT="${PARENT}/$(date --iso-8601)" | |
# Make sure we have root privileges | |
[ "$EUID" -eq 0 ] || exec sudo bash "$0" "$@" | |
# Make sure the backup block device exists before mounting | |
[[ -e "${BLOCK_DEVICE}" ]] \ | |
|| abort "'${BLOCK_DEVICE}' is not a valid block device." | |
# Open block device if not already opened | |
if [[ ! -e "${DM_PATH}" ]]; then | |
step "Opening block device '${BLOCK_DEVICE}'..." | |
cryptsetup open -- "${BLOCK_DEVICE}" "${DM_NAME}" \ | |
|| abort "Unable to open device." | |
fi | |
# Mount mapped device if not already mapped | |
if ! mountpoint -- "${MOUNT_POINT}" > /dev/null; then | |
step "Mounting '${DM_PATH}' at '${MOUNT_POINT}'..." | |
mount -o compress=zstd:2 -- "${DM_PATH}" "${MOUNT_POINT}" \ | |
|| abort "Unable to mount device." | |
fi | |
# Make sure ${BACKUP_ROOT}/.backup exists and is a file | |
[[ -f "${MOUNT_POINT}/.backup" ]] \ | |
|| abort "'${MOUNT_POINT}' missing '.backup' file." | |
# Check whether a backup directory exists for this host | |
[[ -d "${PARENT}" ]] || info "Directory '${PARENT}' will be created." | |
# Check whether a subvolume exists for this host | |
[[ -d "${DEST}" ]] || info "Subvolume '${DEST}' will be created." | |
# Check whether a snapshot with the same date exists for this host | |
[[ ! -d "${SNAPSHOT}" ]] \ | |
|| warn "Existing snapshot '${SNAPSHOT}' will be overwritten." | |
# Print source, destination, and snapshot paths | |
echo "$(color 8 '------------------------------------------------')" | |
echo " $(color 4 "${SRC}") $(color 7 '->') $(color 5 "${DEST}")" | |
echo " $(color 0 "${SRC}") $(color 0 ' ') $(color 2 "${SNAPSHOT}")" | |
echo "$(color 8 '------------------------------------------------')" | |
# Ask for confirmation | |
read -p "$(color 7 'Proceed? (yes/no):') " | |
[[ $REPLY =~ ^(y|yes)$ ]] || exit 1 | |
# Create parent directory if not already present | |
if [[ ! -d "${PARENT}" ]]; then | |
step "Creating directory '${PARENT}'..." | |
mkdir -- "${PARENT}" || abort "Unable to create directory." | |
fi | |
# Create destination subvolume if not already present | |
if [[ ! -d "${DEST}" ]]; then | |
step "Creating subvolume '${DEST}'..." | |
btrfs subvolume create -- "${DEST}" || abort "Unable to create subvolume." | |
fi | |
# Synchronize files (index is built first) | |
step "Synchronizing files..." | |
rsync --archive \ | |
--acls \ | |
--xattrs \ | |
--sparse \ | |
--relative \ | |
--numeric-ids \ | |
--delete \ | |
--delete-excluded \ | |
--include='/home/***' \ | |
--exclude='*' \ | |
--info=progress2 \ | |
-- "${SRC}" "${DEST}" | |
( [ $? -eq 0 ] || [ $? -eq 24 ] ) || abort "rsync exited with errors." | |
# Remove existing snapshot with the same date if present | |
if [[ -d "${SNAPSHOT}" ]]; then | |
step "Removing existing snapshot '${SNAPSHOT}'..." | |
btrfs subvolume delete -- "${SNAPSHOT}" \ | |
|| abort "Unable to delete snapshot." | |
fi | |
# Create new snapshot | |
step "Creating snapshot '${SNAPSHOT}'..." | |
btrfs subvolume snapshot -r -- "${DEST}" "${SNAPSHOT}" \ | |
|| abort "Unable to create snapshot." | |
# Unmount device | |
step "Unmounting '${MOUNT_POINT}'..." | |
umount -- "${MOUNT_POINT}" || abort "Unable to unmount device." | |
# Close device | |
step "Closing '${DM_PATH}'..." | |
cryptsetup close -- "${DM_NAME}" || abort "Unable to close device." | |
step "Backup complete." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment