#!/bin/sh

alterator_api_version=1

. alterator-sh-functions
. shell-config
. grub-raid-boot
. grub-disk
. grub-bootable
. grub-md-list

# effects grub menu l18n
if [ -n "$in_language" ]; then
	LANG="$in_language"
else
	if [ -s /etc/sysconfig/i18n ]; then
		. /etc/sysconfig/i18n
	fi
fi

export LANG

arch="$(uname -m)"

efi_dir="/boot/efi"

pwconf=/etc/grub.d/50_password

errflag=
gruboutput=

make_gruboutput() {
	gruboutput="$(mktemp --tmpdir grub.XXXXXXXXXX 2>&1 ||:)"
	[ -n "$gruboutput" -a -f "$gruboutput" ] || {
		local msg="$(_ "Can't create tempfile ")"
		write_error "$msg$gruboutput!"
		return 1
	}
}

make_grubcfg() {
	if ! grub-mkconfig -o /boot/grub/grub.cfg > "$gruboutput" 2>&1; then
		local msg="$(_ "Can't create grub menu")"
		write_error "$msg: $(cat "$gruboutput")"
		return 1
	fi
	[ -f /_NEW_SYSTEM_ ] && cp -ab "$gruboutput" /tmp/grub.log ||:
}

backup_and_clear_nvram() {
	local mngr="$(command -v efibootmgr 2>/dev/null ||:)"
	[ -x "$mngr" ] || return 1

	local backup="/root/.install-log"
	if [ -d "/mnt/destination/$backup" ]; then
		backup="/mnt/destination/$backup"
	elif [ ! -d "$backup" ]; then
		return 1
	fi
	backup="$backup/NVRAM-$(date "+%Y%m%d").bak"
	[ -f "$backup" ] || (
		echo "# Boot variables:"
		"$mngr" -v ||:
		echo; echo "# Driver variables:"
		"$mngr" -v -r ||:
		echo; echo "# SysPrep variables:"
		"$mngr" -v -y ||:
	) > "$backup" 2>&1

	local bootnum=
	( "$mngr" |grep -E "^Boot[0-9A-F][0-9A-F][0-9A-F][0-9A-F]" |
	  while read bootnum backup; do
		"$mngr" -q -B -b "${bootnum:4:4}" ||:
	  done
	) >/dev/null 2>&1
}

grub_uefi() {
	grub-install --uefi-secure-boot --recheck "$@" \
			>> "$gruboutput" 2>&1 || errflag=1
}

turn_luks_crypto_on() {
	# when a root partition is chosen to be encrypted with LUKS
	# GRUB_ENABLE_CRYPTODISK should be enabled explicitly
	local crypto_luks_present=
	for slink in $(ls /dev/mapper/*_luks); do
		[ -L $slink ] && crypto_luks_present="y"
	done
	if [ "$crypto_luks_present" = "y" ]; then
		if ! grep "^GRUB_ENABLE_CRYPTODISK=" /etc/default/grub > /dev/null 2>&1; then
			echo "GRUB_ENABLE_CRYPTODISK=y" >> /etc/default/grub
		else
			sed -i "s|GRUB_ENABLE_CRYPTODISK=.*|GRUB_ENABLE_CRYPTODISK=y|" /etc/default/grub
		fi
	fi
}

write_efi() {
	make_gruboutput || return 1

	turn_luks_crypto_on

	errflag=0
	case "$1" in
	eficlearnvram)
		backup_and_clear_nvram && grub_uefi || {
			write_error "$(_ "Can't backup or/and clear NVRAM!")"
			return 1
		}
		;;
	efinonvram)
		grub_uefi --no-nvram
		;;
	efiremovable)
		grub_uefi --removable
		;;
	efi)	grub_uefi --force-extra-removable
		;;
	esac
	[ $errflag -eq 0 ] || {
		local msg="$(_ "Can't install grub into")"
		write_error "$msg $efi_dir: $(cat "$gruboutput")"
		return 1
	}

	make_grubcfg
}

change_passwd() {
	case "$in_passwd" in
	"#f")	del_passwd;;
	"#t")	check_passwds;;
	*)	write_error "`_ "Internal error"`";;
	esac
}

check_passwds() {
	if [ -z "$in_passwd_1" -a -z "$in_passwd_2" ]; then
		write_error "`_ "You should define a password for boot with options"`"
	elif [ "$in_passwd_1" != "$in_passwd_2" ]; then
		write_error "`_ "Passwords mismatch"`"
	else
		set_passwd
	fi
}

hash_passwd() {
	echo -e "$in_passwd_1\n$in_passwd_1" \
	| LANG=C grub-mkpasswd-pbkdf2 \
	| sed -rn 's,^.* (grub\.pbkdf2.*)$,\1,p'
}

set_passwd() {
	install -pm700 /dev/null $pwconf
	cat > $pwconf <<-EOF_CONF
	#!/bin/sh
	cat << EOF
	set superusers="boot"
	password_pbkdf2 boot `hash_passwd`
	EOF
	EOF_CONF
	grub-mkconfig -o /boot/grub/grub.cfg
}

del_passwd() {
	shred -u $pwconf
}

read_passwd_status() {
	[ -s $pwconf ] &&
		write_bool_param 'passwd' 'yes' ||
		write_bool_param 'passwd' 'no'
}

list_devices() {
	case "$arch" in
		ppc*)
			list_bootloader_places_ppc
			;;
		*)
			if [ -d "/sys/firmware/efi" -a -d "$efi_dir" ]; then
				write_enum_item "efi"           "$(_ 'EFI (recommended)')"
				write_enum_item "eficlearnvram" "$(_ 'EFI (clear NVRAM before)')"
				write_enum_item "efinonvram"    "$(_ 'EFI (disable write to NVRAM)')"
				write_enum_item "efiremovable"  "$(_ 'EFI (for removable device)')"
			fi
			list_bootloader_places
			write_enum_item "none" "$(_ "Skip bootloader install")"
	esac
}

write_device() {
	make_gruboutput || return 1

	# fallback: BIOS bootloader installation when booted in EFI mode
	if [ -d "/sys/firmware/efi" ]; then
		grep -q efivars /etc/modules || echo efivars >> /etc/modules
		target="--target=i386-pc"
	fi

	bootdev="$(readlink -e $1)"
	if [ -z "$bootdev" ]; then
		write_error "$(_ "No device for install given!")"
		return 1
	fi
	raid_members=$(grub_md_list "${bootdev#/dev/}" 2>/dev/null)
	[ -z "$raid_members" ] || bootdev=$raid_members
	#tout=`mktemp`
	GRUB_FORCE="no"
	GRUB_DEV=
	for dev in $bootdev; do
		GRUB_DEV="$(blockdev_get_symlink "$dev") $GRUB_DEV"
		case "$arch" in
			ppc*)
				# grub-install won't work with unclean
				# PReP partition.
				dd if=/dev/zero of="$dev" ||:
				;;
		esac

		turn_luks_crypto_on

		grub-install $target "$dev" >> "$gruboutput" 2>&1
		if [ $? -ne 0 ]; then
			local msg="$(_ "Can't install grub on ")"
			if grep blocklists "$gruboutput"; then
				GRUB_FORCE="yes"
				grub-install $target "$dev" --force >> "$gruboutput" 2>&1
				if [ $? -ne 0 ]; then
					local msg2="$(_ " even using blocklists :")"
					write_error "$msg$dev$msg2$(cat "$gruboutput")"
					return 1
				fi
			else
				write_error "$msg$dev :$(cat "$gruboutput")"
				return 1
			fi
		fi
		case "$arch" in
			ppc*)
				# Activate PReP partition.
				# set_bootable_flag() is useless and broken.
				local disk="$(partition_parent ${dev#/dev/})"
				local pnum="$(partition_num ${dev#/dev/})"
				if [ -n "$disk" ] && [ -n "$pnum" ]; then
					sfdisk -A /dev/"$disk" "$pnum"
				fi
				;;
			*)
				set_bootable_flag "$dev"
				;;
		esac
	done
	if ! grep "^GRUB_AUTOUPDATE_DEVICE=" /etc/sysconfig/grub2 > /dev/null 2>&1; then
		echo "GRUB_AUTOUPDATE_DEVICE='$GRUB_DEV'" >> /etc/sysconfig/grub2
	else
		sed -i "s|GRUB_AUTOUPDATE_DEVICE=.*|GRUB_AUTOUPDATE_DEVICE='$GRUB_DEV'|" /etc/sysconfig/grub2
	fi
	if ! grep "^GRUB_AUTOUPDATE_FORCE=" /etc/sysconfig/grub2 > /dev/null 2>&1; then
		echo "GRUB_AUTOUPDATE_FORCE='$GRUB_FORCE'" >> /etc/sysconfig/grub2
	else
		sed -i "s|GRUB_AUTOUPDATE_FORCE=.*|GRUB_AUTOUPDATE_FORCE='$GRUB_FORCE'|" /etc/sysconfig/grub2
	fi

	make_grubcfg
}

on_message() {
	case "$in_action" in
	list)
		case "$in__objects" in
		"devices") list_devices;;
		esac
		;;
	read)
		case "$in__objects" in
		"passwd")  read_passwd_status;;
		"devices") list_devices;;
		esac
		;;
	write)
		change_passwd
		case "$in_device" in
		"none")
			;;
		"efi"|"eficlearnvram"|"efinonvram"|"efiremovable")
			write_efi "$in_device"
			;;
		"configonly")
			make_gruboutput || return 1
			make_grubcfg
			;;
		*)
			write_device "$in_device" "$in_runhooks"
			;;
		esac
	esac
}

message_loop
