#!/bin/sh
# Copyright (c) 2017, 2018, 2022, 2023 Jonas 'Sortie' Termansen.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# tix-iso-bootconfig
# Generate hooks that configure the bootloader of releases iso images.

set -e

append_title="modified by $(id -un)@$(hostname)"
console=
default=
directory=
enable_append_title=true
enable_dhclient=
enable_gui=
enable_network_drivers=
enable_ntpd=
enable_src=
enable_sshd=
grub_serial=
kernel_options=
init_target=
liveconfig=
serial=
serial_console=
operand=1
random_seed=false
timeout=

dashdash=
previous_option=
for argument do
  if test -n "$previous_option"; then
    eval $previous_option=\$argument
    previous_option=
    continue
  fi

  case $argument in
  *=?*) parameter=$(expr "X$argument" : '[^=]*=\(.*\)' || true) ;;
  *=)   parameter= ;;
  *)    parameter=yes ;;
  esac

  case $dashdash$argument in
  --) dashdash=yes ;;
  --append-title=*) append_title=$parameter ;;
  --append-title) previous_option=append_title ;;
  --console=*) console=$parameter ;;
  --console) previous_option=console ;;
  --default=*) default=$parameter ;;
  --default) previous_option=default ;;
  --disable-append-title) enable_append_title=false ;;
  --disable-dhclient) enable_dhclient=false ;;
  --disable-gui) enable_gui=false ;;
  --disable-network-drivers) enable_network_drivers=false ;;
  --disable-ntpd) enable_ntpd=false ;;
  --disable-src) enable_src=false ;;
  --disable-sshd) enable_sshd=false ;;
  --enable-append-title) enable_append_title=true ;;
  --enable-dhclient) enable_dhclient=true ;;
  --enable-gui) enable_gui=true ;;
  --enable-network-drivers) enable_network_drivers=true ;;
  --enable-ntpd) enable_ntpd=true ;;
  --enable-src) enable_src=true ;;
  --enable-sshd) enable_sshd=true ;;
  --grub-serial=*) grub_serial=$parameter ;;
  --grub-serial) previous_option=grub_serial ;;
  --kernel-options=*) kernel_options=$parameter ;;
  --kernel-options) previous_option=kernel_options ;;
  --init-target=*) init_target=$parameter ;;
  --init-target) previous_option=init_target ;;
  --liveconfig=*) liveconfig=$parameter ;;
  --liveconfig) previous_option=liveconfig ;;
  --random-seed) random_seed=true ;;
  --serial=*) serial=$parameter ;;
  --serial) previous_option=serial ;;
  --serial-console=*) serial_console=$parameter ;;
  --serial-console) previous_option=serial_console ;;
  --timeout=*) timeout=$parameter ;;
  --timeout) previous_option=timeout ;;
  -*) echo "$0: unrecognized option $argument" >&2
      exit 1 ;;
  *)
    if [ $operand = 1 ]; then
      directory="$argument"
      operand=2
    else
      echo "$0: unexpected extra operand $argument" >&2
      exit 1
    fi
    ;;
  esac
done

if test -n "$previous_option"; then
  echo "$0: option '$argument' requires an argument" >&2
  exit 1
fi

if test -n "$serial"; then
  enable_gui=false
  console="$serial"
  grub_serial="$serial"
  serial_console="$serial"
fi

if test -z "$directory"; then
  echo "$0: No directory was specified" >&2
  exit 1
fi

human_size() {
  (export LC_ALL=C; du -bh -- "$1" 2>/dev/null || du -h -- "$1") |
  sed -E 's/^([^[:space:]]+).*/\1/'
}

print_enable_default() {
  if [ "$1" = true ]; then
    printf "enable_%s=--enable-%s\n" "$2" "$3"
  elif [ "$1" = false ]; then
    printf "enable_%s=--disable-%s\n" "$2" "$3"
  fi
}

print_enable_default_bool() {
  if [ "$1" = true ]; then
    printf "enable_%s=true\n" "$2"
  elif [ "$1" = false ]; then
    printf "enable_%s=false\n" "$2"
  fi
}

if $random_seed; then
  mkdir -p -- "$directory/boot"
  if which dd >/dev/null 2>/dev/null; then
    dd if=/dev/urandom of="$directory/boot/random.seed" bs=256 count=1 2>/dev/null
  elif which rw >/dev/null 2>/dev/null; then
    rw -i /dev/urandom -o "$directory/boot/random.seed" -c 256 -t
  else
    echo "$0: Neither dd(1) nor rw(1) are installed" >&2
    exit 1
  fi
fi

has_autoinstall=false
has_autoupgrade=false
if [ -n "$liveconfig" ]; then
  if [ -e "$liveconfig/etc/autoinstall.conf" ]; then
    has_autoinstall=true
  fi
  if [ -e "$liveconfig/etc/autoupgrade.conf" ]; then
    has_autoupgrade=true
  fi
  mkdir -p -- "$directory/boot"
  (cd "$liveconfig" && tar -c -f- -- *) > "$directory/boot/liveconfig.tar"
  rm -f -- "$directory/boot/liveconfig.tar.xz"
  xz -- "$directory/boot/liveconfig.tar"
fi

mkdir -p -- "$directory/boot/grub"
(if [ -e "$directory/boot/liveconfig.tar.xz" ]; then
   printf 'insmod xzio\n'
 fi
 if [ -n "$console" ]; then
   printf 'console="--console=%s"\n' "$console"
 fi
 if [ -n "$default" ]; then
   printf 'default="%s"\n' "$default"
 fi
 if [ -n "$serial_console" ]; then
   printf 'serial_console="--console=%s"\n' "$serial_console"
 fi
 if [ -n "$timeout" ]; then
   printf 'timeout="%s"\n' "$timeout"
 fi
 if $has_autoinstall; then
   echo "title_sysinstall='***AUTOMATIC INSTALLATION***'"
 fi
 if $has_autoupgrade; then
   echo "title_sysupgrade='***AUTOMATIC UPGRADE***'"
 fi
 print_enable_default_bool "$enable_dhclient" dhclient dhclient
 print_enable_default_bool "$enable_gui" gui gui
 print_enable_default "$enable_network_drivers" network_drivers network-drivers
 print_enable_default_bool "$enable_src" src src
 print_enable_default_bool "$enable_sshd" sshd sshd
 print_enable_default_bool "$enable_ntpd" ntpd ntpd
 if [ -n "$kernel_options" ]; then
   printf 'kernel_options="%s"\n' "$kernel_options"
 fi
 if $enable_append_title; then
   printf "base_menu_title=\"\$base_menu_title - \"'%s'\n" \
          "$(printf '%s\n' "$append_title" | sed "s/'/'\\\\''/g")"
 fi
 if [ -n "$grub_serial" ]; then
   device=$(expr "X$grub_serial" : 'Xcom\([0-9]\+\).*' || true)
   device=$(expr "$device" - 1 || true)
   settings=$(expr "X$grub_serial" : 'Xcom[0-9]\+,\([^,]*\)\(,.*\)\?' || true)
   speed=$(expr "X$settings" : 'X\([0-9]*\)[noe][5678]' || true)
   parity=$(expr "X$settings" : 'X[0-9]*\([noe]\)[5678]' || true)
   case "$parity" in n) parity=no;; o) parity=odd;; e) parity=even;; esac
   bits=$(expr "X$settings" : 'X[0-9]*[noe]\([5678]\)' || true)
cat << EOF
function hook_initialize_terminal {
  serial --unit=$device ${speed+--speed=$speed} ${parity+--parity=$parity} \
         ${bits+--word=$bits}
  terminal_input serial
  terminal_output serial
}
EOF
 fi
 if [ -n "$init_target" ]; then
   printf 'function hook_menu_pre {\n'
   printf '  menuentry "Sortix (%s)" {\n' "$init_target"
   printf '    load_sortix -- /sbin/init --target=%s\n' "$init_target"
   printf '  }\n'
   printf '}\n'
 fi
 if [ -e "$directory/boot/liveconfig.tar.xz" ]; then
   printf 'function hook_initrd_post {\n'
   printf '  echo -n "Loading /boot/liveconfig.tar.xz (%s) ... "\n' \
           "$(human_size "$directory/boot/liveconfig.tar.xz")"
   printf '  module /boot/liveconfig.tar.xz\n'
   printf '  echo done\n'
   printf '}\n'
 fi
 ) > "$directory/boot/grub/hooks.cfg"