X-Git-Url: https://code.delx.au/monosys/blobdiff_plain/6792f8bcd9f26a4ced41093b227cf1b440dc42ae..02a8d3267739326f16c4ab9d559aa22136ef0102:/bsnap diff --git a/bsnap b/bsnap new file mode 100755 index 0000000..1f36d8e --- /dev/null +++ b/bsnap @@ -0,0 +1,124 @@ +#!/bin/bash + +set -eu + +function snap { + unsnap + + mkdir -p /a + + dispatch snap < /etc/fstab +} + +function unsnap { + 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 +} + +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 + echo "Must be root" + exit 1 +fi + +if [ "${1:-}" = "off" ]; then + unsnap +elif [ "${1:-}" = "on" ]; then + snap +else + echo "Usage: $0 on|off" + exit 1 +fi