mkdir -p /a
- cat /etc/fstab | awk '{print $5 " " $1 " " $2;}' | while read -r dump dev mnt; do
- if [ "$dump" = 1 ]; then
- echo "bind mount $mnt"
- mount --bind "${mnt}" "/a${mnt}"
- elif [ "$dump" = 2 ]; then
- read -r lvname vgname _ < <(lvdisplay --noheadings -C "$dev")
- echo "snapshot ${vgname}/${lvname}"
- lvcreate -L1G --snapshot --name "${lvname}snap" "${vgname}/${lvname}"
- mount -o ro "${dev}snap" "/a${mnt}"
- fi
- done
+ dispatch snap < /etc/fstab
}
function unsnap {
- tac /etc/fstab | awk '{print $5 " " $1 " " $2;}' | while read -r dump dev mnt; do
- snapmnt="/a${mnt}"
- snapdev="${dev}snap"
- if [ "$dump" = 1 ]; then
- echo "umount $snapmnt"
- mountpoint -q "$snapmnt" && umount "$snapmnt"
- elif [ "$dump" = 2 ]; then
- echo "umount $snapmnt"
- mountpoint -q "$snapmnt" && umount "$snapmnt"
-
- echo "unsnapshot $snapdev"
- [ -b "$(readlink -f "$snapdev")" ] && echo y | lvremove "${dev}snap"
+ tac /etc/fstab | dispatch unsnap
+
+ if [ -d "/a" ]; then
+ rmdir /a
+ fi
+}
+
+function dispatch {
+ local action="" snaptype=""
+ local dev="" mnt="" fstype="" opts="" dump=""
+
+ while read -r dev mnt fstype opts dump pass; do
+ snaptype="$(get_snaptype "$fstype" "$dump")"
+ if [ -z "$snaptype" ]; then
+ continue
fi
+ action="${1}_${snaptype}"
+ echo "$action $mnt"
+ "$action" "$dev" "$mnt" "$opts"
done
+}
+
+function get_snaptype {
+ local fstype="$1" dump="$2"
+ if [ "$dump" = "1" ]; then
+ echo bind
+ elif [ "$dump" = "2" ] && [ "$fstype" = "btrfs" ]; then
+ echo btrfs
+ elif [ "$dump" = "2" ]; then
+ echo lvm
+ fi
+}
+
+function snap_bind {
+ local mnt="$2"
+ mount --bind "${mnt}" "/a${mnt}"
+}
+
+function unsnap_bind {
+ local snapmnt="/a$2"
+ if mountpoint -q "$snapmnt"; then
+ umount "$snapmnt"
+ fi
+}
+
+function snap_lvm {
+ local dev="$1" mnt="$2"
+ local lvname="" vgname=""
+ read -r lvname vgname _ < <(lvdisplay --noheadings -C "$dev")
+ echo "snapshot ${vgname}/${lvname}"
+ lvcreate -L1G --snapshot --name "${lvname}snap" "${vgname}/${lvname}"
+ mount -o ro "${dev}snap" "/a${mnt}"
+}
+
+function unsnap_lvm {
+ local snapdev="${1}snap"
+ local snapmnt="/a$2"
+ if mountpoint -q "$snapmnt"; then
+ umount "$snapmnt"
+ fi
+ if [ -b "$(readlink -f "$snapdev")" ]; then
+ lvremove -f "${dev}snap"
+ fi
+}
+
+function snap_btrfs {
+ local mnt="$2" opts="$3" snapdir=""
+
+ snapdir="$(get_btrfs_snapshot_dir "$opts" "$mnt")"
+ btrfs subvolume snapshot "$mnt" "$snapdir"
+
+ mount --bind "$snapdir" "/a${mnt}"
+}
+
+function unsnap_btrfs {
+ local mnt="$2" opts="$3" snapdir=""
+
+ local snapmnt="/a$2"
+ if mountpoint -q "$snapmnt"; then
+ umount "$snapmnt"
+ fi
+
+ snapdir="$(get_btrfs_snapshot_dir "$opts" "$mnt")"
+ if [ -d "$snapdir" ]; then
+ btrfs subvolume delete "$snapdir"
+ fi
+}
- rmdir /a || true
+function get_btrfs_snapshot_dir {
+ local opts="$1" mnt="$2" subvol=""
+ subvol="$(echo "$opts" | sed -nE 's/^.*\bsubvol=([^,]+)\b.*$/\1/p')"
+ if [ -z "$subvol" ]; then
+ echo "Unknown subvol for mountpoint: $mnt"
+ exit 1
+ fi
+ echo "/$(hostname -s)/${subvol}-snap"
}
if [ "$(id -u)" -ne 0 ]; then