#!/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