#! /bin/sh -e

# grub-mkconfig helper script.
#
# Copyright © 2009 Joaquim Boura <x-un-i@sapo.pt>
# Copyright © 2009-2024 Stefan Lippers-Hollmann <s.l-h@gmx.de>
# Copyright © 2011-2015 Niall Walsh <niallwalsh@celtux.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# source common grub2 functions
prefix=/usr
exec_prefix=${prefix}
bindir=${exec_prefix}/bin
libdir=${exec_prefix}/lib
. ${libdir}/grub/grub-mkconfig_lib

# override tool behaviour through /etc/default/grub2-suse-fromiso
if [ -r /etc/default/grub2-suse-fromiso ]; then
	. /etc/default/grub2-suse-fromiso 
fi

SUSE_GRUB2_ISO_LOCATION="${SUSE_GRUB2_ISO_LOCATION:-"/srv/ISO"}"
SUSE_GRUB2_ISO_PREFIX="${SUSE_GRUB2_ISO_PREFIX:-"openSUSE"}"
SUSE_GRUB2_LANG="${SUSE_GRUB2_LANG:-"en_EN.UTF8"}"
SUSE_GRUB2_TZ="${SUSE_GRUB2_TZ:-"UTC"}"
SUSE_GRUB2_CHEATCODE="${SUSE_GRUB2_CHEATCODE:-"splash=silent quiet systemd.show_status=yes"}"

# we need isoinfo, bail out if it's not available
ISOINFO="$(which isoinfo)"
if [ -z "${ISOINFO}" ]; then
	exit 1
fi

# find ISO
for location in $SUSE_GRUB2_ISO_LOCATION; do
	if [ -d "${location}" ]; then
		for prefix in $SUSE_GRUB2_ISO_PREFIX; do
			FROMISO="${FROMISO} $(find ${location} -maxdepth 1 -name ${prefix}\*.iso | sort -n)"
		done
	fi
done

# no iso found, quit
if [ -z "${FROMISO}" ]; then
	exit 0
fi

# assemble cmdline
CMDLINE="lang=${SUSE_GRUB2_LANG} ${SUSE_GRUB2_CHEATCODE} "

# create a temp device.map as the actual can be not uptodate
DEVICE_MAP_TMP=$(mktemp)
grub-mkdevicemap -m "${DEVICE_MAP_TMP}"

for iso_image in $FROMISO; do
	cur_device="$(grub-probe --device-map=${DEVICE_MAP_TMP} --target=device ${iso_image})"
	if [ "$(grub-probe -t abstraction --device ${cur_device} | sed -e 's,.*\(lvm\).*,\1,')" = "lvm" ]; then
		cur_fromhd="${cur_device}"
	else
		cur_fromhd="$(grub-probe --device-map=${DEVICE_MAP_TMP} --target=fs_uuid ${iso_image})"
		cur_fromhd_fs="$(/sbin/blkid -s TYPE -o value ${cur_device})"

		if [ "x${cur_fromhd_fs}" = "xmsdos" ] || [ "x${cur_fromhd_fs}" = "xntfs" ] || [ "x${cur_fromhd_fs}" = "xvfat" ]; then
			cur_fromhd="/dev/disk/by-uuid/$(/sbin/blkid -o value -s UUID ${cur_device})"
		else
			cur_fromhd="UUID=${cur_fromhd}"
		fi
	fi

	mountpoint=""
	subvolume=""
	while IFS=' ' read dev mount fs opts dump pass; do
		[ "$mount" = "/" ] && continue
		case $iso_image in
			$mount*)
			[ "$fs" = "btrfs" ] && subvolume=$(echo "$opts" | sed -n 's/.*subvol=\([^,]*\).*/\1/p')
			mountpoint="$mount"
			break
			;;
		esac
	done < /proc/mounts
	stripped_path="${subvolume}${iso_image##$mountpoint}"

	cdlabel="$( ${ISOINFO} -d -i ${iso_image} 2>/dev/null | awk '/^Volume id:/{print $3}' )"
	kernels="$( ( ${ISOINFO} -J -f -i ${iso_image} 2>/dev/null || ${ISOINFO} -R -f -i ${iso_image} 2>/dev/null || ${ISOINFO} -f -i ${iso_image} ) | sed -n -e 's|\;[0-9]*$||' -e 'y|ABCDEFGHIJKLMNOPQRSTUVWXYZ|abcdefghijklmnopqrstuvwxyz|' -e 's|/boot/\([a-z0-9_-]*\)/loader/linux|\1|p')"

	for kernel_arch in $kernels; do
		printf "menuentry \"$(basename ${iso_image} .iso) ($(${ISOINFO} -R -i ${iso_image} 2>/dev/null -x /boot/${kernel_arch}/loader/linux | file -b - | sed 's/.*version //;s/ .*//'))\" {\n"
		printf "\tinsmod iso9660\n"
		prepare_boot_cache="$(prepare_grub_to_access_device ${cur_device} | sed -e "s/^/\t/")"
		printf '%s\n' "${prepare_boot_cache}"

		cat << EOF
	loopback loop ${stripped_path}
	linux (loop)/boot/${kernel_arch}/loader/linux iso-scan/filename=${stripped_path} root=live:CDLABEL=${cdlabel} rd.live.image $CMDLINE
	initrd (loop)/boot/${kernel_arch}/loader/initrd
}
EOF
	echo "Found fromiso: $(basename ${iso_image}) on ${cur_device}" >&2
	done
done

rm -f "${DEVICE_MAP_TMP}"
