···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')"