#!/bin/sh
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# SPDX-FileCopyrightText: 2017-2026 KUNBUS GmbH
#
# reset dtoverlay, password of user pi, machine-id, hostname, FQDN and
# MAC address of a RevPi to factory defaults

: ${DATADIR='/usr/share'}
: ${REVPI_DATADIR="$DATADIR"/revpi}
: ${SYSCONFDIR='/etc'}
: ${LIBDIR="$REVPI_DATADIR"}
: ${DEVINFODIR="$REVPI_DATADIR"/devinfo}

. "$LIBDIR"/revpi-functions

RPI_FW_MOUNT="$ROOT"/boot/firmware
HOSTNAME_PREFIX_FILE="$REVPI_DATADIR/hostname"
FULL_DEVICETYPE_LIST="compact|connect|core|flat|connect-se"	# all suported devices

HOSTNAME_PREFIX="RevPi"

usage() {
	cat <<- __EOF__
	Usage: revpi-factory-reset [-f]
	       revpi-factory-reset [-f] OVERLAY SERIAL_NR MAC_ADDR

	Calling revpi-factory-reset without any arguments is only permitted if the
	device it is called on is equipped with a HAT EEPROM.

	Options:
	  -f      Force run even if revpi-factory-reset already ran before
	__EOF__

	exit "$1"
}

_log() {
	typ="${1:-info}"
	shift

	msg=""
	prefix=""
	output=1

	case "$typ" in
		warn)
			output=2
			prefix="WARNING: "
			;;
		err)
			output=2
			prefix="ERROR: "
			;;
	esac

	msg="$(printf "%s%s\n" "$prefix" "$*")"
	printf "%s\n" "$msg" >&"$output"
	$MOCK logger --id=$$ -t "$(basename "$0")" -p local0."$typ" "$msg"
}

log_err() {
	_log err "$*"
}

log_warn() {
	_log warn "$*"
}

log_info() {
	_log info "$*"
}

die() {
	_log err "$*"
	exit 1
}

normalise_mac() {
	tr -d ':-' | tr '[[:upper:]]' '[[:lower:]]'
}

while getopts "fr:h" opt; do
	case "$opt" in
	f) FORCE=true ;;
	r) ROOT="$OPTARG" ;;
	h) usage 0 ;;
	?) usage 1 >&2 ;;
	esac
done
shift $((OPTIND-1))

if [ -z "$FORCE" ] \
	&& [ -r "$REVPI_DATADIR"/factory-reset ]; then
	log_info "revpi-factory-reset was already run on this device. Skipping."

	exit 0
fi

ovl="$1"
ser="$2"
mac="$(echo "$3" | normalise_mac)"

if has_hat_eeprom; then
	# Get the serial number from device tree according to document:
	# https://gitlab.com/revolutionpi/revpi-hat-eeprom/blob/master/docs/RevPi-HAT-EEPROM-Format.md#1-serial
	ser=$(cat "$ROOT"/proc/device-tree/hat/custom_1)
	mac=$(cat "$ROOT"/proc/device-tree/hat/custom_5 | normalise_mac)
else
	if [ "$#" != 3 ] ||
		! echo "$ovl" | grep -qEx "($FULL_DEVICETYPE_LIST)" ||
		! echo "$ser" | grep -qEx "[[:digit:]]+" ||
		! echo "$mac" | grep -qEx "[[:xdigit:]]{12}"; then
		log_err "$(basename "$0") must be called with all arguments because no HAT EEPROM is present"
		usage 1 >&2
	fi
fi

if [ -f "$HOSTNAME_PREFIX_FILE" ]; then
	log_info "Using custom hostname prefix from $HOSTNAME_PREFIX_FILE"
	HOSTNAME_PREFIX="$(head -n1 "$HOSTNAME_PREFIX_FILE")"

	if echo "$HOSTNAME_PREFIX" | grep -Eq "[[:space:]]"; then
		die "Hostname prefix '$HOSTNAME_PREFIX' contains invalid characters"
	fi
fi

log_info "Using hostname prefix '$HOSTNAME_PREFIX'"

if [ "$(id -u)" != 0 ] ; then
	die "This program requires root access"
fi

# clean up config.txt before doing anything else
if ! sed --follow-symlinks -ri \
	-e "/^dtoverlay=revpi-($FULL_DEVICETYPE_LIST)/d" \
	-e "/^dtparam=eth[0-9]_mac_/d" \
	"$RPI_FW_MOUNT/config.txt"; then
	die "Unable to clean up $RPI_FW_MOUNT/config.txt. Aborting."
fi

if ! has_hat_eeprom; then
	if ! echo "dtoverlay=revpi-$ovl" >> "$RPI_FW_MOUNT/config.txt"; then
		die "Unable to write device tree overlay to $RPI_FW_MOUNT/config.txt. Aborting."
	fi
	# load device tree overlay if it is not already loaded
	if ! grep -qz revpi-"$ovl" "$ROOT"/proc/device-tree/compatible \
		&& ! $MOCK dtoverlay "revpi-$ovl"; then
		die "Unable to load device tree overlay. Aborting."
	fi
	if ! cp "$RPI_FW_MOUNT/overlays/revpi-$ovl-dt-blob.dtbo" \
		"$RPI_FW_MOUNT/dt-blob.bin"; then
		die "Cannot initialise device tree blob. Aborting."
	fi

	if [ "$ovl" = flat ]; then
		# wait for dtoverlay revpi-flat, and tpm modules get probed
		wait_time=60
		i=0
		printf "Wait for tpm chip to become ready. Fail if the chip is not available after %d seconds" "$wait_time"
		while [ "$i" -le "$wait_time" ]; do
			if [ "$i" = "$wait_time" ]; then
				log_err "Timeout while waiting for the TPM chip to become ready"
				die "The factory reset is stopped here!"
			fi
			if [ -c /dev/tpm0 ]; then
				printf " ok\n"
				break
			fi
			printf "."
			sleep 1
			i=$((i+1))
		done
	fi

	log_info "Reboot to activate the MAC Address"
fi

if user_pi_exists; then
	pw="$(piSerial -p)"
	if ! echo "pi:${pw}" | chpasswd; then
		die "Unable to change password for user 'pi'. Aborting."
	fi
	printf "Password:\t%s\n" "$pw"
else
	log_warn "Cannot restore the default password, because the default user 'pi' is absent."
fi

hostname="$HOSTNAME_PREFIX$ser"
if ! sed --follow-symlinks -r -i \
	-e "s/^(127\.0\.1\.1[[:blank:]]+).*/\1$hostname/" \
	"$ROOT"/etc/hosts; then
	die "Unable to write to /etc/hosts. Aborting."
fi
if ! echo "$hostname" > "$ROOT"/etc/hostname; then
	die "Unable to change hostname. Aborting."
fi
if ! $MOCK hostname "$hostname"; then
	log_warn "Cannot activate hostname. A reboot is required."
fi
printf "Hostname:\t%s\n" "$hostname"

log_info "revpi-factory-reset successful!"
echo "Be sure to write down the password if you have lost the sticker"
echo "on your RevPi!"


# format mac address as 01:23:45:67:89:AB
mac=$(echo "$mac" | sed 's/\(..\)/\1:/g; s/:$//' | tr '[[:lower:]]' '[[:upper:]]')

# store device information
mkdir -p "$DEVINFODIR"
printf '%s' "$ser" > "$DEVINFODIR/serial-number"
printf '%s' "$mac" > "$DEVINFODIR/base-mac-address"

# skip /etc/profile.d/revpi-factory-reset.sh on future logins
true > "$REVPI_DATADIR/factory-reset"

# Remove sudoers rule for revpi-factory-reset.
# Allows passwordless execution only on first boot.
rm -f "$SYSCONFDIR/sudoers.d/051_revpi-factory-reset"
