diff --git a/scritps/btrsnp b/scritps/btrsnp new file mode 100755 index 0000000..55b27b6 --- /dev/null +++ b/scritps/btrsnp @@ -0,0 +1,119 @@ +#!/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')"