#!/bin/bash -ue

<< MIT-LICENSE
Copyright (c) 2023 Jianjun Liu<jianjunliu@126.com> https://www.pkglinux.top

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
MIT-LICENSE

PKGLINUX_MAKEISO_VERBOSE=""
PKGLINUX_MAKEISO_TAG="std"
PKGLINUX_MAKEISO_KVER="$(uname -r)"
PKGLINUX_MAKEISO_PREFIX="2022Q2"
PKGLINUX_MAKEISO_ARCH="$(uname -m)"
PKGLINUX_MAKEISO_REPO="https://repos.pkglinux.top/dist/$PKGLINUX_MAKEISO_ARCH/packages.$PKGLINUX_MAKEISO_PREFIX/All"
PKGLINUX_MAKEISO_REPO_ROOT="$(dirname $(dirname $PKGLINUX_MAKEISO_REPO))/iso"
curl --head --silent --fail -k "$PKGLINUX_MAKEISO_REPO_ROOT/LATEST.txt" 2>&1> /dev/null &&
PKGLINUX_MAKEISO_PREFIX="$(curl -sk "$PKGLINUX_MAKEISO_REPO_ROOT/LATEST.txt" | grep -v "^#" | cut -f1 | tail -1)"
[ -L /pkg ] && [ -d /pkg ] && PKGLINUX_MAKEISO_PREFIX="$(readlink /pkg)"
PKGLINUX_MAKEISO_CONF="/$PKGLINUX_MAKEISO_PREFIX/etc/pkgin/repositories.conf"
[ -f "$PKGLINUX_MAKEISO_CONF" ] && PKGLINUX_MAKEISO_REPO=$(grep -v -e "^#" -e "^$" "$PKGLINUX_MAKEISO_CONF")
PKGLINUX_MAKEISO_WAIT="2"
PKGLINUX_MAKEISO_LEVEL="1"
PKGLINUX_MAKEISO_FORCE=false

pkglinux-makeiso-usage()
{
	# Display Help
	echo "Create ISO-9660 file or write it to usb device."
	echo
	echo "Syntax: $0 [ -h|v|V|p|t|w|l|f ] [ --help|verbose|version|prefix|arch|tag|wait|rootwait|rootdelay|level|force ] [ usbdev ]"
	echo "options:"
	echo "h     Print this help."
	echo "v     Verbose mode."
	echo "V     Print software version and exit."
	echo "p     Set new prefix."
	echo "m     Set new machine architecture."
	echo "t     Sub tag name for target iso file."
	echo "w     Seconds of rootdelay/rootwait."
	echo "l     iso-level (default 1)."
	echo "f     Confirm to zap target file or device"
	echo
}

PKGLINUX_MAKEISO_ARGS="$@"
echo Starting $0 $@

for arg in "$@"; do
	shift
	case "$arg" in
		"--help")	set -- "$@" "-h" ;;
		"--verbose")	set -- "$@" "-v" ;;
		"--version")	set -- "$@" "-V" ;;
		"--prefix")	set -- "$@" "-p" ;;
		"--arch")	set -- "$@" "-m" ;;
		"--tag")	set -- "$@" "-t" ;;
		"--wait")	set -- "$@" "-w" ;;
		"--rootwait")	set -- "$@" "-w" ;;
		"--rootdelay")	set -- "$@" "-w" ;;
		"--level")	set -- "$@" "-l" ;;
		"--force")	set -- "$@" "-f" ;;
		*)		set -- "$@" "$arg"
	esac
done

while getopts ':hvVp:m:t:w:l:f' OPTION; do
	case "$OPTION" in
		h)	# display usage
			pkglinux-makeiso-usage
			exit;;
		v)	# verbose mode
			PKGLINUX_MAKEISO_VERBOSE="-v"
			;;
		V)	# display version
			echo "2023.12"	
			exit;;
		p)	# set new prefix
			PKGLINUX_MAKEISO_PREFIX="$OPTARG"
			;;
		m)	# set new machine architeture
			PKGLINUX_MAKEISO_ARCH="$OPTARG"
			;;
		t)	# subtag other than "min", like "gnome","kde", or "gnome+kde"
			PKGLINUX_MAKEISO_TAG="$OPTARG" ;;
		w)	# seconds of rootdelay/rootwait
			PKGLINUX_MAKEISO_WAIT="$OPTARG" ;;
		l)	# iso-level other than 1, like 3.
			PKGLINUX_MAKEISO_LEVEL="$OPTARG" ;;
		f)	# force to zap?
			PKGLINUX_MAKEISO_FORCE=true ;;
		\?)	# Invalid option
			echo "Error: Invalid option: -$OPTARG"
			exit 1 ;;
		:)	# Missing argument
			echo "Error: Option -$OPTARG requires an argument."
			exit 1 ;;
	esac
done

shift "$(($OPTIND -1))"

[ "$#" -gt 1 ] && pkglinux-makeiso-usage && exit 1;

[ ${UID} -ne 0 ] && echo "$0 will not be performed when not running as root" && exit 1;

[ "${PKGLINUX_MAKEISO_PREFIX^^}" = "LATEST" ] &&
curl --head --silent --fail -k "$PKGLINUX_MAKEISO_REPO_ROOT/LATEST.txt" 2>&1> /dev/null &&
PKGLINUX_MAKEISO_PREFIX="$(curl -sk "$PKGLINUX_MAKEISO_REPO_ROOT/LATEST.txt" | grep -v "^#" | cut -f1 | tail -1)"
PKGLINUX_MAKEISO_REPO_ROOT="$(dirname $(dirname $PKGLINUX_MAKEISO_REPO))/iso"

if [[ "$PKGLINUX_MAKEISO_PREFIX" =~ 20[2-9][0-9]Q[1-4] ]]; then
  if curl --head --silent --fail -k "$PKGLINUX_MAKEISO_REPO_ROOT/LATEST.txt" 2>&1> /dev/null; then
    if [ -n "$(curl -sk "$PKGLINUX_MAKEISO_REPO_ROOT/LATEST.txt" | \
	    grep -v "^#" | cut -f1 | grep $PKGLINUX_MAKEISO_PREFIX)" ]; then
      echo "Found $PKGLINUX_MAKEISO_PREFIX in $PKGLINUX_MAKEISO_REPO_ROOT/LATEST.txt"
    else
      echo "$PKGLINUX_MAKEISO_PREFIX is invalid as it's not in $PKGLINUX_MAKEISO_REPO_ROOT/LATEST.txt"
      exit 1
    fi
   fi
else
  echo "$PKGLINUX_MAKEISO_PREFIX is not a valid prefix."
  exit 1
fi

case "$PKGLINUX_MAKEISO_TAG" in
	min)		;;
	std)		;;
	gnome)		;;
	kde)		;;
	kde+gnome)	;;
	*)		#
  if curl --head --silent --fail -k "$PKGLINUX_MAKEISO_REPO_ROOT/TAGS.txt" 2>&1> /dev/null; then
    if [ -n "$(curl -sk "$PKGLINUX_MAKEISO_REPO_ROOT/TAGS.txt" | \
	    grep -v "^#" | cut -f1 | grep $PKGLINUX_MAKEISO_TAG)" ]; then
      echo "Found $PKGLINUX_MAKEISO_TAG in $PKGLINUX_MAKEISO_REPO_ROOT/TAGS.txt"
    else
      echo "$PKGLINUX_MAKEISO_TAG is invalid as it's not in $PKGLINUX_MAKEISO_REPO_ROOT/TAGS.txt"
      exit 1
    fi
  else
    echo "$PKGLINUX_MAKEISO_REPO_ROOT/TAGS.txt is not available. Network problem?"
    echo "Couldn't validate the tag $PKGLINUX_MAKEISO_TAG"
    exit 1
  fi
			;;
esac

PKGLINUX_MAKEISO_CONF="/$PKGLINUX_MAKEISO_PREFIX/etc/pkgin/repositories.conf"

[ -f "$PKGLINUX_MAKEISO_CONF" ] && PKGLINUX_MAKEISO_REPO=$(grep -v -e "^#" -e "^$" "$PKGLINUX_MAKEISO_CONF")
PKGLINUX_MAKEISO_REPO_ROOT="$(dirname $(dirname $PKGLINUX_MAKEISO_REPO))/iso"
PKGLINUX_MAKEISO_FILE="pkglinux-$PKGLINUX_MAKEISO_PREFIX-$PKGLINUX_MAKEISO_ARCH-$PKGLINUX_MAKEISO_TAG.iso"
PKGLINUX_MAKEISO_SFSFILE="pkglinux-$PKGLINUX_MAKEISO_PREFIX-$PKGLINUX_MAKEISO_TAG.sfs"

if [ "$#" -gt 0 ]; then
  [[ "$1" == "/dev/"* ]] || { echo "$1 is not a device."; exit 1; }
  [ "$(lsblk -ndo tran $1)" = "usb" ] || { echo "$1 is not a usb device."; exit 1; }
  $PKGLINUX_MAKEISO_FORCE || {
    echo "Confirm to zap all data on $1 please use --force or -f. Please retype the command:"
    echo "$0 --force $PKGLINUX_MAKEISO_ARGS"
    echo "$0 -f $PKGLINUX_MAKEISO_ARGS"
    exit 1
  }

  if [ -f ${PKGLINUX_MAKEISO_FILE} ]; then
    echo "$PKGLINUX_MAKEISO_FILE exists in the current directory."
    echo "Writting $PKGLINUX_MAKEISO_FILE to the USB device $1 ..."
    cat "${PKGLINUX_MAKEISO_FILE}" | dd bs=1M of=$1
  elif curl --head --silent --fail -k "$PKGLINUX_MAKEISO_REPO_ROOT/$PKGLINUX_MAKEISO_FILE" 2>&1> /dev/null; then
    echo "$PKGLINUX_MAKEISO_FILE doesn't exist in the current directory."
    echo "$PKGLINUX_MAKEISO_REPO_ROOT/$PKGLINUX_MAKEISO_FILE is available."
    echo "Copying $PKGLINUX_MAKEISO_REPO_ROOT/$PKGLINUX_MAKEISO_FILE to the USB device $1 ..."
    curl -k "${PKGLINUX_MAKEISO_REPO_ROOT}/${PKGLINUX_MAKEISO_FILE}" | dd bs=1M of=$1
  elif [ -f ${PKGLINUX_MAKEISO_SFSFILE} ]; then
    echo "$PKGLINUX_MAKEISO_FILE doesn't exist in the current directory."
    echo "$PKGLINUX_MAKEISO_REPO_ROOT/$PKGLINUX_MAKEISO_FILE is not available either."
    echo "Most likely $PKGLINUX_MAKEISO_PREFIX is not the latest one."
    echo "However, $PKGLINUX_MAKEISO_SFSFILE is found in the current directory."
    echo "With this file existing, a $PKGLINUX_MAKEISO_FILE file can easiy be created quickly."
    echo "Retype the same $0 command and flags without specifying usbdev as the last arguments."
    exit 0
  elif curl -k --head --silent --fail "$PKGLINUX_MAKEISO_REPO_ROOT/$PKGLINUX_MAKEISO_SFSFILE" 2>&1> /dev/null; then
    echo "$PKGLINUX_MAKEISO_FILE doesn't exist in the current directory."
    echo "$PKGLINUX_MAKEISO_REPO_ROOT/$PKGLINUX_MAKEISO_FILE is not available either."
    echo "Most likely $PKGLINUX_MAKEISO_PREFIX is not the latest one."
    echo "$PKGLINUX_MAKEISO_SFSFILE is not found in the current directory."
    echo "However, $PKGLINUX_MAKEISO_REPO_ROOT/$PKGLINUX_MAKEISO_SFSFILE is available."
    echo "With this file being available, a $PKGLINUX_MAKEISO_FILE file can easiy be created locally."
    echo "Retype the same $0 command and flags without specifying usbdev as the last arguments."
    exit 0
  else
    echo "$PKGLINUX_MAKEISO_FILE doesn't exist in the current directory."
    echo "$PKGLINUX_MAKEISO_REPO_ROOT/$PKGLINUX_MAKEISO_FILE is not available either."
    echo "Most likely $PKGLINUX_MAKEISO_PREFIX is not the latest one."
    echo "$PKGLINUX_MAKEISO_SFSFILE is not found in the current directory."
    echo "Weird! $PKGLINUX_MAKEISO_REPO_ROOT/$PKGLINUX_MAKEISO_SFSFILE is NOT available."
    echo "Most likely there is a network problem."
    exit 1
  fi
  echo "Syncing disks ..."
  sync
  echo "It's safe to plug off your usb stick."
  exit 0
fi

$PKGLINUX_MAKEISO_FORCE && rm $PKGLINUX_MAKEISO_VERBOSE -f $PKGLINUX_MAKEISO_FILE
[ -e ${PKGLINUX_MAKEISO_FILE} ] && { echo "$PKGLINUX_MAKEISO_FILE exists." && exit 1; }

PKGLINUX_MAKEISO_SFSID="$(tr -dc 'A-F0-9' < /dev/urandom | head -c32)"
PKGLINUX_MAKEISO_ISOID="PKGLINUX-$PKGLINUX_MAKEISO_PREFIX"-"${PKGLINUX_MAKEISO_TAG::4}"
PKGLINUX_MAKEISO_ISOID="$PKGLINUX_MAKEISO_ISOID"-"$(tr -dc 'A-F0-9' < /dev/urandom | head -c11)"
PKGLINUX_MAKEISO_TMPDIR="/root/pkglinux-makeiso.tmp.d"
rm $PKGLINUX_MAKEISO_VERBOSE -rf $PKGLINUX_MAKEISO_TMPDIR
mkdir $PKGLINUX_MAKEISO_VERBOSE -p $PKGLINUX_MAKEISO_TMPDIR

mkdir $PKGLINUX_MAKEISO_VERBOSE -p $PKGLINUX_MAKEISO_TMPDIR/boot/{syslinux,$(uname -m)}
touch $PKGLINUX_MAKEISO_TMPDIR/boot/$PKGLINUX_MAKEISO_ISOID
find /usr/share/syslinux/ -maxdepth 1 -type f | xargs -I {} cp $PKGLINUX_MAKEISO_VERBOSE {} $PKGLINUX_MAKEISO_TMPDIR/boot/syslinux

mkdir $PKGLINUX_MAKEISO_VERBOSE -p $PKGLINUX_MAKEISO_TMPDIR/$PKGLINUX_MAKEISO_SFSID
if [ -f ${PKGLINUX_MAKEISO_SFSFILE} ]; then
  echo "Copying $PKGLINUX_MAKEISO_SFSFILE to pkglinux.sfs ..."
  cp $PKGLINUX_MAKEISO_VERBOSE ${PKGLINUX_MAKEISO_SFSFILE} $PKGLINUX_MAKEISO_TMPDIR/$PKGLINUX_MAKEISO_SFSID/pkglinux.sfs
else
  echo "Copying $PKGLINUX_MAKEISO_REPO_ROOT/$PKGLINUX_MAKEISO_SFSFILE to $PKGLINUX_MAKEISO_TMPDIR/$PKGLINUX_MAKEISO_SFSID/pkglinux.sfs"
  curl -k "${PKGLINUX_MAKEISO_REPO_ROOT}/${PKGLINUX_MAKEISO_SFSFILE}" > $PKGLINUX_MAKEISO_TMPDIR/$PKGLINUX_MAKEISO_SFSID/pkglinux.sfs
fi

PKGLINUX_MAKEISO_SFSFILE="$PKGLINUX_MAKEISO_TMPDIR/$PKGLINUX_MAKEISO_SFSID/pkglinux.sfs"
[ -f ${PKGLINUX_MAKEISO_SFSFILE} ] || { echo "Missing ${PKGLINUX_MAKEISO_SFSFILE}." && exit 1; }

PKGLINUX_MAKEISO_VMLINUZ=$(unsquashfs -l $PKGLINUX_MAKEISO_SFSFILE $PKGLINUX_MAKEISO_PREFIX/native/boot/vmlinuz-* | grep vmlinuz | cut -c 15-)
PKGLINUX_MAKEISO_KDIR=$(dirname $PKGLINUX_MAKEISO_VMLINUZ)
PKGLINUX_MAKEISO_KVER=$(basename $PKGLINUX_MAKEISO_VMLINUZ | cut -d'-' -f 2)
unsquashfs -cat $PKGLINUX_MAKEISO_SFSFILE $PKGLINUX_MAKEISO_VMLINUZ > $PKGLINUX_MAKEISO_TMPDIR/boot/$(uname -m)/vmlinuz
unsquashfs -cat $PKGLINUX_MAKEISO_SFSFILE $PKGLINUX_MAKEISO_KDIR/initramfs-$PKGLINUX_MAKEISO_KVER > $PKGLINUX_MAKEISO_TMPDIR/boot/$(uname -m)/initram.fs
unsquashfs -cat $PKGLINUX_MAKEISO_SFSFILE $PKGLINUX_MAKEISO_KDIR/native-linux-kernel-$PKGLINUX_MAKEISO_KVER.config > $PKGLINUX_MAKEISO_TMPDIR/boot/$(uname -m)/config

cat << EOF > "$PKGLINUX_MAKEISO_TMPDIR/boot/syslinux/syslinux.cfg"
SERIAL 0
PROMPT 1
TIMEOUT 50
DEFAULT pkglinux

SAY
SAY   ##################################################################
SAY   #                                                                #
SAY   #  Press <ENTER> to boot pkgLinux-$PKGLINUX_MAKEISO_PREFIX or wait 5 seconds.      #
SAY   #                                                                #
SAY   #  Press <TAB> to view available boot entries or enter Syslinux  #
SAY   #  commands directly.                                            #
SAY   #                                                                #
SAY   ##################################################################
SAY

LABEL pkglinux
	LINUX  /boot/x86_64/vmlinuz
	APPEND tpm_tis.interrupts=0 acpi=0 sfs=$PKGLINUX_MAKEISO_SFSID root=LABEL=$PKGLINUX_MAKEISO_ISOID rootdelay=$PKGLINUX_MAKEISO_WAIT
	INITRD /boot/x86_64/initram.fs

LABEL rescue
	LINUX  /boot/x86_64/vmlinuz
	APPEND single root=LABEL=$PKGLINUX_MAKEISO_ISOID rootdelay=$PKGLINUX_MAKEISO_WAIT
	INITRD /boot/x86_64/initram.fs
EOF

mkdir $PKGLINUX_MAKEISO_VERBOSE -p "$PKGLINUX_MAKEISO_TMPDIR/boot/grub"
cat << EOF > "$PKGLINUX_MAKEISO_TMPDIR/boot/grub/grub.cfg"
# Begin /boot/grub/grub.cfg
set default=0
set timeout=5

#insmod ext2
#insmod ext4
#set root=(hd0,1)

insmod part_msdos
insmod fat
insmod iso9660
insmod search
insmod probe

search --no-floppy --set=__ISOROOT_ --file '/boot/$PKGLINUX_MAKEISO_ISOID'
probe --set __ISO_UUID --fs-uuid "\${__ISOROOT}"

menuentry "pkgLinux / KERNEL $PKGLINUX_MAKEISO_KVER" {
#	linux   /boot/x86_64/vmlinuz sfs root=UUID=\${__ISO_UUID} rootdelay=$PKGLINUX_MAKEISO_WAIT
	linux   /boot/x86_64/vmlinuz sfs=$PKGLINUX_MAKEISO_SFSID root=LABEL=$PKGLINUX_MAKEISO_ISOID rootdelay=$PKGLINUX_MAKEISO_WAIT
	initrd  /boot/x86_64/initram.fs
}
menuentry "pkgLinux / KERNEL $PKGLINUX_MAKEISO_KVER (RESCUE mode)" {
#	linux   /boot/x86_64/vmlinuz single root=UUID=\${__ISO_UUID} rootdelay=$PKGLINUX_MAKEISO_WAIT
	linux   /boot/x86_64/vmlinuz single root=LABEL=$PKGLINUX_MAKEISO_ISOID rootdelay=$PKGLINUX_MAKEISO_WAIT
	initrd  /boot/x86_64/initram.fs
}
EOF

PKGLINUX_MAKEISO_EFIIMG=$(mktemp)

grub-mkimage-efi $PKGLINUX_MAKEISO_VERBOSE -O x86_64-efi \
	-o "$PKGLINUX_MAKEISO_EFIIMG" \
	-p /boot/grub \
	efi_gop efi_uga boot linux search normal configfile part_gpt btrfs ext2 fat iso9660 loopback test keystatus gfxmenu regexp probe all_video gfxterm font echo read ls cat png jpeg halt reboot

export MTOOLS_SKIP_CHECK=1

mkfs.vfat -C "$PKGLINUX_MAKEISO_TMPDIR/efi.img" \
	$(($(wc -c < $PKGLINUX_MAKEISO_EFIIMG) / 1024 + 511))

mmd -i "$PKGLINUX_MAKEISO_TMPDIR/efi.img" \
	efi \
	efi/boot

	mcopy -i "$PKGLINUX_MAKEISO_TMPDIR/efi.img" \
	"$PKGLINUX_MAKEISO_EFIIMG" \
	::efi/boot/bootx64.efi

rm $PKGLINUX_MAKEISO_VERBOSE -f $PKGLINUX_MAKEISO_EFIIMG

rm $PKGLINUX_MAKEISO_VERBOSE -f $PKGLINUX_MAKEISO_FILE

xorriso -as mkisofs $PKGLINUX_MAKEISO_VERBOSE \
	-isohybrid-mbr /usr/share/syslinux/isohdpfx.bin \
	-b boot/syslinux/isolinux.bin \
	-c boot/syslinux/boot.cat \
	-no-emul-boot \
	-boot-load-size 4 \
	-boot-info-table \
	-V "$PKGLINUX_MAKEISO_ISOID" \
	-o "$PKGLINUX_MAKEISO_FILE" \
	-eltorito-alt-boot \
	-no-emul-boot \
	-e efi.img \
	-isohybrid-gpt-basdat \
	-iso-level $PKGLINUX_MAKEISO_LEVEL \
	$PKGLINUX_MAKEISO_TMPDIR

rm $PKGLINUX_MAKEISO_VERBOSE -rf $PKGLINUX_MAKEISO_TMPDIR
md5sum $PKGLINUX_MAKEISO_FILE > $PKGLINUX_MAKEISO_FILE.md5
$PKGLINUX_MAKEISO_FORCE && rm $PKGLINUX_MAKEISO_VERBOSE -f "$PKGLINUX_MAKEISO_FILE".zsync
zsyncmake -u $PKGLINUX_MAKEISO_FILE $PKGLINUX_MAKEISO_FILE


syntax highlighted by Code2HTML, v. 0.9.1