View difference between Paste ID: YfZUnytT and Rz49ANTU
SHOW: | | - or go back to the newest paste.
1
#!/bin/sh
2
3-
# btrfs-snapshots.sh
3+
# btrfs-snapshots.sh 1.0
4-
# Erzeuge hourly, daily, weekly, and monthly Snapshots der btrfs Dateisysteme
4+
# Create hourly, daily, weekly, and monthly snapshots of btrfs filesystems
5
6-
# Basiert auf http://article.gmane.org/gmane.comp.file-systems.btrfs/12609
6+
# See https://copy.com/WI9AXqTH2nD4 or as a "subversion" of http://pastebin.com/Rz49ANTU
7
8-
# 0 * * * * /usr/local/bin/snapshot hourly 6
8+
# Based somewhat on http://article.gmane.org/gmane.comp.file-systems.btrfs/12609
9-
# 0 0 * * * /usr/local/bin/snapshot daily 7
9+
10-
# 0 0 * * 0 /usr/local/bin/snapshot weekly 4
10+
# 00,15,30,45  * * * *  /usr/local/bin/btrfs-snapshots.sh frequently  4
11
# 38           * * * *  /usr/local/bin/btrfs-snapshots.sh hourly     24
12
# 08          00 * * *  /usr/local/bin/btrfs-snapshots.sh daily       7
13-
    echo "Usage: $0 SNAPSHOT_PREFIX NUM_SNAPSHOTS"
13+
# 08          12 * * 0  /usr/local/bin/btrfs-snapshots.sh weekly      4
14
15
if [ "$#" -ne 2 ]; then
16
    echo "Usage: $0 SNAPSHOT_TAG NUM_SNAPSHOTS
17-
SNAPSHOT_PREFIX="$1"
17+
Create hourly, daily, weekly, and monthly snapshots of btrfs filesystems.
18
19
Based somewhat on http://article.gmane.org/gmane.comp.file-systems.btrfs/12609
20-
#a@ewzw032:~$ sudo btrfs subv snaps -r /.backup /.backup/.blub ; sudo btrfs subv snaps -r /.backup/Syno /.backup/Syno/.blub
20+
Here's my crontab:
21
00,15,30,45  * * * *  $0 frequently  4
22-
snap_prefix=".snapshot:$SNAPSHOT_PREFIX:"
22+
38           * * * *  $0 hourly     24
23-
snap_name="$snap_prefix`date +%Y-%m-%d--%H.%M.%S.%N`"
23+
08          00 * * *  $0 daily       7
24
08          12 * * 0  $0 weekly      4"
25-
# Finde alle btrfs
25+
26-
df -T | grep ' btrfs ' | perl -p -e 's,^(.*?) .* (/.*)$,$1 $2,' | while read dev mp; do
26+
27-
    # Find alle subvolumes dieses btrfs
27+
28-
    # z.B.: ID 268 gen 3176 top level 5 path foo/bar
28+
# "Tag" to use for snapshots
29-
    # Zeige alle subvolumes und zusätzliche alle "readonly" (snapshot)
29+
SNAPSHOT_TAG="$1"
30-
    # Volumes. Filtere dann das raus, was doppelt angezeigt wurde; das
30+
# How many of those snapshots to keep
31-
    # sind die snapshots. Dadurch werden nur die "richtigen" Volumes
31+
32-
    # angezeigt.
32+
33-
    ( btrfs subv list -r "$mp" ; btrfs subv list "$mp" ) | sort | uniq -u | while read id Id gen Gen top level Toplevel path Path; do
33+
# Helper veriables
34-
        # Erzeuge den Snapshot
34+
# A "prefix" for all the snapshots
35-
        #echo "`date +%Y-%m-%d--%H.%M.%S.%N`: Erzeuge Snapshot $mp/$Path/$snap_name fuer $mp/$Path"
35+
snap_prefix="snapshot:$SNAPSHOT_TAG:"
36-
        set -x; btrfs subv snapshot -r "$mp/$Path" "$mp/$Path/$snap_name"; set +x
36+
# "Now"
37
snap_date="`date +%Y-%m-%d--%H.%M.%S.%N`"
38
# Name of the script
39-
    # Lösche alte Snapshot(s)
39+
script_name=`basename "$0"`
40-
    # Zeige alle read only Subvolumes an. Und zusätzlich "doppelt" die letzten
40+
41-
    # $NUM_SNAPSHOTS Snapshots. Führt dazu, das die gewünchte Anzahl an zu 
41+
# Messages are logged to syslog
42-
    # behaltenden Snapshots doppelt angezeigt wird.
42+
# facility: auth, authpriv (for security information of a sensitive nature), cron, daemon, ftp, kern (can't be generated from user process), lpr, mail, news, security (deprecated synonym for auth), syslog, user, uucp, and local0 to local7
43-
    # Nun sortiere die Liste und zeige nur die an, die nur 1x vorkommen.
43+
log_fac="local5"
44-
    # Das sind die Snapshots, die gelöscht werden sollen.
44+
# tag
45-
    # ID 257 gen 28590 top level 256 path a
45+
log_tag="$script_name"
46-
    # a@ewzw032:~$ ( sudo btrfs subv list -r /.backup/ | grep ' \.boing:' | tail -$n ; sudo btrfs subv list -r /.backup/ | grep ' \.boing:' ) | sort | uniq -u
46+
47
# Add path to btrfs-progs dev version to beginning of $PATH
48-
    ( btrfs subv list -r "$mp" | grep " path $snap_prefix" | tail -"$n"; sudo btrfs subv list -r "$mp" | grep " path $snap_prefix" ) | sort | uniq -u | while read id Id gen Gen top level Toplevel path Path; do
48+
# Needs a post 2013-02-01 15:55:06 (commit 64edc851da59c47b92ee6830101be0854add7f09)
49-
        #echo "`date +%Y-%m-%d--%H.%M.%S.%N`: Entferne Snapshot $mp/$Path/$snap_name fuer $mp/$Path"
49+
# version of btrfs-progs from http://git.kernel.org/cgit/linux/kernel/git/mason/btrfs-progs.git/commit/
50-
        set -x; btrfs subv delete "$mp/$Path"; set +x
50+
# because of issues with "btrfs subv list"
51
btrfs_progs_dev_path="/home/a/Copy/Computerkram/Programme/btrfs-progs.dev/bin"
52
PATH="$btrfs_progs_dev_path:$PATH"
53-
    echo
53+
54
# Find all btrfs filesystems
55
btrfs fi show 2>/dev/null | awk '/ path / {print $NF}' | while read dev; do
56
    # Find uuid and label
57
    set -- `sudo btrfs fi show 2>/dev/null | grep -B2 " path $dev" | grep "Label:" | sed  's,.*: \(.*\)  uuid: \(.*\),\1 \2,'`
58
    label="$1"
59
    uuid="$2"
60
    logger -t "$log_tag" -p "$log_fac.info" -- "Processing filesystem with label $label and uuid $uuid on $dev"
61
    # Change the "dev" name ("path") so, that it is usable; ie. / -> .
62
    safe_dev=`echo "$dev" | tr / .`
63
    # Create a directory for the temporary mountpoint
64
    tmp_mount_dir=`mktemp -d "/tmp/.btrfs.mount.$uuid.$safe_dev.XXXXXX"`
65
    # Mount the current btrfs there
66
    if ! mount -t btrfs "$dev" "$tmp_mount_dir"; then
67
        logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: mount -t btrfs $dev $tmp_mount_dir"
68
        exit 1
69
    fi
70
    
71
    # Create snapshots for the "root" volume
72
    if ! btrfs subv snaps -r "$tmp_mount_dir" "$tmp_mount_dir/,$snap_prefix$snap_date" > /dev/null; then
73
        logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: btrfs subv snaps -r $tmp_mount_dir $tmp_mount_dir/,$snap_prefix$snap_date"
74
        exit 1
75
    else
76
        logger -t "$log_tag" -p "$log_fac.info" -- "Created snapshot $Path,$snap_prefix$snap_date for root volume of fs with uuid $uuid"
77
    fi
78
    # Find old, no longer wanted snapshots with the "tag" of this subvolume
79
    # - list all (read only + writable) snapshots of this filesystem
80
    # - list only those for current "path" (-> subvolume) and prefix
81
    # - list only the last $NUM_SNAPSHOTS snapshots -> those are to "survive"
82
    # - again list all snapshots of current path
83
    # - sort and list only only those, which are shown just once
84
    # - -> a list of those snapshots, which are to go
85
    (btrfs subv list -r "$tmp_mount_dir" | grep " path ,$snap_prefix" | tail -"$NUM_SNAPSHOTS"; btrfs subv list -r "$tmp_mount_dir" | grep " path ,$snap_prefix") | sort | uniq -u | while read __id IdDel __gen GenDel __top __level ToplevelDel __path PathDel; do
86
        # Delete the snapshot
87
        if ! btrfs subv del "$tmp_mount_dir/$PathDel" > /dev/null; then
88
            logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: btrfs subv del $tmp_mount_dir/$PathDel"
89
            exit 1
90
        else
91
            logger -t "$log_tag" -p "$log_fac.info" -- "Removed snapshot $PathDel"
92
        fi
93
    done
94
    
95
    # List all non read-only (ie. writable) subvolumes
96
    # - create a list of ALL subvolumes (read only + writable)
97
    # - create a list of writable subvolumes
98
    # - sort those two lists
99
    # - list only those, which are show just once; ie. the read only subvolumes
100
    (btrfs subv list -ar $tmp_mount_dir; btrfs subv list -a $tmp_mount_dir) | sort | uniq -u | while read _id Id _gen Gen _top _level Toplevel _path Path; do
101
        # Create the snapshot
102
        if ! btrfs subv snaps -r "$tmp_mount_dir/$Path" "$tmp_mount_dir/$Path,$snap_prefix$snap_date" > /dev/null; then
103
            logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: btrfs subv snaps -r $tmp_mount_dir/$Path $tmp_mount_dir/$Path,$snap_prefix$snap_date"
104
            exit 1
105
        else
106
            logger -t "$log_tag" -p "$log_fac.info" -- "Created snapshot $Path,$snap_prefix$snap_date for subvolume $Path"
107
        fi
108
        # Find old, no longer wanted snapshots with the "tag" of this subvolume
109
        # - list all (read only + writable) snapshots of this filesystem
110
        # - list only those for current "path" (-> subvolume) and prefix
111
        # - list only the last $NUM_SNAPSHOTS snapshots -> those are to "survive"
112
        # - again list all snapshots of current path
113
        # - sort and list only only those, which are shown just once
114
        # - -> a list of those snapshots, which are to go
115
        (btrfs subv list -r "$tmp_mount_dir" | grep " path $Path,$snap_prefix" | tail -"$NUM_SNAPSHOTS"; btrfs subv list -r "$tmp_mount_dir" | grep " path $Path,$snap_prefix") | sort | uniq -u | while read __id IdDel __gen GenDel __top __level ToplevelDel __path PathDel; do
116
            # Delete the snapshot
117
            if ! btrfs subv del "$tmp_mount_dir/$PathDel" > /dev/null; then
118
                logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: btrfs subv del $tmp_mount_dir/$PathDel"
119
                exit 1
120
            else
121
                logger -t "$log_tag" -p "$log_fac.info" -- "Removed snapshot $PathDel"
122
            fi
123
        done
124
    done
125
    # Unmount the filesystem
126
    if ! umount "$tmp_mount_dir"; then
127
        logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: umount$tmp_mount_dir"
128
        # Not fatal
129
        # exit 1
130
    fi
131
    # Remove the directory where the filesystem was mounted
132
    if ! rmdir "$tmp_mount_dir"; then
133
        logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: rmdir $tmp_mount_dir"
134
        # Not fatal
135
        # exit 1
136
    fi
137
done
138
139
# Done ☺
140
exit 0
141
# EOF