#!/bin/bash

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

set -x
set -e

true "INFO: Currently running script: $BASH_SOURCE $@"

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

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

source pre
source colors
source variables

cd "$MYDIR"
cd ..

build_machine_setup() {
   ## https://github.com/QubesOS/qubes-issues/issues/1066
   $SUDO_TO_ROOT systemctl stop qubes-update-check.timer || true
   $SUDO_TO_ROOT systemctl stop qubes-update-check.service || true
   ## 'safe-rm' not installed yet.
   ## https://github.com/QubesOS/qubes-issues/issues/1066#issuecomment-1987239106
   $SUDO_TO_ROOT rm -f -- "/etc/apt/apt.conf.d/00notify-hook"

   if [ "$dist_build_fast1" = "1" ]; then
      true "${bold}${cyan}INFO: run with '--fast 1' switch, skipping $BASH_SOURCE. ${reset}"
      exit 0
   fi

   ## {{ users and groups

   ## TODO: Still needed?
   ## Check if user "$user_name" already exist.
#    local id_exit_code
#    id_exit_code="0"
#    id "$user_name" || { id_exit_code="$?" ; true; };
#    if [ "$id_exit_code" = "1" ]; then
#       true 'INFO: Creating user "$user_name" with password "changeme", because some things have to be run as "$user_name".'
#       if command -v qubesdb-read >/dev/null 2>&1 ; then
#          password=""
#       else
#          ## setting password of user clearnet to changeme
#          ##
#          ## How this password was created:
#          ## sudo apt-get install whois
#          ## mkpasswd
#          ## changeme
#          ## Resulted in: aTayYxVyw5kDo
#          password="aTayYxVyw5kDo"
#       fi
#       $SUDO_TO_ROOT useradd --password "$password" --user-group --create-home --shell /bin/bash "$user_name"
#    elif [ "$id_exit_code" = "0" ]; then
#       true "${cyan}INFO: Not creating user \"$user_name\" with password \"changeme\", because it already exists.${reset}"
#    else
#       true "${red}${bold}ERROR: id_exit_code was neither 1 or 0, it was: ${id_exit_code}${reset}"
#       error "See above!"
#    fi

   ## Add user to sudo group.
   ## TODO: Still needed?
#    $SUDO_TO_ROOT adduser "$user_name" sudo

   ## }}

   ## Debugging.
   true 'INFO: Benchmarking "$SUDO_TO_ROOT echo "This is a test echo." using "time"...'
   time $SUDO_TO_ROOT echo "This is a test echo."

   ## Nowadays done using: ./derivative-update
   #true "INFO: Updating git sub modules..."
   ## Safe.
   ## Ensures submodules' remote URL configuration matches the values specified in .gitmodules.
   #git submodule sync --recursive
   ## Caution.
   ## This command updates Git submodules to the commit recorded in the parent repository. (derivative-maker)
   ## It modifies the submodule's Git HEAD, potentially overriding local changes.
   #git submodule update --init --recursive --jobs=200
   #git -c merge.verifySignatures=true submodule update --init --recursive --jobs=200 --merge
   #true "INFO: Updated git sub modules."

   ## Might be useful during port to Debian forky.
   #$SUDO_TO_ROOT repository-dist --disable || true
   #$SUDO_TO_ROOT safe-rm -f -- /etc/apt/sources.list.d/extrepo_kicksecure.sources
   #$SUDO_TO_ROOT "$str_replace_many_tool" trixie forky /etc/apt/sources.list.d/* || true

   $SUDO_TO_ROOT \
      apt-get \
         "${APTGETOPT[@]}" \
         -o Dir::Etc::sourcelist="$dist_build_sources_list_primary" \
         -o Dir::Etc::sourceparts="-" \
         update

   true "dist_build_upgrade_build_machine: $dist_build_upgrade_build_machine"
   if [ ! "$dist_build_upgrade_build_machine" = "0" ]; then
      ## Update package lists and upgrade.
      $SUDO_TO_ROOT \
         apt-get \
            "${APTGETOPT[@]}" \
            -o Dir::Etc::sourcelist="$dist_build_sources_list_primary" \
            -o Dir::Etc::sourceparts="-" \
            $apt_unattended_opts \
            --no-install-recommends \
            --yes \
               dist-upgrade
   fi

   ###############################################
   ## Build Dependencies for Whonix Build Script #
   ###############################################
   local packages_to_be_installed
   packages_to_be_installed+=" $dist_build_script_build_dependency "

   if [ "$eatmydata_install" = "true" ]; then
      true "INFO: Installing eatmydata, because using '--unsafe-io true'."
      packages_to_be_installed+=" $eatmydata "
   else
      true "INFO: Not installing eatmydata, because not using '--unsafe-io true'."
   fi

   if [ "$dist_build_iso" = "true" ]; then
      true "INFO: host_architecture: $host_architecture"
      packages_to_be_installed+=" mokutil "
      packages_to_be_installed+=" keyutils "
      packages_to_be_installed+=" grub2-common "
      packages_to_be_installed+=" efibootmgr "

      ## The following grub packages are (partially) build dependencies by Debian live-build.
      ## Certainly required for amd64 ISO images booted with shim and grub.
      if [ "${host_architecture}" = "amd64" ]; then
         ## These packages are all available for the amd64 platform.
         ## "grub-mkrescue will automatically include every platform it finds." [1]
         ## [1] https://lists.gnu.org/archive/html/grub-devel/2014-03/msg00009.html
         ## Install them all for best compatibility and reproducible builds.
         ## Some might be unnecessary and waste a bit space.
         ## Maybe this can be optimized later.
         packages_to_be_installed+=" grub-efi-amd64-bin grub-pc-bin grub-coreboot-bin grub-efi-ia32-bin grub-xen-bin grub-ieee1275-bin "
         packages_to_be_installed+=" grub-efi-amd64-signed "
         packages_to_be_installed+=" shim-unsigned shim-signed shim-signed-common "
         packages_to_be_installed+=" shim-helpers-amd64-signed "
      elif [ "${host_architecture}" = "i386" ]; then
         packages_to_be_installed+=" grub-efi-amd64-bin grub-pc-bin grub-coreboot-bin grub-efi-ia32-bin grub-xen-bin grub-ieee1275-bin "
         packages_to_be_installed+=" grub-efi-ia32-signed "
         packages_to_be_installed+=" shim-unsigned shim-signed shim-signed-common "
         packages_to_be_installed+=" shim-helpers-i386-signed "
      elif [ "${host_architecture}" = "ppc64el" ]; then
         packages_to_be_installed+=" grub-ieee1275-bin  "
      elif [ "${host_architecture}" = "ppc64" ]; then
         packages_to_be_installed+=" grub-ieee1275-bin  "
      elif [ "${host_architecture}" = "sparc64" ]; then
         packages_to_be_installed+=" grub-ieee1275-bin  "
      elif [ "${host_architecture}" = "arm64" ]; then
         packages_to_be_installed+=" grub-efi-arm64-bin "
         packages_to_be_installed+=" shim-unsigned shim-signed shim-signed-common "
      elif [ "${host_architecture}" = "riscv64" ]; then
         packages_to_be_installed+=" grub-efi-riscv64-bin  "
      else
         true "${red}${bold}WARNING:${reset} ${under}The ISO to be build might be unbootable!${eunder}
- This is because bootloader support is not implemented when building on this
  systems's host_architecture.
- Either the build script does not know how to install the required grub '-bin'
  package for this architecture or the package is simply unavailable.
- There is also a small chance that host_architecture detection failed. (Using multiarch, wine?)"
      fi
   fi

   if [ "$dist_build_install_to_root" = "true" ]; then
      ###########################################
      ## Build Dependency for Bare Metal Builds #
      ###########################################
      local bare_metal_basic_package_list
      bare_metal_basic_package_list="$(grep --invert-match --extended-regexp "^\s*#" -- "$source_code_folder_dist/grml_packages" | tr "\n" " ")"
      packages_to_be_installed+=" $bare_metal_basic_package_list "
   else
      if [ "$dist_build_virtualbox" = "true" ]; then
         #######################################################################
         ## Build Dependencies for creating VirtualBox Images (.vdi and .ova)  #
         #######################################################################
         ## uname -r returns on Qubes:
         ## 4.4.31-11.pvops.qubes.x86_64
         local linux_headers
         if command -v qubesdb-read >/dev/null 2>&1 ; then
            true "INFO: Qubes host detected: yes - therefore selecting linux-headers-amd64."
            linux_headers="linux-headers-amd64"
         else
            true "INFO: Qubes host detected: no - therefore selecting host_architecture $host_architecture and linux-headers-${host_architecture}"
            linux_headers="linux-headers-${host_architecture}"
         fi
         packages_to_be_installed+=" $linux_headers "
      fi

   fi

   $SUDO_TO_ROOT \
      apt-get \
         "${APTGETOPT[@]}" \
         -o Dir::Etc::sourcelist="$dist_build_sources_list_primary" \
         -o Dir::Etc::sourceparts="-" \
         $apt_unattended_opts \
         --no-install-recommends \
         --yes \
         install \
         $packages_to_be_installed

   ## Debugging.
   $SUDO_TO_ROOT cat /usr/sbin/policy-rc.d || true

   ## Debugging.
   #$SUDO_TO_ROOT cat /proc/devices
}

check-unicode() {
   local check_unicode_tool
   check_unicode_tool="${dist_developer_meta_files_folder}/usr/bin/dm-check-unicode"
   ## https://github.com/grml/grml-debootstrap/issues/219
   ## overwrite with '|| true' because `grep` exits non-zero if no match was found.
   ## TODO: dm-check-unicode currently hardcoded. Does not use source_code_folder_dist.

   test -x "$check_unicode_tool"

   grep_find_unicode_wrapper_output="$("$check_unicode_tool" "$source_code_folder_dist" 2>&1)" || true

   if [ "$grep_find_unicode_wrapper_output" = "" ]; then
      true "INFO: grep_find_unicode_wrapper_output empty, good, OK."
   else
      error "$0: ERROR: Unicode found!

See also:
https://forums.whonix.org/t/detecting-malicious-unicode-in-source-code-and-pull-requests/13754"
   fi

   true
}

check-git-folder() {
   if ! test -e "$source_code_folder_dist/packages/kicksecure/genmkfile/.git" ; then
      error "$source_code_folder_dist/packages/kicksecure/genmkfile/.git does not exist."
   fi
}

approx_proxy_setup() {
   if [ ! "$APPROX_PROXY_ENABLE" = "yes" ]; then
      return 0
   fi

   ## Install approx proxy configuration
   $SUDO_TO_ROOT mkdir --parents -- '/etc/approx-derivative-maker'
   $SUDO_TO_ROOT mkdir --parents -- '/var/cache/approx-derivative-maker'
   $SUDO_TO_ROOT mkdir --parents -- '/etc/approx-derivative-maker/curl-home'
   $SUDO_TO_ROOT chown --recursive -- approx:approx '/var/cache/approx-derivative-maker'

   ## Clear out empty files from the cache, approx uses these to mark files
   ## that could not be fetched, which could cause problems for later builds
   ## if the fetch failure was transient.
   $SUDO_TO_ROOT find '/var/cache/approx-derivative-maker' -type f -empty -delete

   ## Clear out repository metadata from the cache, approx handles it poorly.
   ## Debian bug report:
   ## Unable to detect when local and remote metadata no longer matches
   ## https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1118031
   #$SUDO_TO_ROOT find '/var/cache/approx-derivative-maker' -type f -name InRelease -delete
   local repo_dir
   for repo_dir in /var/cache/approx-derivative-maker/*; do
     if [ -d "${repo_dir}/dists" ]; then
       $SUDO_TO_ROOT safe-rm --recursive --force -- "${repo_dir}/dists"
     fi
   done

   $SUDO_TO_ROOT cp --no-preserve=mode -- "$source_code_folder_dist/approx/approx-derivative-maker.socket" '/usr/lib/systemd/system/approx-derivative-maker.socket'
   if [ "$dist_build_sources_clearnet_or_onion" = "clearnet" ]; then
      $SUDO_TO_ROOT cp --no-preserve=mode -- "$source_code_folder_dist/approx/approx-derivative-maker@.service" '/usr/lib/systemd/system/approx-derivative-maker@.service'
      $SUDO_TO_ROOT cp --no-preserve=mode -- "$source_code_folder_dist/approx/approx.conf" '/etc/approx-derivative-maker/approx.conf'
      $SUDO_TO_ROOT cp --no-preserve=mode -- "$source_code_folder_dist/approx/curlrc" '/etc/approx-derivative-maker/curl-home/.curlrc'
   else
      $SUDO_TO_ROOT cp --no-preserve=mode -- "$source_code_folder_dist/approx/approx-derivative-maker-tor@.service" '/usr/lib/systemd/system/approx-derivative-maker@.service'
      $SUDO_TO_ROOT cp --no-preserve=mode -- "$source_code_folder_dist/approx/approx-tor.conf" '/etc/approx-derivative-maker/approx.conf'
      $SUDO_TO_ROOT cp --no-preserve=mode -- "$source_code_folder_dist/approx/curlrc-tor" '/etc/approx-derivative-maker/curl-home/.curlrc'
   fi

   $SUDO_TO_ROOT systemctl daemon-reload
   $SUDO_TO_ROOT systemctl restart approx-derivative-maker.socket

   if [ "$dist_build_redistributable" != "true" ]; then
      return 0
   fi

   ## When building redistributable builds, add '/var/cache/approx' to Qubes bind-dirs on build machine.
   $SUDO_TO_ROOT mkdir --parents -- /rw/config/qubes-bind-dirs.d
   echo "binds+=( '/var/cache/approx-derivative-maker' )" | $SUDO_TO_ROOT tee -- /rw/config/qubes-bind-dirs.d/40_derivative-maker_approx.conf >/dev/null

   true
}

repo_proxy_test() {
   if [ "$REPO_PROXY" = "" ]; then
      return 0
   fi
   if [ "$REPO_PROXY" = "none" ]; then
      return 0
   fi

   true "INFO: Testing REPO_PROXY $REPO_PROXY (most likely approx, since default)..."
   local curl_exit_code=0
   curl --fail --silent "$REPO_PROXY" || { curl_exit_code="$?" ; true; };
   if [ "$curl_exit_code" = "0" ]; then
      true "INFO: approx functional..."
      return 0
   fi

   true "${red}${bold}ERROR: REPO_PROXY curl curl_exit_code: $curl_exit_code. REPO_PROXY $REPO_PROXY unreachable! Does a local firewall block connections to REPO_PROXY?${reset}"
   error "See above!"
}

## Install VirtualBox on the host operating system using 'dist-installer-cli'.
virtualbox-installation() {
   if [ ! "$dist_build_virtualbox" = "true" ]; then
      return 0
   fi

   true "INFO: Checking if VirtualBox is already installed..."
   if virtualbox_version_installed="$(dpkg-query --show --showformat='${Version}' "virtualbox")" ; then
      true "INFO: virtualbox is already installed."
      return 0
   elif virtualbox_version_installed="$(dpkg-query --show --showformat='${Version}' "virtualbox-7.2")" ; then
      true "INFO: virtualbox-7.2 is already installed."
      return 0
   fi

   ## NOTE: Code duplication in build-step prepare-build-machine
   ## NOTE: Code duplication in help-step pbuilder-chroot-script-virtualbox
   dist_installer_cli_arguments=()
   dist_installer_cli_arguments+=("--non-interactive")
   dist_installer_cli_arguments+=("--virtualbox-only")
   dist_installer_cli_arguments+=("--log-level=debug")
   ## Speed up the build? Not possible.
   ## `apt-get update` is actually needed to fetch
   ## VirtualBox from Debian 'unstable' repository.
   ## Option '--noupdate' should is not safe here, because if the installer adds a repository,
   ## then running 'apt update' is crucial for APT to learn about the new packages.
   #dist_installer_cli_arguments+=("--noupdate")
   ##
   ## Run virtualbox-installer with '--noupgrade' because the system has been updated earlier.
   ## This is to avoid a race condition where an update is made available shortly after
   ## to avoid breaking the build.
   dist_installer_cli_arguments+=("--noupgrade")
   dist_installer_cli_arguments+=("--ci")
   ## Redundant.
   dist_installer_cli_arguments+=("--no-boot")
   ## Redundant.
   dist_installer_cli_arguments+=("--no-import")
   ## NOTE: End code duplication.

   ## virtualbox-installer / dist-installer-cli
   "$binary_image_installer_dist_source" "${dist_installer_cli_arguments[@]}"

   true
}

check-virtualbox-installed() {
   if [ "$dist_build_internal_run" = "true" ]; then
      true "INFO: dist_build_internal_run set to true, skipping $FUNCNAME, ok."
      return 0
   fi
   if [ ! "$dist_build_virtualbox" = "true" ]; then
      true "INFO: dist_build_virtualbox not yet to true, skipping $FUNCNAME, ok."
      return 0
   fi

   if command -v VBoxManage >/dev/null ; then
      true "INFO: VBoxManage available, ok."
      return 0
   fi

   error "VirtualBox not installed yet. VBoxManage command unavailable."

   true
}

check-vm-exists() {
   if [ "$dist_build_internal_run" = "true" ]; then
      return 0
   fi

   if [ ! "$dist_build_type_long" = "workstation" ]; then
      return 0
   fi

   ## When using:
   ## SKIP_SCRIPTS+= " prepare-release "
   ## then skip this function.
   local skip_script
   for skip_script in $SKIP_SCRIPTS; do
      if matched_word=$(echo "$skip_script" | grep "prepare-release") ; then
         echo "${bold}${green}$BASH_SOURCE INFO: Skipping $FUNCNAME, because SKIP_SCRIPTS matches 'prepare-release'. matched_word: '$matched_word'${reset}"
         return 0
      fi
   done

   if [ "$dist_build_raw" = "true" ]; then
      if ! test -f "$binary_image_raw_file_for_unified" ; then
         error "\
Trying to build...
VMNAME: $VMNAME
vm_names_to_be_exported: $vm_names_to_be_exported
dist_build_desktop: $dist_build_desktop
dist_build_raw: $dist_build_raw
missing other VM for unified builds: $binary_image_raw_file_for_unified

This means dm-prepare-release would fail later.

Did you build a CLI build first and now intent to mix with a LXQt build? In this case, set environment variable, for example:
binary_image_raw_file_for_unified=/path/to/raw ./derivative-maker"
      fi
   fi

   if [ "$dist_build_qcow2" = "true" ]; then
      if ! test -f "$binary_image_qcow2_file_for_unified" ; then
         error "\
Trying to build...
VMNAME: $VMNAME
vm_names_to_be_exported: $vm_names_to_be_exported
dist_build_desktop: $dist_build_desktop
dist_build_qcow2: $dist_build_qcow2
missing other VM for unified builds: $binary_image_qcow2_file_for_unified

This means dm-prepare-release would fail later.

Did you build a CLI build first and now intent to mix with a LXQt build? In this case, set environment variable, for example:
binary_image_qcow2_file_for_unified=/path/to/qcow ./derivative-maker"
      fi
   fi

   if [ "$dist_build_virtualbox" = "true" ]; then
      true "INFO: vm_names_to_be_exported: $vm_names_to_be_exported"
      local vm_name_item_to_be_exported
      for vm_name_item_to_be_exported in $vm_names_to_be_exported ; do
         if printf "%s\n" "$vm_name_item_to_be_exported" | grep --quiet --ignore-case -- "$dist_build_type_long" ; then
            true "${cyan}INFO: Build for $VMNAME in progress... No need to check for vm_name_item_to_be_exported $vm_name_item_to_be_exported as we are building that now, ok.${reset}"
            continue
         fi
         true "${cyan}INFO: Build for VMNAME $VMNAME in progress... Checking if corresponding in list of vm_names_to_be_exported vm $vm_name_item_to_be_exported already exists (because if it did not exist, the later dm-prepare-release script would fail)...${reset}"
         if ! $SUDO_TO_VBOX_TEMP VBoxManage showvminfo "$vm_name_item_to_be_exported" >/dev/null ; then
            error "\
Trying to build...
VMNAME: $VMNAME
dist_build_desktop: $dist_build_desktop
missing other VM for unified builds: $vm_name_item_to_be_exported

This means dm-prepare-release would fail later.

Did you build a CLI build first and now intent to mix with a LXQt build? In this case, set environment variable, for example:
vm_names_to_be_exported=\"Whonix-Gateway-CLI Whonix-Workstation-LXQt\" ./derivative-maker $@"
         fi
      done

      true "INFO: all vm_names_to_be_exported available, ok."
   fi

   true
}

create-virtualbox-temporary-user() {
   if [ ! "$dist_build_virtualbox" = "true" ]; then
      return 0
   fi

   ## Debugging. Because SUDO_TO_VBOX_TEMP is failing on CI.
   if [ "$CI" = "true" ]; then
      whoami || true
      ## ansible
      groups ansible || true
      ## ansible : ansible sudo vboxusers

      $SUDO_TO_ROOT -- cat /etc/sudoers || true
      $SUDO_TO_ROOT -- ls -la /etc/sudoers.d || true
      $SUDO_TO_ROOT -- cat /etc/sudoers.d/90-cloud-init-users || true
      $SUDO_TO_ROOT -- cat /etc/sudoers.d/ansible-passwordless-sudo || true
      $SUDO_TO_ROOT -- cat /etc/sudoers.d/README || true
   fi

   #ansible ALL=NOPASSWD: ALL
   #root ALL=(ALL) NOPASSWD:ALL
   #%sudo   ALL=(ALL:ALL) NOPASSWD:ALL

   ## {{ code duplication
   ##    - prepare-build-machine
   ##    - pbuilder-chroot-script-virtualbox
   $SUDO_TO_ROOT -- adduser --system --group --home "$HOMEVAR_VBOX_TEMP" -- "dm-vbox-temp" || true
   $SUDO_TO_ROOT -- mkdir --parents -- "$HOMEVAR_VBOX_TEMP"
   $SUDO_TO_ROOT -- chown --recursive -- "dm-vbox-temp:dm-vbox-temp" "$HOMEVAR_VBOX_TEMP"
   ## Debugging.
   $SUDO_TO_ROOT -- groups -- "dm-vbox-temp" || true
   $SUDO_TO_ROOT -- ls -la -- "$HOMEVAR_VBOX_TEMP"
   ## Sanity test.
   $SUDO_TO_VBOX_TEMP -- test -d "/"
   $SUDO_TO_VBOX_TEMP -- ls -la -- "$HOMEVAR_VBOX_TEMP"
   ## }}

   true
}

grml-debootstrap_installation() {
   pushd "$source_code_folder_dist/grml-debootstrap"
   $SUDO_TO_ROOT make install
   popd
   true
}

packages_installation_from_backports_repository() {
   if [ "$dist_build_script_build_dependency_debian_backports" = "" ]; then
      return 0
   fi

   $SUDO_TO_ROOT \
      apt-get \
         "${APTGETOPT[@]}" \
         -o Dir::Etc::sourcelist="$dist_build_sources_list_debian_forky_backports" \
         -o Dir::Etc::sourceparts="-" \
         update

   $SUDO_TO_ROOT \
      apt-get \
         "${APTGETOPT[@]}" \
         -o Dir::Etc::sourcelist="$dist_build_sources_list_debian_forky_backports" \
         -o Dir::Etc::sourceparts="-" \
         $apt_unattended_opts \
         --no-install-recommends \
         --yes \
         install \
         $dist_build_script_build_dependency_debian_backports

   true
}

signing_key() {
   true "INFO: GPG_AGENT_INFO: $GPG_AGENT_INFO"
   if [ "$GPG_AGENT_INFO" = "" ]; then
      true "${cyan}${bold}INFO: Environment variable ${under}GPG_AGENT_INFO${eunder} is not set. gnupg-agent will not be available.${reset}"
   fi

   if [ "$CI" = "true" ]; then
      true "INFO: Create signing keys if none exist yet because CI detected..."
      "$dist_source_help_steps_folder/signing-key-create" "$@"
   elif [ "$dist_build_redistributable" = "true" ]; then
      true "INFO: dist_build_redistributable=true, therefore skipping $dist_source_help_steps_folder/signing-key-create, ok.
Not creating signing key when building redistributable builds.
(There is no risk of overwriting signing keys because signing-key-create is checking if signing keys already exist and never overwrites.)
However, if signing keys are missing for redistributable builds, then the keys should be manually put in place to avoid signing redistributable builds using auto-generated keys."
      #"$dist_source_help_steps_folder/signing-key-create" "$@"
   else
      true "INFO: Create signing keys if none exist yet..."
      "$dist_source_help_steps_folder/signing-key-create" "$@"
   fi

   ## Check if signing keys exists and is functional.
   ##
   ## Letting a builder using a gpg key password cache its passwords early,
   ## so we do not pause the build process later when reprepro creates the
   ## local apt repository or when signing redistributable images.
   "$dist_source_help_steps_folder/signing-key-test" "$@"
}

sudo_setup() {
   if [ "$USER" = "" ]; then
      error "Environment variable USER cannot be empty! Function sudo_setup failed!"
      return 0
   fi

   ## Fix 'sudo' error:
   ## > sudo: you are not permitted to use the -D option
   ## When using '$SUDO_TO_VBOX_TEMP' because it uses
   ## 'sudo' with '-D $HOMEVAR_VBOX_TEMP' ('--chdir') to avoid 'VBoxManage' error.
   ## > VBoxManage: error: Could not create the directory '.' (VERR_ACCESS_DENIED)

   local file_content
   file_content="\
## This file has been automatically created by derivative-maker.
## Feel free to delete this file after using derivative-maker.
##
## file: $BASH_SOURCE
## function: $FUNCNAME

## Enable passwordless sudo for '$USER'.
## Avoid 'sudo: a password is required' errors during the build process.
$USER ALL=(ALL:ALL) NOPASSWD:ALL

Defaults:%$USER runcwd=*

## Does not work:
#Defaults:%$USER runcwd=$HOMEVAR_VBOX_TEMP
#Defaults:%$USER runcwd=$HOMEVAR_VBOX_TEMP/
#Defaults:%$USER runcwd=$HOMEVAR_VBOX_TEMP/*
"

   printf "%s" "$file_content" | $SUDO_TO_ROOT SUDO_EDITOR="" VISUAL="" EDITOR=sponge -- visudo -f /etc/sudoers.d/derivative-maker >/dev/null

   ## Debugging.
   $SUDO_TO_ROOT cat /etc/sudoers.d/derivative-maker

   ## Sanity test.
   $SUDO_TO_ROOT visudo --strict --check /etc/sudoers.d/derivative-maker
}

main() {
   approx_proxy_setup "$@"
   repo_proxy_test "$@"
   build_machine_setup "$@"
   check-unicode "$@"
   check-git-folder "$@"
   virtualbox-installation
   check-virtualbox-installed "$@"
   check-vm-exists "$@"
   grml-debootstrap_installation "$@"
   packages_installation_from_backports_repository "$@"
   signing_key "$@"
   sudo_setup "$@"
   create-virtualbox-temporary-user "$@"
}

main "$@"
