]> arthur.barton.de Git - ax-linux.git/blob - btrfs/mksnapshot/btrfs-mksnapshot
3386b471e423ceb17789e2cd8238b901f2c4368e
[ax-linux.git] / btrfs / mksnapshot / btrfs-mksnapshot
1 #!/bin/bash
2 #
3 # btrfs-mksnapshot -- Make snapshots of btrfs filesystems
4 # Copyright (c)2013-2014 Alexander Barton (alex@barton.de)
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11
12 NAME=`basename "$0"`
13
14 function Usage()
15 {
16         echo "Usage: $NAME [-1] [<path>]"; echo
17         echo " -1      Create only one shapshot per day."
18         echo " -n      Dry run, perform a trial run with no changes made."
19         echo " <path>  Volume root path (default: \"/\")."
20         echo; exit 1
21 }
22
23 ONLY_ONE_PER_DAY=
24 DRY_RUN=
25
26 while [ $# -ge 1 ]; do
27         case "$1" in
28           [^\-]*)
29                 break
30                 ;;
31           -1)
32                 ONLY_ONE_PER_DAY=1
33                 ;;
34           -n)
35                 DRY_RUN=1
36                 ;;
37           *)
38                 Usage
39         esac
40         shift
41 done
42 [ $# -gt 1 ] && Usage
43
44 [ -z "$DRY_RUN" ] || echo "ONLY_ONE_PER_DAY=$ONLY_ONE_PER_DAY"
45
46 # The subvolume to snapshot, "/" by default
47 [ $# -ge 1 ] && VOLUME_PATH="$1" || VOLUME_PATH="/"
48
49 [ -z "$DRY_RUN" ] || echo "VOLUME_PATH=$VOLUME_PATH"
50
51 # Detect btrfs filesystem
52 FS_NAME=`btrfs fi sh -m / 2>/dev/null | head -1 | cut -d"'" -f2`
53 if [ -z "$FS_NAME" ]; then
54         FS_NAME=`grep " btrfs " /etc/fstab \
55                 | grep "^LABEL=" \
56                 | grep " $VOLUME_PATH " \
57                 | cut -d'"' -f2 \
58                 | cut -d'=' -f2- \
59                 | cut -d' ' -f1`
60 fi
61 if [ -z "$FS_NAME" ]; then
62         echo "$NAME: Failed to detect btrfs filesystem label for \"$VOLUME_PATH\"!"
63         exit 1
64 fi
65
66 [ -z "$DRY_RUN" ] || echo "FS_NAME=$FS_NAME"
67
68 # Detect btrfs subvolume name
69 VOLUME_NAME=`grep " btrfs " /etc/fstab \
70         | grep "subvol=" \
71         | grep " $VOLUME_PATH " \
72         | sed -r 's|.*subvol=([[:alnum:]]*).*|\1|'`
73 if [ -z "$VOLUME_NAME" -a "$VOLUME_PATH" = "/" ]; then
74         VOLUME_NAME=`btrfs subvolume get-default / | cut -d' ' -f9`
75 fi
76 if [ -z "$VOLUME_NAME" ]; then
77         echo "$NAME: Failed to detect btrfs subvolume name for \"$VOLUME_PATH\"!"
78         exit 1
79 fi
80 BASE_VOLUME_NAME=`echo "$VOLUME_NAME" | cut -d'@' -f1`
81
82 if [ -n "$DRY_RUN" ]; then
83         echo "VOLUME_NAME=$VOLUME_NAME"
84         echo "BASE_VOLUME_NAME=$BASE_VOLUME_NAME"
85 fi
86
87 # Detect mount point of the whole btrfs filesystem
88 FS_MOUNT_PATH="/media/$FS_NAME"
89 if [ ! -d "$FS_MOUNT_PATH" ]; then
90         echo "$NAME: Directory \"$FS_MOUNT_PATH\" does not exist!"
91         exit 1
92 fi
93 grep " btrfs " /proc/mounts | grep " $FS_MOUNT_PATH " >/dev/null 2>&1
94 if [ $? -ne 0 ]; then
95         echo "$NAME: btrfs \"$FS_NAME\" seems not to be mounted on \"$FS_MOUNT_PATH\"!"
96         exit 1
97 fi
98
99 [ -z "$DRY_RUN" ] || echo "FS_MOUNT_PATH=$FS_MOUNT_PATH"
100
101 # Generate snapshot name
102 i=1
103 date=`date +%Y%m%d`
104 while true; do
105         id="$date-$i"
106         [ -e "$FS_MOUNT_PATH/$BASE_VOLUME_NAME@$id" ] || break
107         if [ -n "$ONLY_ONE_PER_DAY" ]; then
108                 echo "Snapshot \"$BASE_VOLUME_NAME@$id\" of \"$VOLUME_PATH\" (\"$VOLUME_NAME\") in btrfs \"$FS_NAME\" already exists."
109                 exit 0
110         fi
111         i=`expr $i + 1`
112 done
113 NEW_VOLUME_NAME="$BASE_VOLUME_NAME@$id"
114
115 [ -z "$DRY_RUN" ] || echo "NEW_VOLUME_NAME=$NEW_VOLUME_NAME"
116
117 [ -z "$DRY_RUN" ] || exit 0
118
119 echo "Creating snapshot of \"$VOLUME_PATH\" (\"$VOLUME_NAME\") in btrfs \"$FS_NAME\" ..."
120 set -x
121
122 cd "$FS_MOUNT_PATH"
123 btrfs subvolume snapshot "$VOLUME_NAME" "$NEW_VOLUME_NAME"
124 find . -maxdepth 1 \( -name "$BASE_VOLUME_NAME" -o \
125  -name "$BASE_VOLUME_NAME"@'*' \) -exec ls -1d {} \; | sort | column