#!/bin/bash

## Copyright (C) 2012 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

set -x
set -o errexit
set -o nounset
set -o pipefail
set -o errtrace
shopt -s inherit_errexit
shopt -s shift_verbose
export LC_ALL=C

true "INFO: Currently running script: ${BASH_SOURCE[0]} $*"

MYDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

cd "${MYDIR}"
cd ..
cd help-steps

source pre
source variables

create-debian-raw-image() {
   mkdir --parents "${binary_build_folder_dist}/"

   ## The shared-base role (--base-image-role create|consume) is applied in
   ## help-steps/variables: 'create' points binary_image_raw_file at base-image.raw,
   ## 'consume' sets cached_binary_image_raw_file to it (the copy branch below).

   if [ ! "${cached_binary_image_raw_file:-}" = "" ]; then
      true "${cyan}${BASH_SOURCE[0]} INFO: copy and use cached_binary_image_raw_file '${cached_binary_image_raw_file}'...${reset}"
      if ! test -f "${cached_binary_image_raw_file}" ; then
         error "cached_binary_image_raw_file '${cached_binary_image_raw_file}' does not exist!"
      fi
      ${SUDO_TO_ROOT} chown "${user_name}:${user_name}" "${cached_binary_image_raw_file}"
      ${SUDO_TO_ROOT} safe-rm -f -- "${binary_image_raw_file}"
      cp -- "${cached_binary_image_raw_file}" "${binary_image_raw_file}"
      true "${cyan}${BASH_SOURCE[0]} INFO: copying cached_binary_image_raw_file done.${reset}"
      return 0
   fi

   ARCH="$(uname --machine)"
   true "${cyan}${BASH_SOURCE[0]} INFO: Architecture ${ARCH} detected.${reset}"
   true "${cyan}INFO: dist_build_target_arch set to: ${dist_build_target_arch}${reset}"

   ${SUDO_TO_ROOT} mkdir --parents "/etc/debootstrap/etc/apt/sources.list.d"
   ${SUDO_TO_ROOT} cp -- "${dist_build_sources_list_primary}" "/etc/debootstrap/etc/apt/sources.list.d/derivative.sources"

   ## Info.
   true "${cyan}INFO: Using the following /etc/apt/sources.list.d/derivative.sources for grml-debootstrap: ${reset}"
   ${SUDO_TO_ROOT} cat -- "/etc/debootstrap/etc/apt/sources.list.d/derivative.sources"

   ## TODO
   ## /etc/resolv.conf of host leaks into image.
   ## https://git-tails.immerda.ch/tails/plain/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/00-resolv-over-clearnet
   ## configure_chroot_dns_servers

   ## {{ grml-debootstrap environment variables

   ## grml-debootstrap variables are documented in /etc/debootstrap/config and
   ## https://github.com/grml/grml-debootstrap/blob/master/config

   ## Using export, so grml-debootstrap can read it.

   [ -n "${DEBUG:-}" ] || export DEBUG="true"

   ## https://github.com/grml/grml-debootstrap/issues/22
   ## https://github.com/grml/grml-debootstrap/pull/31
   [ -n "${REPORT_TRAP_ERR:-}" ] || export REPORT_TRAP_ERR="yes"
   [ -n "${FAIL_TRAP_ERR:-}" ] || export FAIL_TRAP_ERR="yes"

   [ -n "${DPKG_OPTIONS:-}" ] || export DPKG_OPTIONS="${DIST_APTGETOPT[*]}"

   ## Do not install non-Free software.
   [ -n "${COMPONENTS:-}" ] || export COMPONENTS='main'

   ## Integrity test.
   [ -n "${FSCK:-}" ] || export FSCK='yes'

   ## Set time zone to UTC. Not that important, we will install our own
   ## /etc/timezone file later anyway. Just in case.
   [ -n "${TIMEZONE:-}" ] || export TIMEZONE='UTC'

   ## Do not clean APT cache after installation is finished to safe time.
   [ -n "${RM_APTCACHE:-}" ] || export RM_APTCACHE='no'

   ## We do not need to upgrade the image, because when we create an image,
   ## we end up with the most current versions from the repository we are using
   ## anyway. We also do not install any other packages or use any other
   ## repositories, just use grml-debootstrap to create a minimal image.
   ## Would be also no good idea to rely on grml-debootstrap's upgrade
   ## function, because grml-debootstrap does not honor our apt options. (For
   ## higher network timeouts, ignore valid-until, since we are building from
   ## the frozen snapshot.debian.org repository. See also
   ## buildconfig-d/30_apt.conf.) https://github.com/grml/grml-debootstrap/issues/8
   ## Even if we wanted to upgrade the system, we'd be better off using our own
   ## build-step for that.
   [ -n "${UPGRADE_SYSTEM:-}" ] || export UPGRADE_SYSTEM='no'

   ## Use fixed disk identifier. For verifiable builds.
   ## grml-debootstrap sets it to:
   ## 26ada0c0-1165-4098-884d-aafd2220c2c6
   [ -n "${FIXED_DISK_IDENTIFIERS:-}" ] || export FIXED_DISK_IDENTIFIERS='yes'

   ## Speed versus ease of debugging.
   ## Not using grml-debootstrap to install a kernel.
   ## We later install a kernel ourselves.
   #[ -n "${KERNEL:-}" ] || export KERNEL="none"
   #[ -n "${NOKERNEL:-}" ] || export NOKERNEL="true"
   ## We later create an initial ramdisk ourselves.
   #[ -n "${INITRD:-}" ] || export INITRD="no"

   ## Do not use /etc/network/interfaces by grml-debootstrap.
   [ -n "${NOINTERFACES:-}" ] || export NOINTERFACES="true"

   ### {{{
   true "OLD_PATH: ${PATH}"

   ## Expand PATH environment variable so grml-debootstrap will use help-steps/mmdebstrap wrapper.
   ## Because variables "$DEBOOTSTRAP" and "$DEBOOTSTRAP_OPTS" have been deprecate by grml-debootstrap.
   ## https://github.com/grml/grml-debootstrap/pull/309
   new_path="${source_code_folder_dist}/help-steps:${PATH}"

   PATH="${new_path}"
   export PATH
   true "NEW_PATH: ${PATH}"
   ### }}}

   #if [ "${dist_build_flavor:-}" = "whonix-gateway-rpi" ] || [ "${dist_build_target_arch:-}" = "arm64" ]; then
      ## Do not pass --vmefi to grml-debootstarp due to the following grml-debootstrap bug.
      ## VM build failing if combining `--vmefi` with `--arch arm64`
      ## https://github.com/grml/grml-debootstrap/issues/257
      ##
      ## '--arch arm64' do not need '--vmefi' anyhow because grml-debootstrap setups up EFI
      ## for these VM builds anyhow.
      #[ -n "${use_vmefi_maybe:-}" ] || use_vmefi_maybe=""
   #else
      #[ -n "${use_vmefi_maybe:-}" ] || use_vmefi_maybe="--vmefi"
   #fi
   ## Should be fixed.
   ## TODO: test and simplify
   [ -n "${use_vmefi_maybe:-}" ] || use_vmefi_maybe="--vmefi"

   [ -n "${grml_packages_file:-}" ] || grml_packages_file="${source_code_folder_dist}/grml_packages"

   ## Why not use 'qemu-debootstrap' by default?
   ## - Would require a lot work, if at all possible.
   ## - Cannot create raw images.
   ## - Cannot be combined with grml-debootstrap.
   ## - Cannot be combined with mmdebstrap.
   ## - Cannot bootstrap from multiple (regular and security) repositories
   ##   at the same time aka "multistrap".
   ## - Does not support APT sources in a sources  file such as for example
   ##   build_sources/debian_stable_current_clearnet.sources
   ##   (variable: dist_build_sources_list_primary)
   ##   but requires an APT URI such as for example.
   ##   http://HTTPS///deb.debian.org/debian
   ##   (variable: dist_build_apt_sources_mirror)

   ## grml-debootstrap's default is initramfs.
   ## https://github.com/grml/grml-debootstrap/pull/196
   if printf '%s\n' "${BUILD_INITRAMFS_PKGS}" | grep -- dracut &>/dev/null; then
      ## This has currently no effect. Since kernel installation and initrd
      ## creating is not done during this step, grml-debootstrap chroot-script
      ## will skip initramfs creation.
      [ -n "${INITRD_GENERATOR:-}" ] || export INITRD_GENERATOR="dracut"
   fi

   ## See also /etc/debootstrap/config or
   ## https://github.com/grml/grml-debootstrap/blob/master/config to learn
   ## about other grml-debootstrap options and defaults.

   ## Using '--packages "$source_code_folder_dist/grml_packages"' even though
   ## these packages are already passed by '--depopt "--include=,[...]" to
   ## avoid grml-debootstrap apt-get installing its default package selection.
   ## (Which contains grml distribution default packages that we don't need in
   ## Whonix.)

   ## dist_build_multiarch_package_item is read by help-steps/mmdebstrap wrapper.

   dist_grml_mount_point="/mnt/derivative-maker-grml-debootstrap.$$"
   ## dist_grml_mount_point is read by help-steps/mmdebstrap wrapper.
   export dist_grml_mount_point

   ## Pass environment variables:
   ## SOURCE_DATE_EPOCH

   printf '%s\n' "-------------- DEBUGGING BLOCK ---------------------"
   printf '%s\n' "DEBOOTSTRAP_PREFIX: ${DEBOOTSTRAP_PREFIX}"
   printf '%s\n' "new_path: ${new_path}"
   printf '%s\n' "dist_build_target_arch: ${dist_build_target_arch}"
   printf '%s\n' "dist_build_hostname: ${dist_build_hostname}"
   printf '%s\n' "dist_build_apt_stable_release: ${dist_build_apt_stable_release}"
   printf '%s\n' "dist_build_file_system: ${dist_build_file_system}"
   printf '%s\n' "vmsize: ${VMSIZE}"
   printf '%s\n' "packages: ${grml_packages_file}"
   printf '%s\n' "mntpoint: ${dist_grml_mount_point}"
   printf '%s\n' "target: ${binary_image_raw_file}"
   printf '%s\n' "use_vmefi_maybe: ${use_vmefi_maybe}"
   printf '%s\n' "------------ END DEBUGGING BLOCK -------------------"

   ## Sanity test.
   test -n "${dist_build_hostname}"

   ## '$DEBOOTSTRAP_PREFIX', '$UNSHARE_PID_NS' and '$use_vmefi_maybe' are
   ## intentionally unquoted: each holds zero or more words that must split
   ## into separate argv slots.
   # shellcheck disable=SC2086
   ${SUDO_TO_ROOT} \
      --preserve-env \
         PATH="${new_path}" \
         ${DEBOOTSTRAP_PREFIX} \
         dist_build_multiarch_package_item="${dist_build_target_arch}" \
            ${UNSHARE_PID_NS:-} \
            bash -x -e \
               "${dist_build_grml_bin}" \
                  --arch "${dist_build_target_arch}" \
                  --filesystem "${dist_build_file_system}" \
                  ${use_vmefi_maybe} \
                  --force \
                  --hostname "${dist_build_hostname}" \
                  --nopassword \
                  --release "${dist_build_apt_stable_release}" \
                  --keep_src_list \
                  --verbose \
                  --vmfile \
                  --vmsize "${VMSIZE}" \
                  --packages "${grml_packages_file}" \
                  --mntpoint "${dist_grml_mount_point}" \
                  --target "${binary_image_raw_file}" \
                  --no-reimage \
                  --defaultinterfaces
}

create-empty-raw-image() {
   qemu-img create -f raw "${binary_image_raw_file}" "${VMSIZE}"
}

permission-fix-raw-image() {
   ${SUDO_TO_ROOT} chown "${user_name}:${user_name}" "${binary_image_raw_file}"
}

main() {
   if [ "${dist_build_install_to_root:-}" = "true" ]; then
      true "${green}INFO: Skipping ${BASH_SOURCE[0]}, because dist_build_install_to_root is set to true.${reset}"
      return 0
   fi

   if [ "${build_dry_run:-}" = "true" ]; then
      true "${bold}${cyan}INFO: dry-run.${reset}"
      create-empty-raw-image
   elif [ "${dist_build_type_long:-}" = "custom-workstation" ]; then
      create-empty-raw-image
   elif [ "${dist_build_type_long:-}" = "source" ]; then
      ## Missing variables such as: dist_build_hostname
      error "unsupported flavor: --flavor source"
   else
      create-debian-raw-image
   fi

   permission-fix-raw-image
}

main "$@"
