#!/bin/bash
#
# Test integritysetup compatibility.
#
INTSETUP=../src/integritysetup
DEV_NAME=dmc_test
DEV=mode-test.img
KEY_FILE=key.img

dmremove() { # device
	udevadm settle >/dev/null 2>&1
	dmsetup remove $1 >/dev/null 2>&1
}

cleanup() {
	[ -b /dev/mapper/$DEV_NAME ] && dmremove $DEV_NAME
	rm -f $DEV $KEY_FILE >/dev/null 2>&1
}

fail()
{
	echo
	[ -n "$1" ] && echo "FAIL: $1"
	cleanup
	exit 100
}

skip()
{
	[ -n "$1" ] && echo "$1"
	exit 77
}

add_device() {
	cleanup
	dd if=/dev/urandom of=$KEY_FILE bs=1 count=512 >/dev/null 2>&1
	dd if=/dev/zero of=$DEV bs=1M count=32 >/dev/null 2>&1
	sync
}

status_check() # name value
{
	X=$($INTSETUP status $DEV_NAME | grep "$1" | sed 's/.*: //' | cut -d' '  -f 2)
	if [ "$X" != "$2" ] ; then
		echo "[status FAIL]"
		echo " Expecting $1:$2 got \"$X\"."
		fail
	fi
}

dump_check() # name value
{
	X=$($INTSETUP dump $DEV | grep "$1" | cut -d' '  -f 2)
	if [ "$X" != "$2" ] ; then
		echo "[dump FAIL]"
		echo " Expecting $1:$2 got \"$X\"."
		fail
	fi
}

int_check_sum() # alg checksum
{
	# Fill device with zeroes and reopen it
	dd if=/dev/zero of=/dev/mapper/$DEV_NAME bs=1M oflag=direct >/dev/null 2>&1
	dmremove $DEV_NAME

	$INTSETUP open $DEV $DEV_NAME --integrity $1 || fail "Cannot activate device."

	VSUM=$(sha256sum /dev/mapper/$DEV_NAME | cut -d' ' -f 1)
	if [ "$VSUM" = "$2" ] ; then
		echo -n "[CHECKSUM OK]"
	else
		echo "[FAIL]"
		echo " Expecting $2 got $VSUM."
		fail
	fi
}

intformat() # alg alg_out tagsize sector_size csum
{
	echo -n "[INTEGRITY:$2:$3:$4]"
	echo -n "[FORMAT]"
	$INTSETUP format -q --integrity $1 --tag-size $3 --sector-size $4 $DEV || fail "Cannot format device."
	dump_check "tag_size" $3
	dump_check "sector_size" $4
	echo -n "[ACTIVATE]"
	$INTSETUP open $DEV $DEV_NAME --integrity $1 || fail "Cannot activate device."
	status_check "tag size" $3
	status_check "integrity" $2
	status_check "sector size" $4
	int_check_sum $1 $5
	echo -n "[REMOVE]"
	$INTSETUP close $DEV_NAME || fail "Cannot deactivate device."
	echo "[OK]"
}

int_error_detection() # alg tagsize sector_size
{
	echo -n "[INTEGRITY:$1:$2:$3]"
	echo -n "[FORMAT]"
	$INTSETUP format -q --integrity $1 --tag-size $2 --sector-size $3 $DEV || fail "Cannot format device."
	echo -n "[ACTIVATE]"
	$INTSETUP open $DEV $DEV_NAME --integrity $1 --integrity-no-journal || fail "Cannot activate device."
	echo -n "[WRITE DATA]"
	echo -n "EXAMPLE TEXT" | dd of=/dev/mapper/$DEV_NAME >/dev/null 2>&1 || fail "Cannot write to device."
	$INTSETUP close $DEV_NAME || fail "Cannot deactivate device."

	# find offset of data area
	ARR=(`dd if=$DEV bs=512 2>/dev/null | hexdump -C | grep 'EXAMPLE TEXT'`)
	OFF_HEX=${ARR[0]}
	OFF_DEC=$((16#$OFF_HEX))

	echo -n "[CORRUPT DATA:$OFF_DEC]"
	echo -n "Z" | dd of=$DEV bs=1 seek=$OFF_DEC conv=notrunc >/dev/null 2>&1 || fail "Cannot write to device."

	echo -n "[DETECT ERROR]"
	$INTSETUP open $DEV $DEV_NAME --integrity $1 || fail "Cannot activate device."
	dd if=/dev/mapper/$DEV_NAME  >/dev/null 2>&1 && fail "Error detection failed."

	echo -n "[REMOVE]"
	$INTSETUP close $DEV_NAME || fail "Cannot deactivate device."
	echo "[OK]"
}

[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped."
[ ! -x "$INTSETUP" ] && skip "Cannot find $INTSETUP, test skipped."
modprobe dm-integrity >/dev/null 2>&1
dmsetup targets | grep integrity >/dev/null 2>&1 || skip "Cannot find dm-integrity target, test skipped."

add_device

intformat crc32c      crc32c          4  512 08f63eb27fb9ce2ce903b0a56429c68ce5e209253ba42154841ef045a53839d7
intformat crc32       crc32           4  512 08f63eb27fb9ce2ce903b0a56429c68ce5e209253ba42154841ef045a53839d7
intformat sha1        sha1           20  512 6eedd6344dab8875cd185fcd6565dfc869ab36bc57e577f40c685290b1fa7fe7
intformat sha1        sha1           16 4096 e152ec88227b539cd9cafd8bdb587a1072d720cd6bcebe1398d4136c9e7f337b
intformat sha256      sha256         32  512 8e5fe4119558e117bfc40e3b0f13ade3abe497b52604d4c7cca0cfd6c7f4cf11
intformat hmac-sha256 hmac\(sha256\) 32  512 8e5fe4119558e117bfc40e3b0f13ade3abe497b52604d4c7cca0cfd6c7f4cf11
intformat sha256      sha256         32 4096 33f7dfa5163ca9f740383fb8b0919574e38a7b20a94a4170fde4238196b7c4b4
intformat hmac-sha256 hmac\(sha256\) 32 4096 33f7dfa5163ca9f740383fb8b0919574e38a7b20a94a4170fde4238196b7c4b4

echo "Error detection tests:"
int_error_detection crc32c      4  512
int_error_detection crc32c      4  4096
int_error_detection crc32       4  512
int_error_detection crc32       4  4096
int_error_detection sha1        20 512
int_error_detection sha1        16 512
int_error_detection sha1        20 4096
int_error_detection sha256      32 512
int_error_detection sha256      32 4096
int_error_detection hmac-sha256 32 512
int_error_detection hmac-sha256 32 4096

# FIXME: key, journal encryption, mode/recovery, journal params

cleanup
