#!/bin/sh
# Create a BTRFS snapshot of a subvolume

# This script is possibly highly specific to my current BTRFS setup and may not
# work the way you want it to for your system

# My current (2021-09-27) BTRFS is as follows:
# BTRFS Partition (mounted to /mnt/nvme0n1p2 for easy access to subvolumes)
#   - gentoo      (mounted either to / or /mnt/gentoo)
#   - home        (mounted to /home)
#   - sys-misc    (mounted to /mnt/sys-misc)
#   - void        (mounted either to / or /mnt/void)

# Snapshots will be saved with the name `SUBVOLUMENAME-$(date +%F-%H_$M_%S)`

[ "$BTRSNP_DEVICE" ] || BTRSNP_DEVICE=$(findmnt -nvo SOURCE /)
[ "$BTRSNP_READ" ] || BTRSNP_READ=ro
[ "$BTRSNP_SUBVOL" ] || {
	BTRSNP_SUBVOL=$(findmnt -no SOURCE /)
	BTRSNP_SUBVOL=${BTRSNP_SUBVOL##*/}
	BTRSNP_SUBVOL=${BTRSNP_SUBVOL%]}
}

usage() {
	while read -r line
	do printf '%b\n' "$line"
	done <<-USAGE
		usage: ${0##*/} [OPTIONS]

		options:
		\t-d DEVICE  - select which partition the subvolume is on
		\t-h         - displays this message
		\t-r [ro|rw] - determine if the snapshot should be readonly
		\t-s SUBVOL  - select which subvolume to snapshot

		environment variables:
		\tBTRSNP_DEVICE - selects which partition the subvolume is on
		\t                defaults to the root partition
		\tBTRSNP_READ   - determine if the snapshot should be readonly
		\t                defaults to \`ro\`
		\tBTRSNP_SUBVOL - selects which subvolume to snapshot
		\t                defaults to the subvolume mounted at as /
	USAGE

	exit "${1:-1}"
}

msg() {
	case $1 in
		e ) printf '%b\n' "${0##*/}: $*" 1>&2 ;;
		* ) printf '%b\n' "${0##*/}: $*" ;;
	esac
}

while [ "$*" ]
do
	case $1 in
		-  ) shift; continue ;;
		-- ) shift; break ;;
		-* ) flag=${1#-}; shift ;;
		*  ) shift; continue ;;
	esac

	while [ "$flag" ]
	do
		arg=${flag%"${flag#?}"}

		case $arg in
			d ) BTRSNP_DEVICE="$1"; shift ;;
			h ) usage 0 ;;
			s ) BTRSNP_SUBVOL="$1"; shift ;;
			r )
				[ "$1" ] || BTRSNP_READ="rw" && {
					case $1 in
						ro ) BTRSNP_READ="ro" ;;
						rw ) BTRSNP_READ="rw" ;;
						*  ) msg e "$1: invalid option argument for -$arg"; usage 1 ;;
					esac
					shift
				}
			;;
			* ) msg e "-$arg: invalid argument"; usage 1 ;;
		esac

		flag=${flag#?}
	done
done

# shellcheck disable=SC2015
[ "$BTRSNP_DEVICE" ] && [ "$BTRSNP_SUBVOL" ] || {
	msg e "a device and subvolume are required"
	usage 1
}

# Look for the raw BTRFS mount in /mnt this may be changeable in the future
BTRSNP_DEVICE=${BTRSNP_DEVICE##*/}
if findmnt "/mnt/$BTRSNP_DEVICE" > /dev/null 2>&1
then btrfs_partition_path=/mnt/$BTRSNP_DEVICE
else
	msg e "BTRFS partition is not mounted at /mnt/$BTRSNP_DEVICE"
	exit 1
fi

# If I find a more accurate way to check if a directory is a subvolume I will implement it, but for
# now, just check if it's a directory
if [ -d "$btrfs_partition_path/$BTRSNP_SUBVOL" ]
then btrfs_subvolume_path="$btrfs_partition_path/$BTRSNP_SUBVOL"
else
	msg e "This is not a BTRFS subvolume"
	exit 1
fi

case $BTRSNP_READ in
	ro ) ro="-r" ;;
	rw ) ;;
esac

btrfs subvolume snapshot $ro "$btrfs_subvolume_path" \
                             "${btrfs_subvolume_path}-$(date +'%F-%H_%M_%S')"
