#!/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