#!/bin/ash -efu
#
# mki-copy-efiboot
#
# This file is part of mkimage
# Copyright (C) 2007-2009  Alexey Gladkov <gladkov.alexey@gmail.com>
# Copyright (C) 2012       Michael Shigorin <mike@altlinux.org>
#
# This file is covered by the GNU General Public License,
# which should be included with mkimage as the file COPYING.
#

. "${0%/*}"/mki-sh-functions

verbose "has started executing."

pkgs="${PACKAGES_REQUIRED_COPY_EFIBOOT:-}"

[ -d "$chroot" ] ||
	fatal "$dir: does not look like a hasher work directory."

# should be a package name
[ -n "${EFI_BOOTLOADER:-}" ] ||
	fatal "EFI_BOOTLOADER is empty."

pkgs="$pkgs $EFI_BOOTLOADER"

# should be a package name
[ -z "${EFI_SHELL:-}" ] ||
	pkgs="$pkgs $EFI_SHELL"

[ -z "${EFI_CERT:-}" ] ||
	pkgs="$pkgs alt-uefi-certs shim-signed"

case "${EFI_BOOTLOADER:-}" in
refind)	# won't boot unsigned kernels in SB mode
	pkgs="$pkgs elilo"
	;;
esac

[ -z "${EFI_MEMTEST86:-}" ] ||
	pkgs="$pkgs $EFI_MEMTEST86"

mki-install $pkgs ||
	fatal "failed to install packages: $pkgs."

make_exec "$chroot/.host/efiboot.sh" <<EOF
#!/bin/sh -efu${verbose:+x}

cd /.image

fatal() { echo $*; exit 1; }

stage2=
for i in altinst live rescue; do
	if [ -f "\$i" ]; then
		stage2="\${stage2:+\$stage2 }\$i"
	fi
done
[ -n "\${stage2:-}" ] ||
	fatal "no stage2 image found."

efi=EFI
boot=\$efi/BOOT
cert=\$efi/enroll
tools=\$efi/tools
shell=shellx64.efi
mkdir $verbose -p -- \$boot

# nexthop name is hardwired into shim-0.2
if [ -n "${EFI_CERT:-}" ]; then
	shim_path=\$boot/bootx64.efi
	bin_path=\$boot/grubx64.efi
else
	shim_path=
	bin_path=\$boot/bootx64.efi
fi

bootparams() {
	[ -s "\$1" ] || return 0
	stage2_size="\$[ \$(stat -c%s \$1) / 1024 + 1 ]"
	echo "ramdisk_size=\$stage2_size stagename=\$1"
}

efi_bindir=/usr/lib64/efi

copy_shell() {
	dest="\$efi/\$shell"
	src="\$efi_bindir/shell.efi"
	[ ! -f "\$src" ] ||
		cp $verbose -pLf "\$src" "\$dest"
}

copy_mt86() {
	dest="\$tools"
	mkdir $verbose -p "\$dest"
	src="\$efi_bindir/memtest86.efi"
	if [ -f "\$src" ]; then
		cp $verbose -pLf "\$src" "\$dest/memtest86.efi" &&
		find /usr/share/efi-memtest86 -type f |
			xargs cp $verbose -pLft "\$dest"
	fi
}

purge_mt86() {
	(
	cd "\$tools" ||
		return 0

	if [ -s memtest86.efi ]; then
		rm $verbose -f memtest86.efi
		find /usr/share/efi-memtest86 -type f -printf '%f\n' |
			xargs rm $verbose -f
	fi
	)
}

copy_cert() {
	[ -n "${EFI_CERT:-}" ] ||
		return 0

	local keyfile="/etc/pki/uefi/${EFI_CERT:-}.cer"
	[ -s "\$keyfile" ] ||
		fatal "invalid \$keyfile"

	mkdir $verbose -p \$cert
	cp $verbose -pLft \$cert -- "\$keyfile"
}

copy_shim() {
	[ -n "\${shim_path:-}" ] ||
		return 0
	copy_cert
	cp $verbose -pLf \$efi_bindir/shim.efi \$shim_path
	cp $verbose -pLf \$efi_bindir/MokManager.efi \$boot
}

copy_kernel() {
	! [ -s \$boot/vmlinuz -a -s \$boot/full.cz ] ||
		return 0

	cp $verbose -lpLft \$boot -- syslinux/alt0/{vmlinuz,full.cz}
}

kargs="fastboot live lowmem showopts automatic=method:cdrom ${EFI_BOOTARGS:-}"

copy_elilo() {
	cp $verbose -pLf \$efi_bindir/elilo.efi \${1:-\$bin_path}
	cat > \$boot/elilo.conf <<- ELILO_EOF
	append="\$kargs"
	read-only
	image="vmlinuz"
	  label="linux"
	  initrd=full.cz
	ELILO_EOF
	[ "$EFI_BOOTLOADER" != elilo ] ||
		echo "  append=\"\$kargs stagename=\${stage2% *}\"" \
			>> \$boot/elilo.conf
}

add_langs() {
	cat <<- REFIND_EOF
	  submenuentry "English" {
	    add_options "lang=en_US"
	  }
	  submenuentry "Kazakh" {
	    add_options "lang=kk_KZ"
	  }
	  submenuentry "Russian" {
	    add_options "lang=ru_RU"
	  }
	  submenuentry "Ukrainian" {
	    add_options "lang=uk_UA"
	  }
	REFIND_EOF
}

add_forensic_mode() {
	[ -f rescue ] || return 0
	forensic_args="\$(sed -rn \
		's,^.* stagename=rescue (.*forensic hash=[0-9a-f]+)\$,\1,p' \
		syslinux/isolinux.cfg)"
	[ -n "\$forensic_args" ] || return 0

	cat <<- REFIND_EOF
	  submenuentry "Forensic mode (leave disks alone)" {
	    add_options "\$forensic_args"
	  }
	REFIND_EOF
}

add_stage2() {
	count="\`echo \$stage2 | wc -w\`"
	for root in \$stage2; do
		case "\$root" in
		altinst)
			splash="splash "
			label="Installation";;
		live)
			splash="splash "
			label="Live";;
		rescue)
			splash=
			label="Rescue";;
		*)
			label="\$root";;
		esac

		# provide differentiating boot target icons if needed
		icon="\$refind_icons/altlinux/\$root.icns"
		[ "\$count" -ne 1 -a -s "\$icon" ] ||
			icon="\$refind_icons/os_altlinux.icns"

		cat <<- REFIND_EOF

		# ELILO used as SB trampoline for unsigned kernels
		menuentry "ALT Linux \$label" {
		  icon /\$icon
		  loader /\$boot/elilo.efi
		  # NB: -v seems critical, otherwise we hit this:
		  #     gzip_x86_64: invalid exec_header
		  options "-v -i full.cz vmlinuz \`bootparams \$root\` \$splash"
		REFIND_EOF
		[ "\$root" = rescue ] && add_forensic_mode || add_langs
		echo "}"
	done
}

gfxprefix=/usr/share/gfxboot

add_banner() {
	local bgfile="\$refind_icons/bg.png"
	[ -d \$gfxprefix ] || return 0
	type -t convert >&/dev/null || return 0
	bootlogo="\`find \$gfxprefix -name bootlogo | tail -1\`"
	[ -s "\$bootlogo" ] || return 0
	if [ -s "\$bgfile" ] || cpio -i --quiet --to-stdout back.jpg \
		< "\$bootlogo" | convert - \$bgfile; then
		echo "banner /\$bgfile"
	fi
}

refind_aux=\$efi/refind
refind_boot=\$refind_aux/refind_x64.efi
refind_icons=\$refind_aux/icons
scan_icon=os_unknown.icns

# http://www.rodsbooks.com/refind/configfile.html
blacklist="shim.efi shim-fedora.efi PreLoader.efi TextMode.efi ebounce.efi GraphicsConsole.efi MokManager.efi HashTool.efi HashTool-signed.efi elilo.efi"

copy_refind() {
	copy_elilo \$boot/elilo.efi

	mkdir $verbose -p \$boot \$refind_aux
	cp $verbose -pLf \$efi_bindir/refind_x64.efi \$bin_path
	cp $verbose -lpf \$bin_path \$refind_boot

	cp $verbose -aLf \$efi_bindir/drivers_x64/ \$refind_aux
	cp $verbose -aLf /usr/share/refind/icons/ \$refind_aux

	mkdir $verbose -p \$boot/icons
	find \$refind_icons/ \
		-name 'func_*' -o -name 'tool_*' -o -name 'vol_*' \
		-o -name \$scan_icon |
		xargs -r cp $verbose -lpft \$boot/icons

	[ ! -d \$refind_aux/altlinux ] ||
		mv \$refind_aux/altlinux \$boot/icons

	# empty aux refind configuration makes it scan for loaders
	{
		echo "dont_scan_files \$blacklist"
		echo 'dont_scan_volumes "Recovery HD", LRS_ESP, "El Torito"'
		echo "textonly 1"
		echo "textmode 0"	# 80x25
		echo "timeout 0"
	} > \$refind_aux/refind.conf

	# overwrite the main configuration file
	{
		cat <<- REFIND_EOF
		timeout 20
		scanfor manual
		scan_driver_dirs /\$refind_aux/drivers_x64
		REFIND_EOF

		add_banner
		add_stage2

		cat <<- REFIND_EOF

		menuentry "others" {
		  icon /\$boot/icons/\$scan_icon
		  loader /\$refind_boot
		}
		REFIND_EOF
	} > \$boot/refind.conf
}

[ -z "${EFI_CERT:-}" ] ||
	copy_shim

case "$EFI_BOOTLOADER" in
elilo)
	copy_elilo;;
refind)
	copy_refind;;
*)
	fatal "Unable to handle '$EFI_BOOTLOADER'.";;
esac

copy_kernel	# seems to be unavoidable
copy_shell
copy_mt86

imgsize="\$[ \$(du -lsB32k \$efi | cut -f1) + 4 ]"
img=.efiboot.img

dd if=/dev/zero of=\$img bs=32k count="\$imgsize"
mkfs.vfat $verbose -n "El Torito" \$img

# put EFI shell into the FAT image's root (for firmware)...
if [ -f \$efi/\$shell ]; then
	mv $verbose \$efi/\$shell .
	mcopy $verbose \$shell -i \$img ::
fi

mcopy $verbose -i \$img -s \$efi ::

# use ISO9660 hardlinks support if possible
hardlink $verbose -c \$efi

# ...and finally into its ISO9660 location for refind
if [ -f \$shell ]; then
	mkdir $verbose -p \$tools
	mv $verbose \$shell \$tools
fi

mv \$img \$efi/

# eltorito copy is enough for flash as well, at least with refind-0.6.12.1
purge_mt86
EOF

rc=0
mki-run "/.host/efiboot.sh" || rc=$?
rm -f -- "$chroot/.host/efiboot.sh"
find "$chroot/.in" -mindepth 1 -maxdepth 1 -exec rm -rf -- '{}' '+'
exit $rc
