#!/bin/bash

# usage example:
#
# TDB_NOFSYNC=1 NET_BIN="./bin/net" NET_OPTIONS=" -s ./smb.conf" NUM_PARALLEL=128 test_torture_net_registry_createkey.sh

G_REGKEY='HKLM\Software\Samba\MYTESTKEY'
G_LOG_FILE_BASE="/tmp/_test_registry_log.${BASHPID}"

_NET_OPTIONS="${_NET_OPTIONS} ${NET_OPTIONS}"

if [ "x$NET_BIN" = "x" ] ; then
	NET_BIN="net"
fi

NET="${NET_BIN} -d 10 ${NET_OPTIONS}"
NETREG="${NET} registry"

test_log() {
	local L_MSG="$@"

	local L_LOG_FILE_BASE="${G_LOG_FILE_BASE}"
	local L_DATE=$(date +%Y-%m-%d-%H:%M:%S-%N)
	local L_MY_PID=${BASHPID}
	local L_LOG_FILE="${G_LOG_FILE_BASE}.${L_MY_PID}"

	echo "${L_DATE} ${L_MSG}" &>> ${L_LOG_FILE}
	echo "[${L_MY_PID}] ${L_MSG}"
}

test_create_reg_key() {
	local L_REG_BASEKEY=$1
	local L_REG_SUBKEY=$2
	local L_REG_KEY="${L_REG_BASEKEY}\\${L_REG_SUBKEY}"
	local L_REGVAL_DATA="$3"
	local L_MY_PID=${BASHPID}
	local L_LOG_FILE_NET="${G_LOG_FILE_BASE}.net.${L_MY_PID}"

	test_log "About to create key [${L_REG_KEY=}]..."

	${NETREG} enumerate ${L_REG_BASEKEY} &> ${L_LOG_FILE_NET}
	local RC=$?

	if [ "$RC" -ne 0 ] ; then
		test_log "Registry base key [${L_REG_BASEKEY}] does not exist.  Creating..."

		${NETREG} createkey ${L_REG_BASEKEY} &>> ${L_LOG_FILE_NET}
		local RC=$?
		if [ "$RC" -ne 0 ] ; then
			test_log "Error: Create registry key [${L_REG_BASEKEY}] failed."
			return 1
		fi
	else
		test_log "Registry key [${L_REG_BASEKEY}] exists, no need to create it."
	fi

	${NETREG} createkey "${L_REG_KEY}" &>> ${L_LOG_FILE_NET}
	local RC=$?
	if [ "$RC" -ne 0 ] ; then
		test_log "Error: Creating registry key [${L_REG_KEY}] failed."
		return 1
	fi

	test_log "Success: Created registry key [${L_REG_KEY}]."

	${NETREG} enumerate "${L_REG_KEY}" &>> ${L_LOG_FILE_NET}
	local RC=$?
	if [ "$RC" -ne 0 ] ; then
		test_log "Error: Could not enumerate registry key [${L_REG_KEY}]."
		return 1
	fi

	test_log "Success: Found registry key [${L_REG_KEY}]."

	return 0
}


# recursive delete function
test_delete_reg_key_recursive() {
	local L_REG_BASEKEY=$1
	local L_REG_SUBKEY=$2
	local L_REG_KEY="${L_REG_BASEKEY}\\${L_REG_SUBKEY}"
	local L_LOG_FILE_NET="${G_LOG_FILE_BASE}.net.${BASHPID}"

	${NETREG} enumerate "${L_REG_KEY}" &>> ${L_LOG_FILE_NET}
	local RC=$?
	if [ "$RC" -ne 0 ]; then
		test_log "Registry key [${L_REG_KEY}] does not exist. no need to delete."
		return 0;
	fi

	${NETREG} deletekey_recursive "${L_REG_KEY}" &>> ${L_LOG_FILE_NET}
	RC=$?
	if [ "$RC" -ne 0 ] ; then
		test_log "Error: Deleting registry key [${L_REG_KEY}] failed."
		return 1
	fi

	return 0
}

# non-recursive dele function
# should fail when the key does not exist
test_delete_reg_key() {
	local L_REG_BASEKEY=$1
	local L_REG_SUBKEY=$2
	local L_REG_KEY="${L_REG_BASEKEY}\\${L_REG_SUBKEY}"
	local L_LOG_FILE_NET="${G_LOG_FILE_BASE}.net.${BASHPID}"

	${NETREG} deletekey "${L_REG_KEY}" &>> ${L_LOG_FILE_NET}
	local RC=$?
	if [ "$RC" -ne 0 ] ; then
		test_log "Error: Deleting registry key [${L_REG_KEY}] failed."
		return 1
	fi

	return 0
}

test_create_registry_keys_in_parallel() {
	local L_COUNT=$1
	local L_NUM=$2

	local L_REGKEY_BASE="key"

	test_log "[RUN:${L_COUNT}] - test_create_registry_keys_in_parallel"

	for i in $(seq 1 ${L_NUM}) ; do
		local L_REGKEY[$i]="${L_REGKEY_BASE}${i}"
	done

	# preparation: remove...
	if [ $L_COUNT -eq 1 ]; then
		for i in $(seq 1 ${L_NUM}) ; do
			local RC
			local L_REGKEY_NAME="${L_REGKEY[$i]}"
			test_log "Deleting key ${L_REGKEY_NAME}..."
			test_delete_reg_key_recursive ${G_REGKEY} ${L_REGKEY_NAME}
			RC=$?
			if [ $RC -ne 0 ]; then
				test_log "Error deleting key ${L_REGKEY_NAME}. EXIT"
				exit 1
			fi
			test_log "Successfully deleted ${L_REGKEY_NAME}."
		done
	fi


	# create in parallel:

	for i in $(seq 1 ${L_NUM}) ; do
		local L_REGKEY_NAME=${L_REGKEY[$i]}
		test_create_reg_key ${G_REGKEY} ${L_REGKEY_NAME} &
		local L_C_PID[$i]=$!
		test_log "Started subprocess for creation of ${L_REGKEY_NAME}: PID=${L_C_PID[$i]}"
	done

	for i in $(seq 1 ${L_NUM}) ; do
		wait ${L_C_PID[$i]}
		local L_RC[$i]=$?
	done


	for i in $(seq 1 ${L_NUM}) ; do
		local L_REGKEY_NAME="${L_REGKEY[$i]}"
		if [ ${L_RC[$i]} -ne 0 ]; then
			test_log "Error creating key ${L_REGKEY_NAME} (PID=${L_C_PID[$i]}). EXIT"
			exit 1
		fi
		test_log "Creating key ${L_REGKEY_NAME} succeeded (PID=${L_C_PID[$i]})"
	done


	# delete in parallel:

	for i in $(seq 1 ${L_NUM}) ; do
		local L_REGKEY_NAME=${L_REGKEY[$i]}
		test_log "Deleting key ${L_REGKEY_NAME}..."
		test_delete_reg_key ${G_REGKEY} ${L_REGKEY_NAME} &
		L_C_PID[$i]=$!
		test_log "Started subprocess for deletion of ${L_REGKEY_NAME}: PID=${L_C_PID[$i]}"
	done


	for i in $(seq 1 ${L_NUM}) ; do
		wait ${L_C_PID[$i]}
		local L_RC[$i]=$?
	done

	for i in $(seq 1 ${L_NUM}) ; do
		local L_REGKEY_NAME="${L_REGKEY[$i]}"
		if [ ${L_RC[$i]} -ne 0 ]; then
			test_log "Error deleting key ${L_REGKEY_NAME} (PID=${L_C_PID[$i]}). EXIT"
			exit 1
		fi
		test_log "Deleting key ${L_REGKEY_NAME} succeeded (PID=${L_C_PID[$i]})"
	done

	test_log "All OK!"

	test_log "Removing ${G_LOG_FILE_BASE}.*"
	rm -f ${G_LOG_FILE_BASE}.*
}


COUNT=1

if [ "x$NUM_PARALLEL" = "x" ] ; then
	NUM_PARALLEL=8
fi

while true
do
	test_create_registry_keys_in_parallel ${COUNT} ${NUM_PARALLEL}
	COUNT=$((COUNT + 1))
done
