#!/bin/bash

# Copyright (C) 2013-2025 Marcin Krol <hawk@tld-linux.org>
# All Rights Reserved

. /lib/cri/vars
. /lib/cri/functions

# read configuration
. /lib/cri/system.config

crinit_set_opt () {
  sed -i -e 's/'"${1}"'=[01]/'"${1}"'='"${2}"'/g;' /lib/cri/crinit.opts
}

init_status=0

interactive=0
if [ "$(basename "${0}" 2>/dev/null)" = "sysinit" ]; then
  interactive=1
fi

if [ "${1}" = "" ]; then
  echo "Usage: $(basename "${0}" 2>/dev/null) <destination path>"
  exit 1
fi

# get rid of trailing backslashes in destination path
system_path=$(echo "${1}" | sed -e 's/[\/]*$//g' 2>/dev/null)

# Detect system in destination path and set init type
system_type=""
system_name=""
system_version=""
system_version_code=""

if [ -f "${system_path}"/etc/os-release ]; then
  . "${system_path}"/etc/os-release
  system_type="${ID}"
  system_name="${NAME}"
  system_version="${VERSION}"
  system_version_code="${VERSION_ID}"
else
  echo "Error: unable to detect system type and version."
  init_status=1
  exit ${init_status}
fi

if [ -z "${system_type}" ]; then
  echo "Error: unable to detect system type and version."
  init_status=1
  exit ${init_status}
else
  if [ "${system_type}" != "tld" ] && [ "${system_type}" != "pld" ] && [ "${system_type}" != "debian" ] && [ "${system_type}" != "devuan" ] && [ "${system_type}" != "ubuntu" ] && [ "${system_type}" != "almalinux" ] && [ "${system_type}" != "rocky" ] && [ "${system_type}" != "fedora" ] && [ "${system_type}" != "rhel" ]; then
    echo "Error: unsupported system type '${system_type}'"
    init_status=1
    exit ${init_status}
  fi
fi

cat >/lib/cri/crinit.vars <<EOF
system_path="${system_path}"
system_type="${system_type}"
system_name="${system_name}"
system_version="${system_version}"
system_version_code="${system_version_code}"
EOF

cat >/lib/cri/crinit.opts <<EOF
crinit_hostname=1
crinit_timezone=1
crinit_network=1
crinit_netifnames=1
crinit_netrules=1
crinit_fstab=1
crinit_crypttab=1
crinit_mdadm=1
crinit_sshkeys=1
crinit_rootpw=1
crinit_user=1
crinit_initrd=1
crinit_grubconfig=1
crinit_grubinstall=1
EOF

# check if interacive mode was requested
if [ "${interactive}" -eq 1 ]; then
  if [ "$(tput lines 2>/dev/null)" -eq 25 ]; then
    dialog_height=21
    dialog_list_height=11
  else
    dialog_height=24
    dialog_list_height=14
  fi
  dialog_title="System initialization"
  dialog \
    --backtitle "${dialog_backtitle}" \
    --title "${dialog_title}" \
    --colors \
    --cancel-label "Quit" \
    --checklist "\nPlease select system initialization tasks you wish to perform.\n\Z1Warning!\Zn Affected configuration files will be overwritten!\n " \
    ${dialog_height} 76 ${dialog_list_height} \
    "hostname" "Set system hostname" "off" \
    "timezone" "Set system timezone" "off" \
    "network" "Configure network" "off" \
    "netifnames" "Disable predictable network interface names" "off" \
    "netrules" "Generate udev persistent net rules" "off" \
    "fstab" "Generate /etc/fstab" "off" \
    "crypttab" "Generate /etc/crypttab" "off" \
    "mdadm" "Generate mdadm.conf" "off" \
    "sshkeys" "Generate system SSH keys" "off" \
    "rootpw" "Set root password" "off" \
    "user" "Create user account" "off" \
    "initrd" "Generate initrd/initramfs" "off" \
    "grubconfig" "Generate GRUB configuration" "off" \
    "grubinstall" "Install GRUB bootloader" "off" \
  2>/tmp/$(basename "${0}.dialog" 2>/dev/null)
  result=$?
  if [ "${result}" -eq 1 ]; then
    clear
    exit 1
  fi
  # disable selected options
  for opt in $(cat /tmp/$(basename "${0}.dialog" 2>/dev/null) 2>/dev/null); do
    crinit_set_opt "${opt}" "0"
  done
  # reverse all options so only selected ones are enabled
  sed -i -e 's/=1$/=2/g; s/=0$/=1/g; s/=2$/=0/g;' /lib/cri/crinit.opts
  clear
  /lib/cri/install.pre true
fi

. /lib/cri/crinit.opts

echo "System   : [1;37m${NAME}[0m"
echo "Release  : [1;37m${VERSION}[0m"

if [ "${interactive}" -eq 0 ] && [ -f "${system_path}/etc/machine-id" ]; then
  echo -n "Generating machine ID ... "
  rm -f "${system_path}/etc/machine-id"
  if [ -x "${system_path}/bin/systemd-machine-id-setup" ]; then
    chroot "${system_path}" /bin/systemd-machine-id-setup 1>/dev/null 2>&1
  elif [ -x "${system_path}/usr/bin/systemd-machine-id-setup" ]; then
    chroot "${system_path}" /usr/bin/systemd-machine-id-setup 1>/dev/null 2>&1
  fi
  cmd_status $? 0
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_hostname}" -eq 1 ]; then
  /lib/cri/crinit.hostname
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_timezone}" -eq 1 ]; then
  /lib/cri/crinit.timezone
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_network}" -eq 1 ]; then
  /lib/cri/crinit.network
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_netifnames}" -eq 1 ]; then
  /lib/cri/crinit.netifnames
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_netrules}" -eq 1 ]; then
  /lib/cri/crinit.netrules
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_fstab}" -eq 1 ]; then
  /lib/cri/crinit.fstab
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_crypttab}" -eq 1 ]; then
  /lib/cri/crinit.crypttab
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_mdadm}" -eq 1 ]; then
  /lib/cri/crinit.mdadm
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_sshkeys}" -eq 1 ]; then
  /lib/cri/crinit.sshkeys
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_rootpw}" -eq 1 ]; then
  /lib/cri/crinit.rootpw
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_user}" -eq 1 ]; then
  /lib/cri/crinit.user
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_initrd}" -eq 1 ] || [ "${crinit_grubconfig}" -eq 1 ] || [ "${crinit_grubinstall}" -eq 1 ]; then
  # bind-mount /dev, /proc, /run, /sys in destination path
  for d in dev proc run sys; do
    if ! [ -d "${system_path}/${d}" ]; then
      mkdir -p "${system_path}/${d}" 1>/dev/null 2>&1
    fi
    mount /${d} "${system_path}/${d}" -o bind 1>/dev/null 2>&1
  done
  # bind-mount efivars if running under EFI
  if [ -d "/sys/firmware/efi" ]; then
    mount /sys/firmware/efi/efivars "${system_path}/sys/firmware/efi/efivars" -o bind 1>/dev/null 2>&1
  fi
fi

if [ "${crinit_initrd}" -eq 1 ]; then
  /lib/cri/crinit.initrd
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_grubconfig}" -eq 1 ]; then
  /lib/cri/crinit.grubconfig
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_grubinstall}" -eq 1 ]; then
  /lib/cri/crinit.grubinstall
  result=$?
  if [ "${result}" -ne 0 ]; then
    init_status="${result}"
  fi
fi

if [ "${crinit_initrd}" -eq 1 ] || [ "${crinit_grubconfig}" -eq 1 ] || [ "${crinit_grubinstall}" -eq 1 ]; then
  # umount efivars if running under EFI
  if [ -d "/sys/firmware/efi" ]; then
    umount "${system_path}/sys/firmware/efi/efivars" 1>/dev/null 2>&1
  fi
  # umount /dev, /proc, /run, /sys from destination path
  for d in sys run proc dev; do
    mountpoint -q "${1}/${d}" 1>/dev/null 2>/dev/null
    result=$?
    if [ "${result}" -eq 0 ]; then
      umount "${system_path}/${d}" 1>/dev/null 2>&1
    fi
  done
fi

exit "${init_status}"
