#!/bin/sh
# usage: snapshot.lvm2 vg/lv executable [args]
if test $# -lt 2; then
	echo  'usage: snap.lvm2 vg/lv executable [args]'
	exit
fi
SRC="$1"
shift
S_VOL="${SRC}.snaprep"
S_DEV="/dev/mapper/${SRC//\//-}.snaprep"
SNAPSHOT="/mnt/snaprep/${SRC//\//-}"
export SNAPSHOT
LOCKDIR=/var/lock/snaprep
test -d "$LOCKDIR" || mkdir -p "$LOCKDIR" || exit $?
LOCKFILE="$LOCKDIR/lvm2.${SRC//\//-}"
# since LVM implies Linux, I'm assuming the presence of the flock utility
if ! flock -n "$LOCKFILE" true; then
	echo >&2 "locked: $SRC"
	exit 1
fi
(
flock -n 3 || exit $?
echo $$ >&3
if test -b "$S_DEV"; then
	echo >&2 "removing stale snapshot"
	if grep -qF "$S_DEV" /proc/mounts; then  # TODO match only on start of line
		umount $S_DEV || exit $?
	fi
	lvremove -f "$S_DEV" || exit $?
fi
if test -d "$SNAPSHOT"; then
	# make sure it's empty and unused
	rmdir "$SNAPSHOT" || exit $?
fi
mkdir -p "$SNAPSHOT" || exit $?
lvcreate -n "${SRC##*/}.snaprep" -L "${SNAPSHOT_SIZE:-10G}" -s "$SRC" || exit $?
die_lvremove() {
	lvremove -f "$S_VOL"
	exit $?
}
magic="$(file -b -s "$(realpath "$S_DEV")")"
case "$magic" in
	(*XFS*) mount -t xfs -o nouuid "$S_DEV" "$SNAPSHOT" || die_lvremove $?;;
	(*) mount "$S_DEV" "$SNAPSHOT" || die_lvremove $?;;
esac
SNAP_SRC=$SNAPSHOT
export SNAP_SRC
touch $SNAP_SRC/.snapshot.$(date +%s)
"$@"
RETCODE=$?
umount "$SNAPSHOT"
lvremove -f "$S_VOL"
) 3> "$LOCKFILE"
exit $RETCODE