#!/bin/bash
#
# Generate a isolinux/bios and efi ISO boot image

set -e
PATH=/usr/bin:/bin:/usr/sbin:/sbin

OUT=$1
BIOS=$2
EFI=$3

dir=$(mktemp -d $(dirname $OUT)/iso.dir.XXXXXX)
cfg=${dir}/isolinux.cfg

b=$(basename ${BIOS})
g=${b%.lkrn}
g=${g//[^a-z0-9]}
g=${g:0:8}.krn
# generate the config reproducibly
cat > ${cfg} <<EOF
# These default options can be changed in the geniso script
SAY iPXE ISO boot image
TIMEOUT 0
DEFAULT ${b}
LABEL ${b}
 KERNEL ${g}
EOF
touch --date="@$SOURCE_DATE_EPOCH" ${cfg}

# copy BIOS boot file reproducibly
cp ${BIOS} ${dir}/${g}
touch --date="@$SOURCE_DATE_EPOCH" ${dir}/${g}

# copy isolinux bootloader reproducibly
cp -p /usr/lib/ISOLINUX/isolinux.bin ${dir}
cp -p /usr/lib/syslinux/modules/bios/ldlinux.c32 ${dir}

# generate EFI boot image reproducibly
blocks=$((($(stat -c %s "$EFI") / 1024 + 55 + 1) / 32 * 32 ))
# use the first 32 bit of SOURCE_DATE_EPOCH as volume_id
volume_id=$(printf "%x" $(($SOURCE_DATE_EPOCH & 0xffffffff)))
mkfs.msdos -i $volume_id -C ${dir}/efi.img $blocks >/dev/null
mkdir -p ${dir}/efi/boot/
cp "$EFI" ${dir}/efi/boot/bootx64.efi
touch --date="@$SOURCE_DATE_EPOCH" ${dir}/efi ${dir}/efi/boot ${dir}/efi/boot/*
# mcopy considers locale and localtime when copying modification timestamps,
# make it reproducible 
LC_ALL=C TZ=UTC mcopy -s -m -i ${dir}/efi.img ${dir}/efi ::
rm -rf ${dir}/efi/
touch --date="@$SOURCE_DATE_EPOCH" ${dir}/efi.img

# make top directory reproducible
touch --date="@$SOURCE_DATE_EPOCH" ${dir}

# generate the iso image
xorriso -as mkisofs \
	-r -J -preparer "iPXE build system" \
	-appid "iPXE ${VERSION} - Open Source Network Boot Firmware" \
	-publisher "https://ipxe.org/" \
	-b isolinux.bin -c boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table \
	-eltorito-alt-boot --efi-boot efi.img -no-emul-boot \
	-output ${OUT} ${dir}

# make it bootable as a CD-ROM or as a HD, reproducibly
# create mbr_id from volume_id toggling its first bit
mbr_id=$(printf "0x%x" $((0x$volume_id ^ 1)))
isohybrid -i $mbr_id  ${OUT}

# clean up temporary dir
rm -fr ${dir}
