#! /bin/bash

mknod /dev/ttyprintk c 5 3
echo "hello world" >/dev/ttyprintk

# Setup our path
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

# This is the very first script invoked by the Linux kernel and is
# running out of the ram disk.  There are no fileysstems mounted.
# It is important to have a way to invoke a recovery shell in case
# the boot scripts are messed up, but also important to modify the
# PCRs if this happens to prevent the TPM Disk Unlock Keys from being revealed.

# First thing it is vital to mount the /dev and other system directories
mkdir /proc /sys /dev /tmp /boot /media 2>&- 1>&-
mount /dev 2>/dev/ttyprintk
mount /proc 2>/dev/ttyprintk
mount /sys 2>/dev/ttyprintk

if [ "$CONFIG_LINUXBOOT" = "y" ]; then
	mount /sys/firmware/efi/efivars
fi

# Setup the pty pseudo filesystem
mkdir /dev/pts
mount /dev/pts 2>/dev/ttyprintk

if [ ! -r /dev/ptmx ]; then
	ln -s /dev/pts/ptmx /dev/ptmx
fi

# Needed by bash
[ -e /dev/stdin ] || ln -s /proc/self/fd/0 /dev/stdin
[ -e /dev/stdout ] || ln -s /proc/self/fd/1 /dev/stdout
[ -e /dev/stderr ] || ln -s /proc/self/fd/2 /dev/stderr
[ -e /dev/fd ] || ln -s /proc/self/fd /dev/fd

# Recovery shells will erase anything from here
mkdir -p /tmp/secret

# Now it is safe to print a banner
if [ -r /etc/motd ]; then
	cat /etc/motd >/dev/tty0
fi

# Load the date from the hardware clock, setting it in local time
hwclock -l -s

# When mounting a filesystem, try exFAT last, since it logs errors if the
# filesystem is not exFAT, and the errors go to the console.  Those errors are
# spurious when the medium is iso9660.  By default in our config, the only
# filesystem after exFAT is iso9660, move exFAT last.
(grep -v '^\texfat$' /proc/filesystems && echo -e '\texfat') >/etc/filesystems

# Read the system configuration parameters from build time board configuration
. /etc/config
# import global functions
. /etc/functions.sh

# export user related content from cbfs
if [ "$CONFIG_COREBOOT" = "y" ]; then
	/bin/cbfs-init.sh
fi

# Override CONFIG_USE_BLOB_JAIL if needed and persist via user config
if lspci -n | grep -E -q "8086:(2723|4df0)"; then
	if ! cat /etc/config.user 2>/dev/null | grep -q "USE_BLOB_JAIL"; then
		echo "CONFIG_USE_BLOB_JAIL=y" >>/etc/config.user
	fi
fi

# Override CONFIG_TPM and CONFIG_TPM2_TOOLS from /etc/config with runtime value
# determined above.
#
# Values in user config have higher priority during combining thus effectively
# changing the value for the rest of the scripts which source /tmp/config.

#Only set CONFIG_TPM and CONFIG_TPM2_TOOLS if they are not already set in /etc/config.user
if ! grep -q 'CONFIG_TPM=' /etc/config.user 2>/dev/null; then
	echo "export CONFIG_TPM=\"$CONFIG_TPM\"" >>/etc/config.user
fi
if ! grep -q 'CONFIG_TPM2_TOOLS=' /etc/config.user 2>/dev/null; then
	echo "export CONFIG_TPM2_TOOLS=\"$CONFIG_TPM2_TOOLS\"" >>/etc/config.user
fi

# CONFIG_BASIC was previously CONFIG_PUREBOOT_BASIC in the PureBoot distribution.
# Substitute it in config.user if present for backward compatibility.
sed -i -e 's/^export CONFIG_PUREBOOT_BASIC=/export CONFIG_BASIC=/g' /etc/config.user

# Combine user configuration overrides from CBFS's /etc/config.user
combine_configs
# Load the user configuration parameters from combined config
. /tmp/config

# Enable maximum debug info from here if config.user extracted and combined from CBFS had CONFIG_DEBUG_OUTPUT=y
if [ "$CONFIG_DEBUG_OUTPUT" = "y" ]; then
	#Output all kernel messages to console (8=debug)
	#DEBUG and TRACE calls will be in dmesg and on console
	# config.user extracted and combined from CBFS had CONFIG_DEBUG_OUTPUT=y
	# DO_WITH_DEBUG redirects stderr and stdout to /tmp/debug.log to not clog console	
	TRACE_FUNC
	dmesg -n 8
	DEBUG "Full debug output enabled from this point: output both in dmesg and on console (equivalent of passing debug to kernel cmdline)"
	DEBUG "NOTE: DO_WITH_DEBUG std_err and std_out will be redirected to /tmp/debug.log"
fi

# report if we are in quiet mode, tell user measurements logs available under /tmp/debug.log
if [ "$CONFIG_QUIET_MODE" = "y" ]; then
	# check origin of quiet mode setting =y: if it is under /etc/config.user then early cbfs-init outputs are not suppressible
	# if it is under /etc/config then early cbfs-init outputs are suppressible
	if grep -q 'CONFIG_QUIET_MODE="y"' /etc/config 2>/dev/null; then
		echo "Quiet mode enabled from board configuration: refer to '/tmp/debug.log' for boot measurements traces" >/dev/tty0
	else
		echo "Runtime applied Quiet mode: refer to '/tmp/debug.log' for additional boot measurements traces past this point" >/dev/tty0
		echo "To suppress earlier boot measurements traces, enable CONFIG_QUIET_MODE=y in your board configuration at build time." >/dev/tty0
	fi
# If CONFIG_QUIET_MODE enabled in board config but disabled from Config->Configuration Settings
# warn that early boot measurements output was suppressed prior of this point
elif [ "$CONFIG_QUIET_MODE" = "n" ]; then
	# if CONFIG_QUIET_MODE=n in /etc/config.user but CONFIG_QUIET_MODE=y in /etc/config then early cbfs-init outputs are suppressed
	# both needs to be checked to determine if early boot measurements traces were suppressed
	if grep -q 'CONFIG_QUIET_MODE="y"' /etc/config 2>/dev/null && grep -q 'CONFIG_QUIET_MODE="n"' /etc/config.user 2>/dev/null; then
		echo "Early boot measurements traces were suppressed per CONFIG_QUIET_MODE=y in your board configuration at build time (/etc/config)" >/dev/tty0
		echo "Runtime applied Quiet mode disabled: refer to '/tmp/debug.log' for cbfs-init related traces prior of this point" >/dev/tty0
	fi
fi

TRACE_FUNC

# make sure we have sysctl requirements
if [ ! -d /proc/sys ]; then
	warn "BUG!!! The following requirements to apply runtime kernel tweaks are missing:"
	warn "CONFIG_SYSCTL=y"
	warn "CONFIG_PROC_SYSCTL=y"
	warn "Please open an issue"
fi

if [ ! -e /proc/sys/vm/panic_on_oom ]; then
	warn "BUG!!! Requirements to setup Panic when under Out Of Memory situation through PROC_SYSCTL are missing (panic_on_oom was not enabled)"
	warn "Please open an issue"
else
	DEBUG "Applying panic_on_oom setting to sysctl"
	echo 1 >/proc/sys/vm/panic_on_oom
fi

# set CONFIG_TPM dynamically off before init if no TPM device is present
if [ ! -e /dev/tpm0 ]; then
	CONFIG_TPM='n'
	CONFIG_TPM2_TOOLS='n'
fi

#Specify whiptail background colors cues under FBWhiptail only
if [ -x /bin/fbwhiptail ]; then
	export BG_COLOR_WARNING="${CONFIG_WARNING_BG_COLOR:-"--background-gradient 0 0 0 150 125 0"}"
	export BG_COLOR_ERROR="${CONFIG_ERROR_BG_COLOR:-"--background-gradient 0 0 0 150 0 0"}"
	export BG_COLOR_MAIN_MENU="normal"
else
	export TEXT_BG_COLOR_WARNING="${CONFIG_WARNING_TEXT_BG_COLOR:-"yellow"}"
	export TEXT_BG_COLOR_ERROR="${CONFIG_ERROR_TEXT_BG_COLOR:-"red"}"
	export BG_COLOR_MAIN_MENU="normal"
fi

if [ "$CONFIG_TPM" = "y" ]; then
	# Initialize tpm2 encrypted sessions here
	tpmr.sh startsession
fi

if [ "$CONFIG_LINUXBOOT" = "y" ]; then
	# Initialize the UEFI environment for linuxboot boards
	/bin/uefi-init.sh
fi

# Set GPG_TTY before calling gpg in key-init
#TODO: do better then this; on dual console gpg only interacts with main console (affects Talos-2 and all whiptail variants)
export GPG_TTY=/dev/console

# Initialize gpnupg with distro/user keys and setup the keyrings
/bin/key-init.sh

# Setup recovery serial shell
if [ ! -z "$CONFIG_BOOT_RECOVERY_SERIAL" ]; then
	stty -F "$CONFIG_BOOT_RECOVERY_SERIAL" 115200
	pause_recovery 'Serial console recovery shell' \
		<"$CONFIG_BOOT_RECOVERY_SERIAL" \
		>"$CONFIG_BOOT_RECOVERY_SERIAL" 2>&1 &
fi

# load USB modules for boards using a USB keyboard
if [ "$CONFIG_USB_KEYBOARD_REQUIRED" = y ] || [ "$CONFIG_USER_USB_KEYBOARD" = "y" ]; then
	enable_usb
fi

# Set the keyboard keymap if defined, file exists, and loadkeys is available
load_keymap "$CONFIG_KEYBOARD_KEYMAP"

# If the user has been holding down r, enter a recovery shell
# otherwise immediately start the configured boot script.
# We don't print a prompt, since this is a near instant timeout.
read \
	-t 0.1 \
	-n 1 \
	boot_option
echo

if [ "$boot_option" = "r" ]; then
	# Start an interactive shell
	recovery 'User requested recovery shell'
	# just in case...
	exit
elif [ "$boot_option" = "o" ]; then
	# Launch OEM Factory Reset mode
	echo -e "***** Entering OEM Factory Reset mode\n" >/dev/tty0
	oem-factory-reset.sh --mode oem
	# just in case...
	exit
fi

if [ "$CONFIG_BASIC" = "y" ]; then
	echo -e "***** BASIC mode: tamper detection disabled\n" >/dev/tty0
fi

# export firmware version
export FW_VER=$(fw_version)
# export EC firmware version (DMI type 11 OEM string)
# `ec_version` returns an empty string if the field is missing.
export EC_VER=$(ec_version)

# Add our boot devices into the /etc/fstab, if they are defined
# in the configuration file.
if [ ! -z "$CONFIG_BOOT_DEV" ]; then
	echo >>/etc/fstab "$CONFIG_BOOT_DEV /boot auto defaults,ro 0 0"
fi

# Set the console font if needed
setconsolefont.sh

if [ "$CONFIG_BASIC" = "y" ]; then
	CONFIG_BOOTSCRIPT=/bin/gui-init-basic.sh
	export CONFIG_HOTPKEY=n
fi

# Perform board-specific init if present
if [ -x /bin/board-init.sh ]; then
	/bin/board-init.sh
fi

if [ ! -x "$CONFIG_BOOTSCRIPT" -a ! -x "$CONFIG_BOOTSCRIPT_NETWORK" ]; then
	recovery 'Boot script missing?  Entering recovery shell'
else
	if [ -x "$CONFIG_BOOTSCRIPT_NETWORK" ]; then
		echo '***** Network Boot:' $CONFIG_BOOTSCRIPT_NETWORK
		$CONFIG_BOOTSCRIPT_NETWORK
		echo '***** Network Boot Completed:' $CONFIG_BOOTSCRIPT_NETWORK
		# not blocking
	fi

	if [ -x "$CONFIG_BOOTSCRIPT" ]; then
		echo '***** Normal boot:' $CONFIG_BOOTSCRIPT

		if [ -x /bin/setsid ] && [ -x /bin/agetty ]; then
			for console in $CONFIG_BOOT_EXTRA_TTYS; do
				setsid agetty -aroot -l"$CONFIG_BOOTSCRIPT" "$console" linux &
			done
		fi

		#Setup a control tty so that all terminals outputs correct tty when tty is called
		exec cttyhack "$CONFIG_BOOTSCRIPT"
	else
		# wait for boot via network to occur
		pause_recovery 'Override network boot. Entering recovery shell'
	fi
fi

# We should never reach here, but just in case...
recovery 'Boot script failure?  Entering recovery shell'
