#!/usr/bin/env bash

# For the license, see the LICENSE file in the root directory.
#set -x

if [ "$(id -u)" -ne 0 ]; then
	echo "Need to be root to run this test."
	exit 77
fi

ROOT=${abs_top_builddir:-$(dirname "$0")/..}
TESTDIR=${abs_top_testdir:-$(dirname "$0")}

TPM_PATH="$(mktemp -d)" || exit 1
STATE_FILE=$TPM_PATH/tpm-00.permall
VOLATILE_STATE_FILE=$TPM_PATH/tpm-00.volatilestate
PID_FILE=$TPM_PATH/swtpm.pid
SOCK_PATH=$TPM_PATH/sock
CMD_PATH=$TPM_PATH/cmd
RESP_PATH=$TPM_PATH/resp
LOGFILE=$TPM_PATH/logfile

function cleanup()
{
	pid=$(ps aux | grep "swtpm" | grep -E " file=${PID_FILE}\$" | gawk '{print $2}')
	if [ -n "$pid" ]; then
		kill_quiet -9 "$pid"
	fi
	rm -rf "$TPM_PATH"
}

trap "cleanup" EXIT

source "${TESTDIR}/common"
skip_test_no_tpm12 "${SWTPM_EXE}"

source "${TESTDIR}/load_vtpm_proxy"

rm -f "$STATE_FILE" "$VOLATILE_STATE_FILE" 2>/dev/null

$SWTPM_EXE chardev --vtpm-proxy \
	--tpmstate "dir=$TPM_PATH" \
	--ctrl "type=unixio,path=$SOCK_PATH" \
	${SWTPM_TEST_SECCOMP_OPT:+${SWTPM_TEST_SECCOMP_OPT}} \
	--pid "file=$PID_FILE" &>"$LOGFILE" &
sleep 0.5
PID=$(ps aux | grep swtpm | grep -E " file=${PID_FILE}\$" | gawk '{print $2}')

display_processes_by_name "swtpm"

if ! kill_quiet -0 "$PID"; then
	echo "Error: Chardev TPM did not start."
	exit 1
fi

if wait_for_file "$PID_FILE" 3; then
	echo "Error: Chardev TPM did not write pidfile."
	exit 1
fi

# Wait for chardev to appear; TPM 1.2 may take a long time to self-test
# with valgrind
for ((i = 0; i < 200; i ++)); do
	if [ -z "${TPM_DEVICE}" ]; then
		TPM_DEVICE=$(sed -n 's,.*\(/dev/tpm[0-9]\+\).*,\1,p' "$LOGFILE")
		if [ -n "${TPM_DEVICE}" ]; then
			echo "Using ${TPM_DEVICE}."
		fi
	fi
	if [ -n "${TPM_DEVICE}" ]; then
		[ -c "${TPM_DEVICE}" ] && break
	fi
	sleep 0.1
done
if ! [ -c "${TPM_DEVICE}" ]; then
	echo "Error: Chardev ${TPM_DEVICE} did not appear"
	exit 1
fi

# Open access to the TPM
if ! exec 100<>"$TPM_DEVICE"; then
	echo "Error: Could not open $TPM_DEVICE"
	exit 1
fi

# Read PCR 17 -- this should give a fatal error response
echo -en '\x00\xC1\x00\x00\x00\x0E\x00\x00\x00\x15\x00\x00\x00\x11' >&100
#RES=$(cat <&100 | od -t x1 -A n -w128)
RES=$(od -t x1 -A n -w128 <&100)
exp=' 00 c4 00 00 00 1e 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff'
if [ "$RES" != "$exp" ]; then
	echo "Error: Did not get expected result from TPM_PCRRead(17)"
	echo "expected: $exp"
	echo "received: $RES"
	exit 1
fi

exec 100>&-

if ! kill_quiet -0 "$PID"; then
	echo "Error: Chardev TPM must have crashed."
	exit 1
fi

if [ ! -e "$STATE_FILE" ]; then
	echo "Error: TPM state file $STATE_FILE does not exist."
	exit 1
fi

# Send shutdown command to the TPM: CMD_SHUTDOWN = 00 00 00 03
echo -en '\x00\x00\x00\x03' > "$CMD_PATH"
socat -x -t10 "FILE:$CMD_PATH,rdonly" "UNIX-CONNECT:$SOCK_PATH" 2>&1 | \
	sed -n '/^ /p' | \
	tail -n1 > "$RESP_PATH"
res="$(cat "$RESP_PATH")"
exp=" 00 00 00 00"
if [ "$res" != "$exp" ]; then
	echo "Error: Unexpected response from CMD_SHUTDOWN:"
	echo "       actual  : $res"
	echo "       expected: $exp"
	exit 1
fi

if wait_file_gone "$PID_FILE" 2; then
	echo "Error: TPM should have removed PID file by now."
	exit 1
fi

if wait_process_gone "${PID}" 4; then
	echo "Error: TPM should not be running anymore."
	exit 1
fi

echo "OK"

exit 0
