diff --git a/README.md b/README.md index 0c00b14..6c89ef2 100644 --- a/README.md +++ b/README.md @@ -12,3 +12,4 @@ Btrfs snapshot managing bash script - Display usage instructions with `snapsh -h` or `snapsh --help` - Taking snapshots requires root priviledges. Take a snapshot with `snapsh -s SUBVOLUME` or `snapsh --snapshot SUBVOLUME`, where `SUBVOLUME` is the name of the source subvolume. You can add a description for the snapshot with the `-d | --description` option (must be used before the `-s` option)

Example with Fedora default btrfs layout with `root` and `home` subvolumes:
`snapsh -d "This is a snapshot" -s root`
This will create a snapshot called `root_snapshot_YYYY.MM.DD-hh:mm:ss` to the `snapshots` subvolume (or the one you defined with `SNAPSHOTS_LOCATION`), with a description "This is a snapshot" - Snapshots can be listed with `snapsh -l` or `snapsh --list` +- Delete snapshots with the `-r` or `--remove` option. List snapshots first with `snapsh -l`, then delete snapshot with e.g. `snapsh -r 2`, where 2 is the number of the deletable snapshot in the `-l` listing. The list numbers always start from 1 and increment from there, so always check the number before deletion. Batch deletion might be implemented later. diff --git a/snapsh b/snapsh deleted file mode 100755 index e685614..0000000 --- a/snapsh +++ /dev/null @@ -1,203 +0,0 @@ -#!/bin/bash - -## snapsh -## Copyright (C) 2020 Jarno Rankinen -## -## This program is free software: you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation, either version 3 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program. If not, see . - -# Environment set up: - -TOPLEVEL="/root/btrfs-toplevel" -SNAPSHOTS_LOCATION="/root/btrfs-toplevel/snapshots" - -BTRFS_EXECUTABLE=$(which btrfs) -TIMESTAMP=$(date +%Y.%m.%d-%H:%M:%S) -SUBVOLUME="root" -DESCRIPTION="" -REMOVE_TARGET="" - - - -help() { - printf "Usage: - snapsh [OPTIONS] - -Options: - -h, --help Display this help message - -d STR, --description STR Add a description for the snapshot displayed in the - snapshots listing. Must be used before -s, e.g. - snapsh -d \"A snapshot\" -s root - -s SUBVOL, --snapshot SUBVOL Take a snapshot of subvolume named SUBVOL. - -l, --list List snapshots - -r NUMBER, --remove NUMBER Remove snapshot NUMBER. See snapshot numbers with - snapsh -l\n" -} - - - -snapshot() { - - EXIT_CODE=0 - root_check - - # Check that the subvolume storing snapshots exists - if [[ ! -d ${SNAPSHOTS_LOCATION} ]]; then - printf "Subvolume ${SNAPSHOTS_LOCATION} does not exist. Create it now?\n" - read -n 1 -p "y/n: " - - if [[ "${REPLY}" == "y" ]]; then - ${BTRFS_EXECUTABLE} subvolume create ${SNAPSHOTS_LOCATION} - unset ${REPLY} - else - EXIT_CODE=1 - fi - else - 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 - printf "DATE=\"$(date)\" - SOURCE_SUBVOLUME=\"${SUBVOLUME}\" - DESCRIPTION=\"${DESCRIPTION}\" - TYPE=\"manual\"\n" > ${TOPLEVEL}/${SUBVOLUME}/.snapsh - - # Create readonly subvolume - ${BTRFS_EXECUTABLE} subvolume snapshot -r ${TOPLEVEL}/${SUBVOLUME} ${SNAPSHOTS_LOCATION}/${SUBVOLUME}_snapshot_${TIMESTAMP} - - # Delete info file from source - rm -f ${TOPLEVEL}/${SUBVOLUME}/.snapsh - - printf "Snapshot created! - ${SUBVOLUME}_snapshot_${TIMESTAMP} - DATE=$(date) - SOURCE_SUBVOLUME=${SUBVOLUME} - DESCRIPTION=${DESCRIPTION} - TYPE=\"manual\"\n" - - fi - - exit ${EXIT_CODE} -} - - - -list() { - root_check - NUM=1 - printf "%6s %s %s %26s %s %s %6s %s %s\n" "Number" "|" "Time:" "|" "Source" "|" "Type" "|" "Description" - for snapshot in ${SNAPSHOTS_LOCATION}/*/; do - . ${snapshot}/.snapsh - printf "%8s %32s %8s %8s %s\n" "${NUM} |" "${DATE} |" "${SOURCE_SUBVOLUME} |" "${TYPE} |" "${DESCRIPTION}" - let NUM=NUM+1 - done - exit 0 -} - - - -remove() { - root_check - SNAPSHOTS=(${SNAPSHOTS_LOCATION}/*/) - let INDEX=${REMOVE_TARGET}-1 - TARGET=${SNAPSHOTS[${INDEX}]} - . ${TARGET}/.snapsh - - if [[ "${INDEX}" -gt "${#SNAPSHOTS[@]}" ]]; then - printf "Snapshot number ${REMOVE_TARGET} does not exist.\n" - list - exit 1 - elif [[ "${REMOVE_TARGET}" -lt 1 ]]; then - printf "Number must be a positive integer.\n" - list - exit 1 - fi - - printf "Delete snapshot ${REMOVE_TARGET}: ${DATE}, subvolume ${SOURCE_SUBVOLUME}, ${DESCRIPTION} (y/n)? " - read -n 1 - if [[ "${REPLY}" == "y" ]]; then - printf "\n" - ${BTRFS_EXECUTABLE} property set ${TARGET} ro false - ${BTRFS_EXECUTABLE} subvolume delete ${TARGET} - exit 0 - else - printf "\nAborted by user.\n" - exit 1 - fi -} - - - -# Check for root permissions -root_check() { - if [[ "$UID" -ne 0 ]]; then - printf "This option needs root permission.\n" - exit 1 - fi -} - - - -# If no options are given, display help -if [[ "$#" -eq 0 ]]; then - help - exit 0 -fi - - -# Options parsing: -OPTIONS=$(getopt -a -n snapsh -o hs:d:lr: --long help,snapshot:,description:,list,remove: -- "$@") - -# Invalid options (getopt returns nonzero) -if [[ "$?" -ne 0 ]]; then - printf "Error Parsing options\n" - help - exit 1 -fi - -eval set -- "$OPTIONS" -while true; do - case "$1" in - - -h | --help) - help - shift - exit 0 - ;; - - -d | --description) - DESCRIPTION="$2" - shift 2 - ;; - - -s | --snapshot) - SUBVOLUME="$2" - snapshot - shift 2 - ;; - - -l | --list) - list - shift - ;; - - -r | --remove) - REMOVE_TARGET="$2" - remove - shift 2 - ;; - - - esac -done -