#!/bin/bash
PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"

# File paths (used for dd if=/dev/zero and ggate to create GEOM providers)
# NOTE: ~200MB is required to be free on this partition!
# I've only tested with /root/ myself, in case I accidentally hardcoded it.
MASTERPATH="/root/zfsclonecrash/crashtestmaster.disk"
SLAVEPATH="/root/zfsclonecrash/crashtestslave.disk"
LASTBACKUP="/root/zfsclonecrash/last-backup-name"

# ggate IDs - high "random" numbers that are unlikely to be in use
MASTERNUM=1482
SLAVENUM=1675

die() {
# Basically, print the error, and if applicable, go back to status quo.
# We don't want errors printed since they are useless without loads of sanity checking...
	echo $@ 1>&2
	zpool export crashtestmaster 2>/dev/null
	zpool export crashtestslave 2>/dev/null
	ggatel destroy -u $MASTERNUM 2>/dev/null
	ggatel destroy -u $SLAVENUM 2>/dev/null
	exit 1
}

function mount_unmount {
	if [ -z "$1" ]; then
		die 'Invalid argument given to mount_unmount'
	elif [[ "$1" == "mount" ]]; then
		ggatel create -u ${MASTERNUM} $MASTERPATH 2>/dev/null
		zpool import -R /crashtestmaster crashtestmaster 2>/dev/null
		ggatel create -u ${SLAVENUM} $SLAVEPATH 2>/dev/null
		zpool import -R /crashtestslave crashtestslave 2>/dev/null
	elif [[ "$1" == "unmount" ]]; then
		zpool export crashtestmaster 2>&1 >/dev/null
		ggatel destroy -u ${MASTERNUM} 2>&1 >/dev/null
		zpool export crashtestslave 2>&1 >/dev/null
		ggatel destroy -u ${SLAVENUM} 2>&1 >/dev/null
	fi
}

help() {
	echo "Usage: $0 <crash|mount|unmount|initial|stress>" 1>&2
	echo "Hint: Just do $0 crash, and it probably will do so." 1>&2
	exit 1
}

initial() {
	mkdir -p $(dirname $MASTERPATH)

	# Cleaning up, in case this isn't the first run, and some crap got left behind
	rm -rf /crashtest{master,slave}
	mount_unmount unmount

	echo Creating files and syncing
	dd if=/dev/zero of=$MASTERPATH bs=1000k count=100
	dd if=/dev/zero of=$SLAVEPATH bs=1000k count=100
	sync
	echo Sleeping 5 seconds
	sleep 5
	echo 'Creating GEOM providers (~10 secs)'
	ggatel create -u ${MASTERNUM} $MASTERPATH || die 'Unable to create GEOM provider for master'
	sleep 5
	ggatel create -u ${SLAVENUM} $SLAVEPATH || die 'Unable to create GEOM provider for slave'
	sleep 5
	echo 'Creating pools'
	zpool create -f crashtestmaster ggate${MASTERNUM} || die 'Unable to create master pool'
	zpool create -f crashtestslave ggate${SLAVENUM} || die 'Unable to create slave pool'

	echo 'Adding some data to the master pool'
	zfs create crashtestmaster/test_orig
	dd if=/dev/random of=/crashtestmaster/test_orig/file1 bs=1000k count=10
	dd if=/dev/random of=/crashtestmaster/test_orig/file2 bs=1000k count=10

	echo 'Cloning test_base'
	zfs snapshot crashtestmaster/test_orig@snap
	zfs clone crashtestmaster/test_orig@snap crashtestmaster/test_cloned
	zfs promote crashtestmaster/test_cloned

	NOW=$(date +"backup-%Y%m%d-%H%M%S")
	echo 'Creating snapshots'
	zfs snapshot -r crashtestmaster@$NOW || die 'Unable to snapshot'
	echo 'Doing initial clone to slave pool'
	zfs send -R crashtestmaster@$NOW | zfs recv -vFd crashtestslave
	mount_unmount unmount
	echo $NOW > $LASTBACKUP

	echo 'Done!'

}

function stress() {
	while :; do
		mount_unmount mount

		CURR=$(date +"backup-%Y%m%d-%H%M%S")

		echo Taking snapshots
		zfs snapshot -r crashtestmaster@$CURR || die 'Unable to create $CURR snapshot'

		echo Starting backup...
		LAST=$(cat $LASTBACKUP)
		zfs send -R -I $LAST crashtestmaster@$CURR | zfs recv -Fvd crashtestslave

		echo $CURR > $LASTBACKUP

		mount_unmount unmount
	done
}

if [ ! -z "$1" ]; then
	case $1 in
	mount) mount_unmount mount; exit 0;;
	unmount) mount_unmount unmount; exit 0;;
	initial) initial; exit 0;;
	stress) stress; exit 0;;
	crash) initial; stress; exit 0;;
	*) help;;
	esac
else
	help
fi
