#!/bin/sh

# privilege-checker-integrity
#
# Integrity check and recovery for the read-write privilege-checker databases
# (.policy.db, .privacy.db). Each database is checked with sqlite3's
# integrity_check pragma and, when corrupted or missing, restored from its
# backup copy by the matching updater script.
#
# Run at boot by privilege-checker-integrity.service, or manually with either
#     /usr/share/privilege-manager/privilege-checker-integrity
#     systemctl start privilege-checker-integrity.service

PATH=/bin:/usr/bin:/sbin:/usr/sbin

. /etc/tizen-platform.conf

PRIVILEGE_DB_DIR=${TZ_SYS_RO_SHARE}/privilege-manager

POLICY_DB=${TZ_SYS_DB}/.policy.db
POLICY_UPDATER=${PRIVILEGE_DB_DIR}/policy_db_updater.sh

PRIVACY_DB=${TZ_SYS_DB}/.privacy.db
PRIVACY_UPDATER=${PRIVILEGE_DB_DIR}/privacy_db_updater.sh

LOG_TAG=PRIVILEGE_CHECKER_INTEGRITY

logsend() {
	# Send a dlog message. dlog is not up yet this early in the boot, so a
	# failed log must neither abort the check nor pollute the output with
	# dlogsend's error message. The printed copy still reaches the journal.
	dlogsend -p "$1" -t "$LOG_TAG" "$2" 2>/dev/null || true

	if [ "$1" = Error ]; then
		echo "[ERROR] $2"
	else
		echo "$2"
	fi
}

# checkIntegrity <db>
# Prints the reason when the database is not usable.
checkIntegrity() {
	if [ ! -e "$1" ]; then
		echo "database does not exist"
		return 1
	fi

	check_result="`sqlite3 "$1" "pragma integrity_check" 2>&1`"
	if [ "$check_result" = "ok" ]; then
		return 0
	fi

	echo "$check_result"
	return 1
}

# verifyDb <db> <updater>
# Returns 0 when the database is intact, 2 when it was restored, 1 on failure.
verifyDb() {
	reason="`checkIntegrity "$1"`"
	if [ $? -eq 0 ]; then
		logsend Info "Integrity check of $1 passed"
		return 0
	fi

	logsend Error "Integrity check of $1 failed: $reason"

	# Keep the damaged database for investigation.
	if [ -e "$1" ]; then
		if cp "$1" "$1-failed"; then
			logsend Info "Damaged $1 kept as $1-failed"
		else
			logsend Error "Could not keep a copy of damaged $1"
		fi
	fi

    # Check if given updater script is executable
	if [ ! -x "$2" ]; then
		logsend Error "Cannot restore $1: $2 is not executable"
		return 1
	fi

	if ! "$2" --restore; then
		logsend Error "Restoring $1 failed"
		return 1
	fi

	logsend Info "Restored $1 from its backup"
	return 2
}

logsend Info "Starting integrity check of the read-write databases"

rst=0
verifyDb "$POLICY_DB" "$POLICY_UPDATER"
if [ $? -eq 1 ]; then
	rst=1
fi

verifyDb "$PRIVACY_DB" "$PRIVACY_UPDATER"
if [ $? -eq 1 ]; then
	rst=1
fi

if [ "$rst" -eq 0 ]; then
	logsend Info "Integrity check finished"
else
	logsend Error "Integrity check finished with errors"
fi

exit $rst
