A collection of scripts
1#!/bin/sh
2# Create a BTRFS snapshot of a subvolume
3
4# This script is possibly highly specific to my current BTRFS setup and may not
5# work the way you want it to for your system
6
7# My current (2021-09-27) BTRFS is as follows:
8# BTRFS Partition (mounted to /mnt/nvme0n1p2 for easy access to subvolumes)
9# - gentoo (mounted either to / or /mnt/gentoo)
10# - home (mounted to /home)
11# - sys-misc (mounted to /mnt/sys-misc)
12# - void (mounted either to / or /mnt/void)
13
14# Snapshots will be saved with the name `SUBVOLUMENAME-$(date +%F-%H_$M_%S)`
15
16[ "$BTRSNP_DEVICE" ] || BTRSNP_DEVICE=$(findmnt -nvo SOURCE /)
17[ "$BTRSNP_READ" ] || BTRSNP_READ=ro
18[ "$BTRSNP_SUBVOL" ] || {
19 BTRSNP_SUBVOL=$(findmnt -no SOURCE /)
20 BTRSNP_SUBVOL=${BTRSNP_SUBVOL##*/}
21 BTRSNP_SUBVOL=${BTRSNP_SUBVOL%]}
22}
23
24usage() {
25 while read -r line
26 do printf '%b\n' "$line"
27 done <<-USAGE
28 usage: ${0##*/} [OPTIONS]
29
30 options:
31 \t-d DEVICE - select which partition the subvolume is on
32 \t-h - displays this message
33 \t-r [ro|rw] - determine if the snapshot should be readonly
34 \t-s SUBVOL - select which subvolume to snapshot
35
36 environment variables:
37 \tBTRSNP_DEVICE - selects which partition the subvolume is on
38 \t defaults to the root partition
39 \tBTRSNP_READ - determine if the snapshot should be readonly
40 \t defaults to \`ro\`
41 \tBTRSNP_SUBVOL - selects which subvolume to snapshot
42 \t defaults to the subvolume mounted at as /
43 USAGE
44
45 exit "${1:-1}"
46}
47
48msg() {
49 case $1 in
50 e ) printf '%b\n' "${0##*/}: $*" 1>&2 ;;
51 * ) printf '%b\n' "${0##*/}: $*" ;;
52 esac
53}
54
55while [ "$*" ]
56do
57 case $1 in
58 - ) shift; continue ;;
59 -- ) shift; break ;;
60 -* ) flag=${1#-}; shift ;;
61 * ) shift; continue ;;
62 esac
63
64 while [ "$flag" ]
65 do
66 arg=${flag%"${flag#?}"}
67
68 case $arg in
69 d ) BTRSNP_DEVICE="$1"; shift ;;
70 h ) usage 0 ;;
71 s ) BTRSNP_SUBVOL="$1"; shift ;;
72 r )
73 [ "$1" ] || BTRSNP_READ="rw" && {
74 case $1 in
75 ro ) BTRSNP_READ="ro" ;;
76 rw ) BTRSNP_READ="rw" ;;
77 * ) msg e "$1: invalid option argument for -$arg"; usage 1 ;;
78 esac
79 shift
80 }
81 ;;
82 * ) msg e "-$arg: invalid argument"; usage 1 ;;
83 esac
84
85 flag=${flag#?}
86 done
87done
88
89# shellcheck disable=SC2015
90[ "$BTRSNP_DEVICE" ] && [ "$BTRSNP_SUBVOL" ] || {
91 msg e "a device and subvolume are required"
92 usage 1
93}
94
95# Look for the raw BTRFS mount in /mnt this may be changeable in the future
96BTRSNP_DEVICE=${BTRSNP_DEVICE##*/}
97if findmnt "/mnt/$BTRSNP_DEVICE" > /dev/null 2>&1
98then btrfs_partition_path=/mnt/$BTRSNP_DEVICE
99else
100 msg e "BTRFS partition is not mounted at /mnt/$BTRSNP_DEVICE"
101 exit 1
102fi
103
104# If I find a more accurate way to check if a directory is a subvolume I will implement it, but for
105# now, just check if it's a directory
106if [ -d "$btrfs_partition_path/$BTRSNP_SUBVOL" ]
107then btrfs_subvolume_path="$btrfs_partition_path/$BTRSNP_SUBVOL"
108else
109 msg e "This is not a BTRFS subvolume"
110 exit 1
111fi
112
113case $BTRSNP_READ in
114 ro ) ro="-r" ;;
115 rw ) ;;
116esac
117
118btrfs subvolume snapshot $ro "$btrfs_subvolume_path" \
119 "${btrfs_subvolume_path}-$(date +'%F-%H_%M_%S')"