Skip to content

Instantly share code, notes, and snippets.

@mubeeniqbal
Forked from cmlsharp/snp
Last active June 8, 2021 14:43
Show Gist options
  • Save mubeeniqbal/81fd74d5e8cf522c780f to your computer and use it in GitHub Desktop.
Save mubeeniqbal/81fd74d5e8cf522c780f to your computer and use it in GitHub Desktop.
Runs a command wrapped with snapper pre-post snapshots for btrfs subvolumes. File path: /usr/local/bin
#!/usr/bin/env bash
#
# Runs a command wrapped with snapper pre-post snapshots for btrfs subvolumes.
# Usage: snp [-c config1,config2,...] <command>
# Constants
readonly LOG_PATH='/var/local/log/snp'
readonly DATE="$(date +'%Y-%m-%d-%H%M%S')"
readonly LOG_FILE="${LOG_PATH}/snp-${DATE}.log"
#######################################
# Print out error messages to STDERR.
# Globals:
# None
# Arguments:
# Error
# Returns:
# None
#######################################
err() {
echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] error: $@" 1>&2
}
#######################################
# Log STDOUT and STDERR.
# Reference: http://stackoverflow.com/questions/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself
# Globals:
# None
# Arguments:
# Path to log file
# Returns:
# None
#######################################
log_stdout_stderr() {
exec > >(tee -a "$@")
exec 2> >(tee -a "$@" >&2)
}
# TODO(mubeeniqbal): Use of eval considered dangerous. Find an alternative to all eval commands.
main() {
if [[ "${EUID}" -ne 0 ]]; then
err 'snp: you cannot perform this operation unless you are root: Permission denied'
exit 1
fi
if [[ ! -d "${LOG_PATH}" ]]; then
mkdir -vp "${LOG_PATH}" || return
fi
log_stdout_stderr "${LOG_FILE}"
# Snapper configs array.
local -a CONFIGS=('root')
# Populate the array if configs are provided in arguments.
if [[ "$1" = '-c' ]]; then
shift
CONFIGS=(${1//,/ })
shift
fi
# Make configs array constant.
readonly CONFIGS
local -ri CONFIG_COUNT="${#CONFIGS[@]}"
# Save command to wrap with pre-post snapshots.
local -r CMD="$@"
# Declare local snapshot numbers array.
local -a numbers
local snapper_cmd
echo '> Creating pre snapshots.'
local -i i
# Create pre snapshots.
for ((i=0; i<"${CONFIG_COUNT}"; ++i)); do
snapper_cmd="snapper --config=${CONFIGS[${i}]} create --type=pre --cleanup-algorithm=number --print-number --description=\"command: ${CMD}\""
echo "> Running command: ${snapper_cmd}"
numbers["${i}"]="$(eval "${snapper_cmd}")" || return
echo "> Snapshot created: config:${CONFIGS[${i}]}, type:pre, number:${numbers[${i}]}"
done
# Run wrapped command.
echo '> ---------------------------------------------------------------------'
echo "> Running command: ${CMD}"
eval "${CMD}"
echo '> ---------------------------------------------------------------------'
echo '> Creating post snapshots.'
# Create post snapshots.
for ((i=0; i<"${CONFIG_COUNT}"; ++i)); do
snapper_cmd="snapper --config=${CONFIGS[${i}]} create --type=post --cleanup-algorithm=number --print-number --description=\"command: ${CMD}\" --pre-number=${numbers[${i}]}"
echo "> Running command: ${snapper_cmd}"
numbers["${i}"]="$(eval "${snapper_cmd}")" || return
echo "> Snapshot created: config:${CONFIGS[${i}]}, type:post, number:${numbers[${i}]}"
done
exit 0
}
main "$@"
@mubeeniqbal
Copy link
Author

Forked and improved code. Made more readable following Google shell style guide (https://google-styleguide.googlecode.com/svn/trunk/shell.xml).

@cmlsharp
Copy link

EUID should be inside (()) instead of [[]]

@mubeeniqbal
Copy link
Author

Why is that so? What effect does (( )) have over [[ ]]?

@auipga
Copy link

auipga commented Jun 8, 2021

-c is exactly what I was looking for. Thank you!

Why do you always deny unless root? My .snapshots directory is accessible to me. (man snapper #PERMISSIONS)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment