Implemented automatic toplevel mounting

snapsh now checks if the toplevel subvolume is mounted at the path
defined in TOPLEVEL, and if not, does it automatically.
This commit is contained in:
Jarno Rankinen 2021-01-05 00:39:13 +02:00
parent d003820acb
commit a13cba3790
1 changed files with 104 additions and 51 deletions

99
snapsh
View File

@ -42,27 +42,40 @@ snapsh [OPTIONS]
Options: Options:
-h, --help Display this help message -h, --help Display this help message
-s SUBVOL, --snapshot SUBVOL Take a snapshot of subvolume named SUBVOL. -s SUBVOL, --snapshot SUBVOL Take a snapshot of subvolume named SUBVOL.
-d STR, --description STR Add a description for the snapshot displayed in the -d STR, --description STR Add a description for the snapshot displayed
snapshots listing. in the snapshots listing.
-t TYPE, --type TYPE Set the type of snapshot, where TYPE=manual|auto|boot|backup -t TYPE, --type TYPE Set the type of snapshot, where
Can be used with -l, --list to filter results TYPE=manual|auto|boot|backup
Can be used with --list to filter results
-l, --list List snapshots -l, --list List snapshots
-r NUMBER, --remove NUMBER Remove snapshot NUMBER. See snapshot numbers with -r NUMBER, --remove NUMBER Remove snapshot NUMBER. See snapshot numbers
snapsh -l with snapsh -l
--rollback NUMBER Roll back to snapshot NUMBER. See snapshot numbers --rollback NUMBER Roll back to snapshot NUMBER. See snapshot
with snapsh -l. Target subvolume is detected from numbers with snapsh -l. Target subvolume is
snapshot automatically.\n" detected from snapshot automatically.\n"
} }
mount_check() {
# Check that the toplevel subvolume (id=5) is mounted, and if not,
# mount it to path defined in $TOPLEVEL
snapshot() { mount | grep subvolid=5 | grep "${TOPLEVEL}" > /dev/null
if [[ "$?" -ne 0 ]]; then
# Get the UUID of the current btrfs volume
MOUNT_UUID=$(btrfs filesystem show | grep uuid | cut -d ':' -f 3)
# Create the mountpoint for the toplevel if needed
[[ -d ${TOPLEVEL} ]] || mkdir -p ${TOPLEVEL}
# Mount the toplevel
mount -U ${MOUNT_UUID} -o subvolid=5 ${TOPLEVEL}
fi
EXIT_CODE=0 if [[ -n ${SNAPSHOT} ]]; then
root_check #Check that script is run with root privileges. # If taking a snapshot,
# check that the subvolume storing snapshots exists and if not, ask
# Check that the subvolume storing snapshots exists # to create it.
if [[ ! -d ${SNAPSHOTS_LOCATION} ]]; then ${BTRFS_EXECUTABLE} subvolume show ${SNAPSHOTS_LOCATION} > /dev/null
if [[ "$?" -ne 0 ]]; then
printf "Subvolume ${SNAPSHOTS_LOCATION} does not exist. Create it now?\n" printf "Subvolume ${SNAPSHOTS_LOCATION} does not exist. Create it now?\n"
read -n 1 -p "y/n: " read -n 1 -p "y/n: "
@ -71,15 +84,38 @@ snapshot() {
${BTRFS_EXECUTABLE} subvolume create ${SNAPSHOTS_LOCATION} ${BTRFS_EXECUTABLE} subvolume create ${SNAPSHOTS_LOCATION}
unset ${REPLY} unset ${REPLY}
else else
EXIT_CODE=1 exit 1
fi
fi fi
else else
# Otherwise, just check that the subvolume in SNAPSHOTS_LOCATION
# exists, and notify if not.
${BTRFS_EXECUTABLE} subvolume show ${SNAPSHOTS_LOCATION} > /dev/null
if [[ "$?" -ne 0 ]]; then
printf "Subvolume ${SNAPSHOTS_LOCATION} does not exist.\n"
exit 1
fi
fi
}
snapshot() {
EXIT_CODE=0
root_check #Check that script is run with root privileges.
mount_check #Check that the toplevel subvolume is mounted
# TYPE defaults to manual # TYPE defaults to manual
if [[ -z "${SET_TYPE}" ]]; then if [[ -z "${SET_TYPE}" ]]; then
SET_TYPE="manual" SET_TYPE="manual"
fi fi
printf "Creating snapshot of subvolume ${SUBVOLUME} as ${SUBVOLUME}_snapshot_${TIMESTAMP}\n" printf "Creating snapshot of subvolume ${SUBVOLUME} as \
${SUBVOLUME}_snapshot_${TIMESTAMP}\n"
# Create info file for listing snapshots # Create info file for listing snapshots
# Created first on the source subvolume, then deleted from the source # Created first on the source subvolume, then deleted from the source
@ -89,7 +125,10 @@ snapshot() {
TYPE=\"${SET_TYPE}\"\n" > ${TOPLEVEL}/${SUBVOLUME}/.snapsh TYPE=\"${SET_TYPE}\"\n" > ${TOPLEVEL}/${SUBVOLUME}/.snapsh
# Create readonly subvolume # Create readonly subvolume
${BTRFS_EXECUTABLE} subvolume snapshot -r ${TOPLEVEL}/${SUBVOLUME} ${SNAPSHOTS_LOCATION}/${SUBVOLUME}_snapshot_${TIMESTAMP} ${BTRFS_EXECUTABLE} subvolume snapshot -r ${TOPLEVEL}/${SUBVOLUME} \
${SNAPSHOTS_LOCATION}/${SUBVOLUME}_snapshot_${TIMESTAMP}
let EXIT_CODE=${EXIT_CODE}+$?
# Delete info file from source # Delete info file from source
rm -f ${TOPLEVEL}/${SUBVOLUME}/.snapsh rm -f ${TOPLEVEL}/${SUBVOLUME}/.snapsh
@ -101,7 +140,6 @@ snapshot() {
DESCRIPTION=${DESCRIPTION} DESCRIPTION=${DESCRIPTION}
TYPE=\"${SET_TYPE}\"\n" TYPE=\"${SET_TYPE}\"\n"
fi
exit ${EXIT_CODE} exit ${EXIT_CODE}
} }
@ -110,6 +148,8 @@ snapshot() {
list() { list() {
root_check root_check
mount_check
shopt -s nullglob shopt -s nullglob
NUM=1 NUM=1
SNAPSHOTS=(${SNAPSHOTS_LOCATION}/*/) SNAPSHOTS=(${SNAPSHOTS_LOCATION}/*/)
@ -117,14 +157,18 @@ list() {
printf "No snapshots found in ${SNAPSHOTS_LOCATION}.\n" printf "No snapshots found in ${SNAPSHOTS_LOCATION}.\n"
exit 0 exit 0
fi fi
printf "%6s %s %s %26s %s %s %6s %s %s\n" "Number" "|" "Time:" "|" "Source" "|" "Type" "|" "Description" printf "%6s %s %s %26s %10s %s %6s %s %s\n" "Number" "|" "Time:" "|" \
"Source" "|" "Type" "|" "Description"
for snapshot in ${SNAPSHOTS[@]}; do for snapshot in ${SNAPSHOTS[@]}; do
if [[ -z "${SET_TYPE}" ]]; then if [[ -z "${SET_TYPE}" ]]; then
. ${snapshot}/.snapsh . ${snapshot}/.snapsh
printf "%8s %32s %8s %8s %s\n" "${NUM} |" "${DATE} |" "${SOURCE_SUBVOLUME} |" "${TYPE} |" "${DESCRIPTION}" printf "%8s %32s %12s %8s %s\n" "${NUM} |" "${DATE} |" \
"${SOURCE_SUBVOLUME} |" "${TYPE} |" "${DESCRIPTION}"
elif [[ -n "${SET_TYPE}" ]]; then elif [[ -n "${SET_TYPE}" ]]; then
. ${snapshot}/.snapsh . ${snapshot}/.snapsh
[[ "${SET_TYPE}" == "${TYPE}" ]] && printf "%8s %32s %8s %8s %s\n" "${NUM} |" "${DATE} |" "${SOURCE_SUBVOLUME} |" "${TYPE} |" "${DESCRIPTION}" [[ "${SET_TYPE}" == "${TYPE}" ]] && printf "%8s %32s %12s %8s %s\n" \
"${NUM} |" "${DATE} |" "${SOURCE_SUBVOLUME} |" "${TYPE} |" \
"${DESCRIPTION}"
fi fi
let NUM=NUM+1 let NUM=NUM+1
@ -136,6 +180,7 @@ list() {
remove() { remove() {
root_check root_check
mount_check
# List snapshots in to array SNAPSHOTS # List snapshots in to array SNAPSHOTS
SNAPSHOTS=(${SNAPSHOTS_LOCATION}/*/) SNAPSHOTS=(${SNAPSHOTS_LOCATION}/*/)
@ -170,6 +215,8 @@ remove() {
rollback() { rollback() {
root_check # Check root privileges root_check # Check root privileges
mount_check # Check that the toplevel subvolume is mounted
SNAPSHOTS=(${SNAPSHOTS_LOCATION}/*/) # List snapshots to array SNAPSHOTS=(${SNAPSHOTS_LOCATION}/*/) # List snapshots to array
# Check that NUBER to roll back to is a valid snapshot # Check that NUBER to roll back to is a valid snapshot
@ -302,7 +349,7 @@ fi
# Options parsing: # Options parsing:
OPTIONS=$(getopt -a -n snapsh -o hs:d:lr:t: --long help,snapshot:,description:,list,remove:,rollback:,type:,post-rollback -- "$@") OPTIONS=$(getopt -a -n snapsh -o hs:d:lr:t: --long help,snapshot:,description:,list,remove:,rollback:,type:,post-rollback,mount -- "$@")
# Invalid options (getopt returns nonzero) # Invalid options (getopt returns nonzero)
if [[ "$?" -ne 0 ]]; then if [[ "$?" -ne 0 ]]; then
@ -373,6 +420,12 @@ while true; do
shift 2 shift 2
;; ;;
--mount)
mount_check
shift
break
;;
--) --)
shift shift
break break