From 22ae5b84e02201e9075cf59b3d9b6fdf4d439d63 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Sun, 7 Jul 2024 22:27:25 -0700 Subject: [PATCH] add btrfs snapshot encrypted backup script --- backup.sh | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100755 backup.sh diff --git a/backup.sh b/backup.sh new file mode 100755 index 0000000..b79984d --- /dev/null +++ b/backup.sh @@ -0,0 +1,79 @@ +#!/bin/bash +set -e -o pipefail +mkdir -p /backups +chmod 750 /backups +chown root:sudo /backups +mkdir -p /snapshots +chmod 700 /snapshots +chown root:root /snapshots +name="" +clone_sources=() +while (( $# > 0 )); do + case "$1" in + -n) + name="$2" + shift + ;; + -c) + clone_sources+=(-c "$2") + shift + ;; + *) + cat <&2 +usage: sudo $0 [-n ] [-c ] +creates a encrypted backup of the btrfs subvolume mounted at '/' and uses all +the '-c' options as clone source snapshots to reduce the size of the +final file. see 'man btrfs-send' for details of how '-c' works. +EOF + exit 1 + ;; + esac + shift +done +if [[ -n "$name" ]]; then + name="-$name" +fi +name="snap-$(date --iso-8601=date -u)$name" +echo "final base name: '$name'" +if [[ "$1" =~ ^'-' ]]; then + cat <<'EOF' >&2 +usage: sudo ./backup.sh [] +creates a encrypted backup of the btrfs subvolume mounted at `/` +EOF + exit 1 +fi +echo "creating btrfs snapshot with name: '$name'" +zst_name="$name.btrfs.zst" +out_name="/backups/$zst_name.gpg" +prompt=0 +if [[ -d /snapshots/"$name" ]]; then + prompt=1 + echo "snapshot already exists: /snapshots/$name" >&2 +fi +if [[ -f "$out_name" ]]; then + prompt=1 + echo "output file already exists: $out_name" >&2 +fi +mapfile -t existing_backups < <(find /backups/ -maxdepth 1 -name 'snap-*.btrfs.zst.gpg' -print) +for existing_backup in "${existing_backups[@]}"; do + if [[ "$existing_backup" != "$out_name" ]]; then + echo "other backup files exist, you should copy them to a remote system and then delete them." >&2 + echo "If you don't delete them, they will be included in this backup, using waay more space than necessary." >&2 + printf "e.g., run: sudo rm %q\n" "$existing_backup" >&2 + exit 1 + fi +done +if ((prompt)); then + if read -r -p "snapshot and/or output file already exists, do you want to overwrite them? [y/n]: " -t 300 REPLY && [[ "$REPLY" =~ ^[yY]$ ]]; then + btrfs subvolume delete /snapshots/"$name" + rm -f "$out_name" + else + echo "exiting" >&2 + exit 1 + fi +fi +btrfs subvolume snapshot -r / /snapshots/"$name" +echo "encrypting and writing to: $out_name" +exec 3<&0 +btrfs send "${clone_sources[@]}" /snapshots/"$name" | zstd --fast -T0 | gpg --symmetric --compress-algo none --set-filename "$zst_name" -o- /dev/fd/4 4<&0- <&3 > "$out_name" +echo "written to: $out_name"