#!/bin/sh

set -e

mkdir -p /mnt/urbackup_snaps

CDIR=`dirname $0`

VOLUME_SNAP=0
if [ "x$1" = "xvol" ]
then
	VOLUME_SNAP=1
elif [ "x$1" != "xfs" ]
then
	echo "First parameter must be either 'fs' or 'vol'"
	exit 1
fi
shift

SNAP_ID=$1
SNAP_MOUNTPOINT="$2"
SNAP_DEST=/mnt/urbackup_snaps/$SNAP_ID

CDIR=`dirname $0`
. $CDIR/filesystem_snapshot_common
exit_exclude_snapshot_mountpoints "$SNAP_MOUNTPOINT"

DEVICE=$(df -T -P | egrep " ${SNAP_MOUNTPOINT}\$" | head -n 1 | tr -s " " | cut -d" " -f1)
set_filesystem_type "${SNAP_MOUNTPOINT}"
DEVNAME=$(basename $DEVICE)


if [ "x$TYPE" = "x" ]
then
        if btrfs subvolume list -o "$SNAP_MOUNTPOINT" > /dev/null 2>&1
        then
                TYPE="btrfs"
        fi
fi

if [ $VOLUME_SNAP = 0 ] && [ "x$TYPE" = "xbtrfs" ]
then
    $CDIR/btrfs_create_filesystem_snapshot "$@"
    exit $?
fi

if [ "x$TYPE" = "xvfat" ]
then
	mount -o remount,ro "$SNAP_MOUNTPOINT"
	echo "$DEVICE" > "$SNAP_MOUNTPOINT-dev"
	echo "vfat" > "$SNAP_MOUNTPOINT-name"
	echo "SNAPSHOT=$SNAP_MOUNTPOINT"
	exit 0
fi


if [ "x$TYPE" != "xxfs" ] && [ "x$TYPE" != "xext4" ] && [ "x$TYPE" != "xbtrfs" ]
then
    echo "File system $TYPE not supported"
    exit 1
fi

if [ "x$DEVICE" = "x" ]
then
    echo "Cannot get device for filesystem $SNAP_MOUNTPOINT"
    exit 1
fi

echo "Snapshotting device $DEVICE via dm..."

if ! dmsetup table "$DEVICE" > /dev/null 2>&1
then
	echo "$DEVICE is not a device mapper device. Cannot snapshot via dm."
	exit 1
fi

modprobe dm_snapshot

DEV_SIZE=$(blockdev --getsz "$DEVICE")

if [ "x$DEV_SIZE" = "x" ]
then
	echo "Cannot get device size of device $DEVICE"
	exit 1
fi


RUUID="a31725acca86421d"

ORIG_DEVICE="/dev/mapper/$DEVNAME-$RUUID-clone"
ERA_META_FN=".era-meta_3d41c58e-6724-4d47-8981-11c766a08a24"

ERA_RESET=0
if ! command -v era_dump >/dev/null 2>&1
then
	echo "thin-provisioning-tools not installed. CBT not enabled."
elif modprobe dm_era && ! dmsetup table "$DEVICE" | grep " era " > /dev/null 2>&1 && ! dmsetup table "$DEVICE" | grep " snapshot-origin " > /dev/null 2>&1
then
	echo "Layering in dm-era device..."
	META_SIZE=$(( (((DEV_SIZE*4)/1024)/512)*512 + 3*1024*1024 ))
	if [ $META_SIZE -lt $((4*1024*1024)) ]
	then
		META_SIZE=$((4*1024*1024))
	fi

	if [ -e "$SNAP_MOUNTPOINT/$ERA_META_FN" ]
	then
		chattr -i "$SNAP_MOUNTPOINT/$ERA_META_FN" || true
		rm "$SNAP_MOUNTPOINT/$ERA_META_FN"
	fi

	if [ "$TYPE" = "btrfs" ]
	then
		touch "$SNAP_MOUNTPOINT/$ERA_META_FN"
		chattr +C "$SNAP_MOUNTPOINT/$ERA_META_FN"
	fi

	fallocate -l $META_SIZE "$SNAP_MOUNTPOINT/$ERA_META_FN"
	chattr +i "$SNAP_MOUNTPOINT/$ERA_META_FN"
	echo "FLOCK_PERM=$SNAP_MOUNTPOINT/$ERA_META_FN"

	ORIG_DEVICE="/dev/mapper/$DEVNAME-$RUUID-clone-era"
	dmsetup table "$DEVICE" | dmsetup create "$DEVNAME-$RUUID-clone-era"
	urbackupclientbackend --internal --print-dm-file-extents "$SNAP_MOUNTPOINT/$ERA_META_FN" --file-dm-block-dev "$ORIG_DEVICE" | dmsetup create "$DEVNAME-$RUUID-era-metadata"
	dmsetup table "$DEVNAME-$RUUID-era-metadata" | dmsetup create "$DEVNAME-$RUUID-era-metadata-access"
	dd if=/dev/zero of=/dev/mapper/$DEVNAME-$RUUID-era-metadata bs=512 count=$(blockdev --getsz /dev/mapper/$DEVNAME-$RUUID-era-metadata) > /dev/null 2>&1
	echo "0 $DEV_SIZE era /dev/mapper/$DEVNAME-$RUUID-era-metadata $ORIG_DEVICE 1024" | dmsetup create "$DEVNAME-$RUUID-clone"
	echo "CBT=type=era&reset=1"
	ERA_RESET=1
fi

OVERLAY_FN="$SNAP_MOUNTPOINT/.overlay_2fefd007-3e48-4162-b2c6-45ccdda22f37_$SNAP_ID"
if [ -e "$OVERLAY_FN" ]
then
	chattr -i "$OVERLAY_FN" || true
	rm "$OVERLAY_FN"
fi

if [ "$TYPE" = "btrfs" ]
then
	touch "$OVERLAY_FN"
        chattr +C "$OVERLAY_FN"
fi

fallocate -l 5G "$OVERLAY_FN"
chattr +i "$OVERLAY_FN"
echo "FLOCK=$OVERLAY_FN"

if ! [ -e "/dev/mapper/$DEVNAME-$RUUID-clone" ]
then
	dmsetup table "$DEVICE" | dmsetup create "$DEVNAME-$RUUID-clone"
fi

urbackupclientbackend --internal --print-dm-file-extents "$OVERLAY_FN" --file-dm-block-dev "$ORIG_DEVICE" | dmsetup create "$DEVNAME-$SNAP_ID-cow-storage"
# Needs to run with mlockall for root device -> cannot do that in bash
urbackupclient_dmsnaptool --dev "$DEVICE" --clone-dev "/dev/mapper/$DEVNAME-$RUUID-clone" --snap-dev "/dev/mapper/$DEVNAME-$SNAP_ID" --cow-dev "/dev/mapper/$DEVNAME-$SNAP_ID-cow-storage" --origin-dev "/dev/mapper/$DEVNAME-$RUUID-origin" --era-access-dev "/dev/mapper/$DEVNAME-$RUUID-era-metadata-access" --dev-size "$DEV_SIZE"

truncate -s100M $SNAP_MOUNTPOINT/.overlay_2fefd007-3e48-4162-b2c6-45ccdda22f37_$SNAP_ID-wsnap

LODEV=`losetup -f`

if [ "x$LODEV" = x ]
then
        echo "TODO: Cleanup"
        exit 1
fi

losetup $LODEV $SNAP_MOUNTPOINT/.overlay_2fefd007-3e48-4162-b2c6-45ccdda22f37_$SNAP_ID-wsnap

echo "0 $DEV_SIZE snapshot /dev/mapper/$DEVNAME-$SNAP_ID $LODEV N 8" | dmsetup create "$DEVNAME-$SNAP_ID-wsnap"

echo "Mounting /dev/mapper/$DEVNAME-$SNAP_ID-wsnap..."

MOUNTOPTS="ro"

if [ $TYPE = "xfs" ]
then
	MOUNTOPTS="ro,nouuid"
elif [ $TYPE = "btrfs" ] && [ $VOLUME_SNAP = 0 ]
then
	btrfstune -m "/dev/mapper/$DEVNAME-$SNAP_ID-wsnap"
fi

mkdir -p "$SNAP_DEST"
if [ $VOLUME_SNAP = 0 ]
then
	if ! mount -o $MOUNTOPTS "/dev/mapper/$DEVNAME-$SNAP_ID-wsnap" "$SNAP_DEST"
	then
		echo "Mounting filesystem failed"
		#TODO: CLEANUP
		exit 1
	fi
fi

echo "$DEVNAME" > ${SNAP_DEST}-name
echo "/dev/mapper/$DEVNAME-$SNAP_ID" > ${SNAP_DEST}-dev
echo "SNAPSHOT=$SNAP_DEST"
