#!/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 )"

source "$MYDIR/pre"
source "$MYDIR/colors"
source "$MYDIR/variables"

exception_handler_unmount-raw() {
   true "${red}${bold}BASH_COMMAND${reset}: $BASH_COMMAND
${red}${bold}ERROR $BASH_SOURCE: | caller: $(caller)${reset}"
   exit 1
}

unmount_raw() {
   trap "exception_handler_unmount-raw" ERR INT TERM

   if [ "$mount_folder" = "" ]; then
      true
   else
      ## hack for help-steps/analyze-image
      CHROOT_FOLDER="$mount_folder"
   fi

   sync

   true "INFO: Start of $FUNCNAME. Running losetup --all for debugging before running kpartx."
   $SUDO_TO_ROOT losetup --all

   if [ "$kpartx_only" = "true" ]; then
      true "INFO: kpartx_only=$kpartx_only, skipping unmount $CHROOT_FOLDER"
   else
      "$dist_source_help_steps_folder/unmount-helper" "$CHROOT_FOLDER"
   fi

   local img
   if [ "$dist_build_mount_raw_file" = "" ]; then
      img="$binary_image_raw_file"
   else
      img="$dist_build_mount_raw_file"
   fi

   ## Sleep to work around some obscure bug.
   ## https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=734794
   sleep 2 &
   wait "$!"
   sync

   $SUDO_TO_ROOT kpartx -d -s -v "$img"
   sync

   local loop_devices_output_before loop_devices_list loop_devices_item
   ## Example:
   ## sudo losetup --associated /home/user/derivative-binary/17.4.0.2/Kicksecure-CLI-17.4.0.2.Intel_AMD64.raw --noheadings --output NAME
   #/dev/loop1
   #/dev/loop2
   #/dev/loop0
   ## NOTE: There should only be one loop device (such as '/dev/loop1'). But in case of bugs, there might be multiple.
   loop_devices_output_before="$($SUDO_TO_ROOT losetup --associated "$img" --noheadings --output NAME)"

   mapfile -t loop_devices_list <<< "$loop_devices_output_before"

   for loop_devices_item in "${loop_devices_list[@]}" ; do
      ## Check if the block device still exists.
      if ! test -b "$loop_devices_item" ; then
         continue
      fi
      true "INFO: kpartx -d -s -v failed to unmount all loop devices, attempting to unmount..."
      ## Inside docker (and maybe other corner cases) 'kpartx -d -s -v "$img"' might fail to unmount loop devices.
      ## https://forums.whonix.org/t/docker-container-that-builds-whonix-images/17494/43

      ## Overwrite with '|| true' because it might exit non-zero.
      ## sudo kpartx -d -s -v /dev/loop0
      #del devmap : loop0p1
      #del devmap : loop0p2
      #loop0p3 is in use. Not removing
      #zsh: exit 1
      $SUDO_TO_ROOT kpartx -d -s -v "$loop_devices_item" || true "INFO: kpartx non-zero exit code."

      ## Overwrite with '|| true' because: Precaution. Testing. Unknown is strictly required.
      $SUDO_TO_ROOT losetup -d "$loop_devices_item" || true "INFO: losetup non-zero exit code."
   done

   true "INFO: Middle of $FUNCNAME. losetup --associated after kpartx -d (Delete partition mappings.)"
   local loop_devices_output_after
   loop_devices_output_after="$($SUDO_TO_ROOT losetup --associated "$img" --noheadings --output NAME)"

   if [ ! "$loop_devices_output_after" = "" ]; then
      error "Unmount failed. Variable loop_devices_output_after is non-empty."
   fi

   true "INFO: Middle of $FUNCNAME. Running losetup --all for debugging after kpartx -d (Delete partition mappings.)"
   $SUDO_TO_ROOT losetup --all
   sync

   if [ "$kpartx_only" = "true" ]; then
      true "INFO: kpartx_only=$kpartx_only, skipping debugging: ls -la $CHROOT_FOLDER"
   else
      if test -d "$CHROOT_FOLDER" ; then
         ls -la "$CHROOT_FOLDER"
      else
         true "INFO: CHROOT_FOLDER is not a directory. Perhaps already unmounted?"
      fi
   fi

   if [ "$kpartx_only" = "true" ]; then
      true "INFO: kpartx_only=$kpartx_only, skipping rmdir."
   else
      ## Delete temporary folder.
      ## It did not contain anything. It was only a mount point.
      $SUDO_TO_ROOT rmdir "$CHROOT_FOLDER" || true
      sync
   fi
}

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

main "$@"
