3 # btrfs-mksnapshot -- Make snapshots of btrfs filesystems
4 # Copyright (c)2013-2020 Alexander Barton (alex@barton.de)
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.
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: \"/\")."
26 while [ $# -ge 1 ]; do
44 [ -z "$DRY_RUN" ] || echo "ONLY_ONE_PER_DAY=$ONLY_ONE_PER_DAY"
46 # The subvolume to snapshot, "/" by default
47 [ $# -ge 1 ] && VOLUME_PATH="$1" || VOLUME_PATH="/"
49 [ -z "$DRY_RUN" ] || echo "VOLUME_PATH=$VOLUME_PATH"
51 # Detect btrfs filesystem
52 FS_NAME=$(btrfs filesystem show -m / 2>/dev/null | head -1 | cut -d"'" -f2)
53 if [ -z "$FS_NAME" ]; then
54 FS_NAME=$(grep " btrfs " /etc/fstab \
56 | grep " $VOLUME_PATH " \
61 if [ -z "$FS_NAME" ]; then
62 echo "$NAME: Failed to detect btrfs filesystem label for \"$VOLUME_PATH\"!"
66 [ -z "$DRY_RUN" ] || echo "FS_NAME=$FS_NAME"
68 # Detect btrfs subvolume name
69 VOLUME_NAME=$(grep " btrfs " /etc/fstab \
71 | grep " $VOLUME_PATH " \
72 | sed -r 's|.*subvol=([^, \t]*).*|\1|')
73 if [ -z "$VOLUME_NAME" ] && [ "$VOLUME_PATH" = "/" ]; then
74 VOLUME_NAME=$(btrfs subvolume get-default / | cut -d' ' -f9)
76 if [ -z "$VOLUME_NAME" ]; then
77 echo "$NAME: Failed to detect btrfs subvolume name for \"$VOLUME_PATH\"!"
80 BASE_VOLUME_NAME=$(echo "$VOLUME_NAME" | cut -d'@' -f1)
82 if [ -n "$DRY_RUN" ]; then
83 echo "VOLUME_NAME=$VOLUME_NAME"
84 echo "BASE_VOLUME_NAME=$BASE_VOLUME_NAME"
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!"
93 if grep " btrfs " /proc/mounts | grep " $FS_MOUNT_PATH " >/dev/null 2>&1; then
94 echo "$NAME: btrfs \"$FS_NAME\" seems not to be mounted on \"$FS_MOUNT_PATH\"!"
98 [ -z "$DRY_RUN" ] || echo "FS_MOUNT_PATH=$FS_MOUNT_PATH"
100 # Generate snapshot name
105 [ -e "$FS_MOUNT_PATH/$BASE_VOLUME_NAME@$id" ] || break
106 if [ -n "$ONLY_ONE_PER_DAY" ]; then
107 echo "Snapshot \"$BASE_VOLUME_NAME@$id\" of \"$VOLUME_PATH\" (\"$VOLUME_NAME\") in btrfs \"$FS_NAME\" already exists."
112 NEW_VOLUME_NAME="$BASE_VOLUME_NAME@$id"
114 [ -z "$DRY_RUN" ] || echo "NEW_VOLUME_NAME=$NEW_VOLUME_NAME"
116 [ -z "$DRY_RUN" ] || exit 0
118 echo "Creating snapshot of \"$VOLUME_PATH\" (\"$VOLUME_NAME\") in btrfs \"$FS_NAME\" ..."
121 cd "$FS_MOUNT_PATH" || exit 1
122 btrfs subvolume snapshot -r "$VOLUME_NAME" "$NEW_VOLUME_NAME"
123 find . -maxdepth 1 \( -name "$BASE_VOLUME_NAME" -o \
124 -name "$BASE_VOLUME_NAME"@'*' \) -exec ls -1d {} \; | sort | column