···11+#!/bin/sh
22+# Create a BTRFS snapshot of a subvolume
33+44+# This script is possibly highly specific to my current BTRFS setup and may not
55+# work the way you want it to for your system
66+77+# My current (2021-09-27) BTRFS is as follows:
88+# BTRFS Partition (mounted to /mnt/nvme0n1p2 for easy access to subvolumes)
99+# - gentoo (mounted either to / or /mnt/gentoo)
1010+# - home (mounted to /home)
1111+# - sys-misc (mounted to /mnt/sys-misc)
1212+# - void (mounted either to / or /mnt/void)
1313+1414+# Snapshots will be saved with the name `SUBVOLUMENAME-$(date +%F-%H_$M_%S)`
1515+1616+[ "$BTRSNP_DEVICE" ] || BTRSNP_DEVICE=$(findmnt -nvo SOURCE /)
1717+[ "$BTRSNP_READ" ] || BTRSNP_READ=ro
1818+[ "$BTRSNP_SUBVOL" ] || {
1919+ BTRSNP_SUBVOL=$(findmnt -no SOURCE /)
2020+ BTRSNP_SUBVOL=${BTRSNP_SUBVOL##*/}
2121+ BTRSNP_SUBVOL=${BTRSNP_SUBVOL%]}
2222+}
2323+2424+usage() {
2525+ while read -r line
2626+ do printf '%b\n' "$line"
2727+ done <<-USAGE
2828+ usage: ${0##*/} [OPTIONS]
2929+3030+ options:
3131+ \t-d DEVICE - select which partition the subvolume is on
3232+ \t-h - displays this message
3333+ \t-r [ro|rw] - determine if the snapshot should be readonly
3434+ \t-s SUBVOL - select which subvolume to snapshot
3535+3636+ environment variables:
3737+ \tBTRSNP_DEVICE - selects which partition the subvolume is on
3838+ \t defaults to the root partition
3939+ \tBTRSNP_READ - determine if the snapshot should be readonly
4040+ \t defaults to \`ro\`
4141+ \tBTRSNP_SUBVOL - selects which subvolume to snapshot
4242+ \t defaults to the subvolume mounted at as /
4343+ USAGE
4444+4545+ exit "${1:-1}"
4646+}
4747+4848+msg() {
4949+ case $1 in
5050+ e ) printf '%b\n' "${0##*/}: $*" 1>&2 ;;
5151+ * ) printf '%b\n' "${0##*/}: $*" ;;
5252+ esac
5353+}
5454+5555+while [ "$*" ]
5656+do
5757+ case $1 in
5858+ - ) shift; continue ;;
5959+ -- ) shift; break ;;
6060+ -* ) flag=${1#-}; shift ;;
6161+ * ) shift; continue ;;
6262+ esac
6363+6464+ while [ "$flag" ]
6565+ do
6666+ arg=${flag%"${flag#?}"}
6767+6868+ case $arg in
6969+ d ) BTRSNP_DEVICE="$1"; shift ;;
7070+ h ) usage 0 ;;
7171+ s ) BTRSNP_SUBVOL="$1"; shift ;;
7272+ r )
7373+ [ "$1" ] || BTRSNP_READ="rw" && {
7474+ case $1 in
7575+ ro ) BTRSNP_READ="ro" ;;
7676+ rw ) BTRSNP_READ="rw" ;;
7777+ * ) msg e "$1: invalid option argument for -$arg"; usage 1 ;;
7878+ esac
7979+ shift
8080+ }
8181+ ;;
8282+ * ) msg e "-$arg: invalid argument"; usage 1 ;;
8383+ esac
8484+8585+ flag=${flag#?}
8686+ done
8787+done
8888+8989+# shellcheck disable=SC2015
9090+[ "$BTRSNP_DEVICE" ] && [ "$BTRSNP_SUBVOL" ] || {
9191+ msg e "a device and subvolume are required"
9292+ usage 1
9393+}
9494+9595+# Look for the raw BTRFS mount in /mnt this may be changeable in the future
9696+BTRSNP_DEVICE=${BTRSNP_DEVICE##*/}
9797+if findmnt "/mnt/$BTRSNP_DEVICE" > /dev/null 2>&1
9898+then btrfs_partition_path=/mnt/$BTRSNP_DEVICE
9999+else
100100+ msg e "BTRFS partition is not mounted at /mnt/$BTRSNP_DEVICE"
101101+ exit 1
102102+fi
103103+104104+# If I find a more accurate way to check if a directory is a subvolume I will implement it, but for
105105+# now, just check if it's a directory
106106+if [ -d "$btrfs_partition_path/$BTRSNP_SUBVOL" ]
107107+then btrfs_subvolume_path="$btrfs_partition_path/$BTRSNP_SUBVOL"
108108+else
109109+ msg e "This is not a BTRFS subvolume"
110110+ exit 1
111111+fi
112112+113113+case $BTRSNP_READ in
114114+ ro ) ro="-r" ;;
115115+ rw ) ;;
116116+esac
117117+118118+btrfs subvolume snapshot $ro "$btrfs_subvolume_path" \
119119+ "${btrfs_subvolume_path}-$(date +'%F-%H_%M_%S')"