backup-btrfs-vol.sh 2.51 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
#!/usr/bin/env bash
# Take a snapshot of a btrfs subvolume and back up its contents to another location
#
# Copyright 2017-today
#
# Project WEBIS
# Author: Michael Völske
#

# Load libaries and toolkits.
scriptPath=${0%/*}
. "$scriptPath"/../../libs/bashhelper.sh
. "$scriptPath"/../../libs/shflags

check_tools "btrfs rsync xargs"

# Define usage screen.
usage() {
    echo "
Usage:
    $(basename "$0") -v VOLUME -s SNAPSHOT DEST_1 [DEST_2 ... DEST_N]

Description:
    Take a btrfs snapshot of the subvolume located at VOLUME into SNAPSHOT.
    Then, back up the contents of the snapshot directory to each of the
    destinations DEST_1 .. DEST_N via rsync.

    Defaults:
     - SNAPSHOT: VOLUME-BACKUP

Examples:
    $(basename "$0") code-in-progress/code-cluster/code-webis-cmd

"
    exit 0
}

# Define command line arguments and parse them.
DEFINE_string "volume" "" "Path to BTRFS Volume to back up" "v"
DEFINE_string "snapshot" "" "Path to snapshot volume to be created" "s"
export FLAGS_HELP=$(usage)
FLAGS "$@" || exit 0
eval set -- "${FLAGS_ARGV}"


btrfs_snapshot() {
    FROM="$1"
    TO="$2"

    if [ ! -e "$FROM" ]; then
        logError "$FROM does not exist. Aborting."
        exit 1
    fi
    $( btrfs subvolume show "$FROM" >/dev/null 2>&1  ) || {
        logError "$FROM is not a btrfs subvolume or not accessible (permissions?)."
        exit 1
    }
    if [ -e "$TO" ]; then
        logError "$TO already exists. Aborting."
        exit 1
    fi

63 64 65 66
    logInfo "Creating snapshot for $FROM at $TO"
    btrfs subvolume snapshot "$FROM" "$TO"
    date -Is > "$TO/.BACKUP-CREATED"
    btrfs property set -ts "$TO" ro true
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
}

snapshot_delete() {
    btrfs subvolume show "$1" >/dev/null 2>&1 && {
        btrfs subvolume show "$1" | grep -q 'Flags:.*readonly' || {
            logError "$1 is not a read-only subvolume. Aborting."
            exit 1
        }
        btrfs subvolume delete "$1"
    } || {
        logError "$1 is not a btrfs subvolume or not accessible (permissions?)."
    }
}

run_backup() {
    SRC=$1
    shift
84
    printf '%s\0' "${@}" | xargs -0 -n1 -I% -P3 rsync -rt --delete "$SRC/" "%"
85 86 87 88 89 90 91 92 93 94 95 96 97 98
}

main() {
    if [ "" == "$FLAGS_volume" ]; then
        logError "Parameter -v is required."
        exit 1
    fi
    if [ "" == "$FLAGS_snapshot" ]; then
        FLAGS_snapshot=${FLAGS_volume%/}-BACKUP
    fi

    set -e
    btrfs_snapshot "$FLAGS_volume" "$FLAGS_snapshot"

99 100
    cleanup() { snapshot_delete "$FLAGS_snapshot"; }
    trap cleanup EXIT
101

102
    run_backup "$FLAGS_snapshot" $@
103 104 105 106 107
}


# Start program with parameters.
main "$@"