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:
-h, --help Display this help message
-s SUBVOL, --snapshot SUBVOL Take a snapshot of subvolume named SUBVOL.
-d STR, --description STR Add a description for the snapshot displayed in the
snapshots listing.
-t TYPE, --type TYPE Set the type of snapshot, where TYPE=manual|auto|boot|backup
Can be used with -l, --list to filter results
-d STR, --description STR Add a description for the snapshot displayed
in the snapshots listing.
-t TYPE, --type TYPE Set the type of snapshot, where
TYPE=manual|auto|boot|backup
Can be used with --list to filter results
-l, --list List snapshots
-r NUMBER, --remove NUMBER Remove snapshot NUMBER. See snapshot numbers with
snapsh -l
--rollback NUMBER Roll back to snapshot NUMBER. See snapshot numbers
with snapsh -l. Target subvolume is detected from
snapshot automatically.\n"
-r NUMBER, --remove NUMBER Remove snapshot NUMBER. See snapshot numbers
with snapsh -l
--rollback NUMBER Roll back to snapshot NUMBER. See snapshot
numbers with snapsh -l. Target subvolume is
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
root_check #Check that script is run with root privileges.
# Check that the subvolume storing snapshots exists
if [[ ! -d ${SNAPSHOTS_LOCATION} ]]; then
if [[ -n ${SNAPSHOT} ]]; then
# If taking a snapshot,
# check that the subvolume storing snapshots exists and if not, ask
# to create it.
${BTRFS_EXECUTABLE} subvolume show ${SNAPSHOTS_LOCATION} > /dev/null
if [[ "$?" -ne 0 ]]; then
printf "Subvolume ${SNAPSHOTS_LOCATION} does not exist. Create it now?\n"
read -n 1 -p "y/n: "
@ -71,15 +84,38 @@ snapshot() {
${BTRFS_EXECUTABLE} subvolume create ${SNAPSHOTS_LOCATION}
unset ${REPLY}
else
EXIT_CODE=1
exit 1
fi
fi
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
if [[ -z "${SET_TYPE}" ]]; then
SET_TYPE="manual"
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
# Created first on the source subvolume, then deleted from the source
@ -89,7 +125,10 @@ snapshot() {
TYPE=\"${SET_TYPE}\"\n" > ${TOPLEVEL}/${SUBVOLUME}/.snapsh
# 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
rm -f ${TOPLEVEL}/${SUBVOLUME}/.snapsh
@ -101,7 +140,6 @@ snapshot() {
DESCRIPTION=${DESCRIPTION}
TYPE=\"${SET_TYPE}\"\n"
fi
exit ${EXIT_CODE}
}
@ -110,6 +148,8 @@ snapshot() {
list() {
root_check
mount_check
shopt -s nullglob
NUM=1
SNAPSHOTS=(${SNAPSHOTS_LOCATION}/*/)
@ -117,14 +157,18 @@ list() {
printf "No snapshots found in ${SNAPSHOTS_LOCATION}.\n"
exit 0
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
if [[ -z "${SET_TYPE}" ]]; then
. ${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
. ${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
let NUM=NUM+1
@ -136,6 +180,7 @@ list() {
remove() {
root_check
mount_check
# List snapshots in to array SNAPSHOTS
SNAPSHOTS=(${SNAPSHOTS_LOCATION}/*/)
@ -170,6 +215,8 @@ remove() {
rollback() {
root_check # Check root privileges
mount_check # Check that the toplevel subvolume is mounted
SNAPSHOTS=(${SNAPSHOTS_LOCATION}/*/) # List snapshots to array
# Check that NUBER to roll back to is a valid snapshot
@ -302,7 +349,7 @@ fi
# 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)
if [[ "$?" -ne 0 ]]; then
@ -373,6 +420,12 @@ while true; do
shift 2
;;
--mount)
mount_check
shift
break
;;
--)
shift
break