#!/bin/bash -p

# EMBA - EMBEDDED LINUX ANALYZER
#
# Copyright 2020-2025 Siemens Energy AG
# Copyright (c) 2017 - 2020, Mingeun Kim, Dongkwan Kim, Eunsoo Kim
# Copyright (c) 2015 - 2016, Daming Dominic Chen
#
# EMBA comes with ABSOLUTELY NO WARRANTY.
#
# This module is licensed under MIT
# See LICENSE file for usage of this software.
# SPDX-License-Identifier: MIT
#
# Original firmadyne project can be found here: https://github.com/firmadyne/firmadyne
# Original firmAE project can be found here: https://github.com/pr0v3rbs/FirmAE
#
# Author(s): Michael Messner

# Description:  Builds and emulates Linux firmware - this module is based on the great work of firmadyne and firmAE
#               Check out the original firmadyne project at https://github.com/firmadyne
#               Check out the original FirmAE project at https://github.com/pr0v3rbs/FirmAE
#               Currently this is an experimental module and needs to be activated separately via the -Q switch.
# Warning:      This module changes your network configuration and it could happen that your system looses
#               network connectivity.
#
# shellcheck disable=SC2153

L10_system_emulation() {
  module_log_init "${FUNCNAME[0]}"
  module_title "System emulation of Linux based embedded devices."

  # enable L10_DEBUG_MODE in scan profile or default config for further debugging capabilities:
  # * create_emulation_archive for all attempts
  # * do not stop after 2 detected network services
  # * enable experimental tests

  export SYS_ONLINE=0
  export TCP=""
  local lARCH_END=""
  local lMODULE_END=0
  local lUNSUPPORTED_ARCH=0
  export STATE_CHECK_MECHANISM="PING"

  if [[ "${FULL_EMULATION}" -eq 1 && "${RTOS}" -eq 0 ]]; then
    pre_module_reporter "${FUNCNAME[0]}"
    export MODULE_SUB_PATH="${MOD_DIR}"/"${FUNCNAME[0]}"

    local lIMAGE_DIR=""
    export IMAGE_NAME=""
    export ARCHIVE_PATH=""
    export HOSTNETDEV_ARR=()
    local lEMULATION_ENTRY=""
    export BINARY_DIR="${EXT_DIR}/EMBA_Live_bins"
    # lFIRMWARE_PATH_orig="$(abs_path "${FIRMWARE_PATH_BAK}")"
    LOG_PATH_MODULE=$(abs_path "${LOG_PATH_MODULE}")
    local lR_PATH_CNT=1
    local lIP_ADDRESS=""
    export R_PATH=""
    export MIN_TCP_SERV=2
    ### export IP_ADDRESS_=""

    # if we have a supported arch we move on with out emulation attempt
    if [[ "${ARCH}" == "MIPS"* || "${ARCH}" == "ARM"* || "${ARCH}" == "x86" ]]; then

      check_bmc_supermicro

      # WARNING: false was never tested ;)
      # Could be interesting for future extensions
      set_firmae_arbitration "true"

      # just to ensure nothing has already put a run.sh into our log
      find "${LOG_PATH_MODULE}" -name "run.sh" --delete 2>/dev/null || true

      # handling restarted scans with old emulation processes:
      if [[ -f "${L10_SYS_EMU_RESULTS}" ]] && grep -q "L10_system_emulation finished" "${LOG_DIR}"/emba.log; then
        print_ln
        print_output "[*] Found finished emulation process - trying to recover old emulation process"

        lEMULATION_ENTRY="$(grep "TCP ok" "${L10_SYS_EMU_RESULTS}" | sort -k 7 -t ';' | tail -1)"
        lIP_ADDRESS=$(grep "TCP ok" "${L10_SYS_EMU_RESULTS}" | sort -k 7 -t ';' | tail -1 | cut -d\; -f9 | awk '{print $3}')
        lIMAGE_DIR="$(grep "TCP ok" "${L10_SYS_EMU_RESULTS}" | sort -k 7 -t ';' | tail -1 | cut -d\; -f11)"
        ARCHIVE_PATH="${OLD_LOG_DIR}""/""${lIMAGE_DIR}"

        print_output "[*] Recovered IP address: ${ORANGE}${lIP_ADDRESS}${NC}"
        print_output "[*] Recovered IMAGE_DIR: ${ORANGE}${lIMAGE_DIR}${NC}"
        print_output "[*] Recovered ARCHIVE_PATH: ${ORANGE}${ARCHIVE_PATH}${NC}"

        if [[ -v ARCHIVE_PATH ]] && [[ -f "${ARCHIVE_PATH}"/run.sh ]]; then
          IMAGE_NAME="$(tr ' ' '\n' < "${ARCHIVE_PATH}"/run.sh | grep -o "file=.*" | cut -d '/' -f2)"
          print_output "[*] Identified IMAGE_NAME: ${ORANGE}${IMAGE_NAME}${NC}" "no_log"
          print_output "[+] Startup script (run.sh) found in old logs ... restarting emulation process now"
          mapfile -t HOSTNETDEV_ARR < <(grep "ip link set.*up" "${ARCHIVE_PATH}"/run.sh | awk '{print $4}' | sort -u)

          if [[ "${lEMULATION_ENTRY}" == *"ICMP not ok"* ]]; then
            print_output "[*] Testing system recovery with hping instead of ping" "no_log"
            STATE_CHECK_MECHANISM="HPING"
          fi
          # we should get TCP="ok" and SYS_ONLINE=1 back
          if restart_emulation "${lIP_ADDRESS}" "${IMAGE_NAME}" 1 "${STATE_CHECK_MECHANISM}"; then
            print_output "[+] System recovery was successful. Further live analysis possible for IP ${lIP_ADDRESS}"
          else
            print_output "[-] System recovery went wrong. No further analysis possible"
          fi
        else
          print_output "[-] No archive path found in old logs ... restarting emulation process not possible"
        fi
      fi

      # this is our main emulation area:
      if [[ "${SYS_ONLINE}" -ne 1 ]] && [[ "${TCP}" != "ok" ]]; then
        # ROOT_PATH array is exported from the pre-checking phase
        # shellcheck disable=SC2153
        for R_PATH in "${ROOT_PATH[@]}" ; do
          print_output "[*] Testing root path (${ORANGE}${lR_PATH_CNT}${NC}/${ORANGE}${#ROOT_PATH[@]}${NC}): ${ORANGE}${R_PATH}${NC}"
          if grep -q "P55_unblob_extractor nothing reported" "${P55_LOG}" 2>/dev/null; then
            if ! grep -q "P60_deep_extractor nothing reported" "${P60_LOG}" 2>/dev/null; then
              [[ -f "${P60_LOG}" ]] && write_link "p60"
            fi
          else
            [[ -f "${P55_LOG}" ]] && write_link "p55"
          fi

          if [[ -n "${D_END}" ]]; then
            export TAPDEV_0="tap0_0"
            local lARCH_END=""

            lARCH_END="${ARCH,,}"
            lARCH_END+="${D_END,,}"

            # default is ARM_SF -> we only need to check if it is HF
            # The information is based on the results of architecture_check()
            if [[ -n "${ARM_HF}" ]] && [[ "${ARM_HF}" -gt "${ARM_SF:-0}" ]]; then
              print_output "[*] ARM hardware floating detected"
              lARCH_END+="hf"
            fi

            if [[ "${lARCH_END}" == "armbe"* ]] || [[ "${lARCH_END}" == "mips64r2"* ]] || [[ "${lARCH_END}" == "mips64_3"* ]]; then
              print_output "[-] Found NOT supported architecture ${ORANGE}${lARCH_END}${NC}"
              [[ -f "${P99_LOG}" ]] && write_link "p99"
              print_output "[-] Please open a new issue here: https://github.com/e-m-b-a/emba/issues"
              lUNSUPPORTED_ARCH=1
              return
            fi

            # just in case we remove the return in the unsupported arch checker for testing:
            if [[ "${lUNSUPPORTED_ARCH}" -ne 1 ]]; then
              print_output "[*] Found supported architecture ${ORANGE}${lARCH_END}${NC}"
              write_link "p99"
            fi

            pre_cleanup_emulator

            main_emulation "${R_PATH}" "${lARCH_END}"

            if [[ -d "${MNT_POINT}" ]]; then
              rm -r "${MNT_POINT}" || true
            fi

            if [[ "${SYS_ONLINE}" -eq 1 ]] && [[ "${TCP}" == "ok" ]]; then
              # do not test other root paths if we are already online (some ports are available)
              if [[ "${L10_DEBUG_MODE}" -eq 1 ]]; then
                print_output "[!] Debug mode: We do not stop here ..."
              else
                break
              fi
            fi
          else
            print_output "[!] No supported architecture detected"
          fi
          ((lR_PATH_CNT+=1))
        done
        print_system_emulation_results
      fi
      lMODULE_END=1
    else
      print_output "[!] No supported architecture found.\\n"
      print_output "[!] Curently supported: ${ORANGE}ARM${NC}, ${ORANGE}MIPS${NC} and ${ORANGE}x86${NC}.\\n"
      lMODULE_END=0
    fi
  fi

  if [[ "${lMODULE_END}" -ne 0 ]] && [[ -f "${L10_SYS_EMU_RESULTS}" ]]; then
    if [[ $(grep -c "TCP ok" "${L10_SYS_EMU_RESULTS}" || true) -gt 0 ]]; then
      print_ln
      print_output "[+] Identified the following system emulation results (with running network services):"
      export HOSTNETDEV_ARR=()
      local lIMAGE_DIR=""
      local lSYS_EMUL_POS_ENTRY=""
      lSYS_EMUL_POS_ENTRY="$(grep "TCP ok" "${L10_SYS_EMU_RESULTS}" | sort -t ';' -k7 -n -r | head -1 || true)"
      print_output "$(indent "$(orange "${lSYS_EMUL_POS_ENTRY}")")"

      lIP_ADDRESS=$(echo "${lSYS_EMUL_POS_ENTRY}" | grep "TCP ok" | sort -k 7 -t ';' | tail -1 | cut -d\; -f9 | awk '{print $3}')
      lIMAGE_DIR="$(echo "${lSYS_EMUL_POS_ENTRY}" | grep "TCP ok" | sort -k 7 -t ';' | tail -1 | cut -d\; -f11)"
      ARCHIVE_PATH="${LOG_PATH_MODULE}""/""${lIMAGE_DIR}"

      print_ln
      print_output "[*] Identified IP address: ${ORANGE}${lIP_ADDRESS}${NC}" "no_log"
      print_output "[*] Identified IMAGE_DIR: ${ORANGE}${lIMAGE_DIR}${NC}" "no_log"
      print_output "[*] Identified ARCHIVE_PATH: ${ORANGE}${ARCHIVE_PATH}${NC}" "no_log"

      if [[ -v ARCHIVE_PATH ]] && [[ -f "${ARCHIVE_PATH}"/run.sh ]]; then
        IMAGE_NAME="$(tr ' ' '\n' < "${ARCHIVE_PATH}"/run.sh | grep -o "file=.*" | cut -d '/' -f2)"
        print_output "[*] Identified IMAGE_NAME: ${ORANGE}${IMAGE_NAME}${NC}" "no_log"
        print_output "[+] Identified emulation startup script (run.sh) in ARCHIVE_PATH ... starting emulation process for further analysis" "no_log"
        print_ln
        mapfile -t HOSTNETDEV_ARR < <(grep "ip link set.*up" "${ARCHIVE_PATH}"/run.sh | awk '{print $4}' | sort -u)
        if [[ "${lSYS_EMUL_POS_ENTRY}" == *"ICMP not ok"* ]]; then
          print_output "[*] Testing system recovery with hping instead of ping" "no_log"
          STATE_CHECK_MECHANISM="HPING"
        fi

        if [[ "${FINAL_FW_RM}" -ne 1 ]]; then
          # we should get TCP="ok" and SYS_ONLINE=1 back
          if restart_emulation "${lIP_ADDRESS}" "${IMAGE_NAME}" 1 "${STATE_CHECK_MECHANISM}"; then
            print_output "[+] System recovery was successful. Further live analysis possible for IP ${lIP_ADDRESS}."
          else
            print_output "[-] System recovery went wrong. No further analysis possible."
          fi
        else
          print_output "[*] System recovery not possible - FINAL_FW_RM option set! No further analysis possible."
        fi
        export IP_ADDRESS_="${lIP_ADDRESS}"
      else
        print_output "[-] ${ORANGE}WARNING:${NC} No archive path found in logs ... restarting emulation process for further analysis not possible" "no_log"
      fi
    fi
  fi

  module_end_log "${FUNCNAME[0]}" "${lMODULE_END}"
}

check_bmc_supermicro() {
  if [[ -f "${S06_CSV_LOG}" ]]; then
    if grep -q "supermicro:bmc" "${S06_CSV_LOG}"; then
      print_output "[-] WARNING: Supermicro firmware found - Specific qemu emulation not supported"
    fi
  fi
}

print_system_emulation_results() {
  if [[ -f "${L10_SYS_EMU_RESULTS}" ]]; then
    sub_module_title "System emulation results"
    print_output "EMBA was able to identify the following system emulation results:"
    print_ln

    local lEMU_RES=""

    while read -r lEMU_RES; do
      lEMU_RES=$(echo "${lEMU_RES}" | cut -d\; -f2-)
      if [[ "${lEMU_RES}" == *"ICMP ok"* ]] || [[ "${lEMU_RES}" == *"TCP-0 ok"* ]] || [[ "${lEMU_RES}" == *"TCP ok"* ]]; then
        print_output "[+] ${lEMU_RES}"
      else
        print_output "[*] ${lEMU_RES}"
      fi
    done < "${L10_SYS_EMU_RESULTS}"
  fi
}

pre_cleanup_emulator() {
  # this cleanup function is to ensure that we have no mounts from previous tests mounted
  local lCHECK_MOUNTS_ARR=()
  local lMOUNT=""

  print_output "[*] Checking for not unmounted proc, sys and run in log directory" "no_log"
  mapfile -t lCHECK_MOUNTS_ARR < <(mount | grep "${LOG_DIR}" | grep "proc\|sys\|run" || true)
  for lMOUNT in "${lCHECK_MOUNTS_ARR[@]}"; do
    print_output "[*] Unmounting ${lMOUNT}" "no_log"
    lMOUNT=$(echo "${lMOUNT}" | cut -d\  -f3)
    umount -l "${lMOUNT}" || true
  done
}

cleanup_tap() {
  local lTAP_CLEAN_ARR=()
  local lTAP_TO_CLEAN=""

  mapfile -t lTAP_CLEAN_ARR < <(ifconfig | grep tap | cut -d: -f1 || true)
  for lTAP_TO_CLEAN in "${lTAP_CLEAN_ARR[@]}"; do
    print_output "[*] Cleaning up TAP interface ${lTAP_TO_CLEAN}"
    tunctl -d "${lTAP_TO_CLEAN}" || print_error "[-] Error in tap cleanup"
  done
}

create_emulation_filesystem() {
  # based on the original firmAE script:
  # https://github.com/pr0v3rbs/FirmAE/blob/master/scripts/makeImage.sh

  sub_module_title "Create Qemu filesystem for full system emulation"
  local lROOT_PATH="${1:-}"
  local lARCH_END="${2:-}"
  local lIMAGE_SIZE=""
  local lNVRAM_FILE_LIST=()
  local lNVRAM_FILE=""
  local lCURRENT_DIR=""
  export DEVICE="NA"
  export IMAGE_NAME=""
  IMAGE_NAME="$(basename "${lROOT_PATH}")_${lARCH_END}-${RANDOM}"

  export MNT_POINT="${LOG_PATH_MODULE}/emulation_tmp_fs_EMBA"
  if [[ -d "${MNT_POINT}" ]]; then
    MNT_POINT="${MNT_POINT}"-"${RANDOM}"
  fi
  mkdir "${MNT_POINT}" || true

  print_output "[*] Create Qemu filesystem for emulation - ${lROOT_PATH}.\\n"
  lIMAGE_SIZE="$(du -b --max-depth=0 "${lROOT_PATH}" | awk '{print $1}')"
  lIMAGE_SIZE=$((lIMAGE_SIZE + 400 * 1024 * 1024))

  print_output "[*] Size of filesystem for emulation - ${ORANGE}${lIMAGE_SIZE}${NC}.\\n"
  print_output "[*] Name of filesystem for emulation - ${ORANGE}${IMAGE_NAME}${NC}.\\n"
  qemu-img create -f raw "${LOG_PATH_MODULE}/${IMAGE_NAME}" "${lIMAGE_SIZE}"
  chmod a+rw "${LOG_PATH_MODULE}/${IMAGE_NAME}"

  print_output "[*] Creating Partition Table"
  echo -e "o\nn\np\n1\n\n\nw" | /sbin/fdisk "${LOG_PATH_MODULE}/${IMAGE_NAME}"

  print_output "[*] Identify Qemu Image device for ${ORANGE}${LOG_PATH_MODULE}/${IMAGE_NAME}${NC}"
  local lCNT=0
  while [[ "${DEVICE:-NA}" == "NA" ]]; do
    DEVICE="$(add_partition_emulation "${LOG_PATH_MODULE}/${IMAGE_NAME}")"
    lCNT=$((lCNT+1))
    if [[ "${DEVICE:-NA}" == "NA" ]] && [[ "${lCNT}" -gt 10 ]]; then
      print_output "[-] No Qemu Image device identified - return from ${FUNCNAME[0]}"
      return
    fi
    if [[ "${DEVICE:-NA}" != "NA" ]]; then
      break
    fi
    print_output "[*] Info: Initial identification for Qemu Image device for ${ORANGE}${LOG_PATH_MODULE}/${IMAGE_NAME}${NC} failed ... trying again"
    losetup || tee -a "${LOG_FILE}"
    losetup -D
    sleep 5
    losetup || tee -a "${LOG_FILE}"
  done

  print_output "[*] Qemu Image device: ${ORANGE}${DEVICE}${NC}"
  sleep 1
  print_output "[*] Device mapper created at ${ORANGE}${DEVICE}${NC}"

  print_output "[*] Creating Filesystem"
  sync
  mkfs.ext2 "${DEVICE}" || ( print_output "[-] Error in filesystem creation" && return )

  print_output "[*] Mounting QEMU Image Partition 1 to ${ORANGE}${MNT_POINT}${NC}"
  mount "${DEVICE}" "${MNT_POINT}" || ( print_output "[-] Error in mounting the filesystem" && return )

  if mount | grep -q "${MNT_POINT}"; then
    print_output "[*] Copy extracted root filesystem to new QEMU image"
    cp -prf "${lROOT_PATH}"/* "${MNT_POINT}"/ || (print_output "[-] Warning: Root filesystem not copied!" && return)

    print_output "[*] Binwalk v3+ creates raw files on extraction. We remove these files from our emulation root directory"
    find "${MNT_POINT}" -name "*.raw" -delete || true

    # ensure that the needed permissions for exec files are set correctly
    # This is needed at some firmwares have corrupted permissions on ELF or sh files
    print_output "[*] Multiple firmwares have broken links and script and ELF permissions - We fix them now"
    "${HELP_DIR}"/fix_bins_lnk_emulation.sh "${MNT_POINT}"

    print_output "[*] Creating EMBA emulation helper directories within the firmware environment"
    mkdir -p "${MNT_POINT}/firmadyne/libnvram/" || true
    mkdir -p "${MNT_POINT}/firmadyne/libnvram.override/" || true

    print_output "[*] Patching filesystem (chroot)"
    cp "$(command -v busybox)" "${MNT_POINT}" || true
    cp "$(command -v bash-static)" "${MNT_POINT}" || true

    if [[ -f "${S24_CSV_LOG}" ]]; then
      # kernelInit is getting the output of the init command line we get from s24
      if grep -q ";rdinit=" "${S24_CSV_LOG}"; then
        print_output "[*] Found ${ORANGE}rdinit${NC} entry for kernel - see ${ORANGE}${S24_LOG}${NC}:"
        grep ";rdinit=/" "${S24_CSV_LOG}" | cut -d\; -f4 | sed -e 's/.*rdinit=/rdinit=/' | awk '{print $1}'| sort -u | tee -a "${MNT_POINT}"/kernelInit
        tee -a "${LOG_FILE}" < "${MNT_POINT}"/kernelInit
      elif grep -q ";init=" "${S24_CSV_LOG}"; then
        print_output "[*] Found ${ORANGE}init${NC} entry for kernel - see ${ORANGE}${S24_LOG}${NC}:"
        grep ";init=/" "${S24_CSV_LOG}" | cut -d\; -f4 | sed -e 's/.*init=/init=/' | awk '{print $1}'| sort -u | tee -a "${MNT_POINT}"/kernelInit
        tee -a "${LOG_FILE}" < "${MNT_POINT}"/kernelInit
      fi
    else
      print_output "[-] No results from S24 kernel module found"
    fi

    print_output "[*] fixImage.sh (chroot)"
    cp "${MODULE_SUB_PATH}/fixImage.sh" "${MNT_POINT}" || true
    EMBA_BOOT=${EMBA_BOOT} EMBA_ETC=${EMBA_ETC} timeout --preserve-status --signal SIGINT 120 chroot "${MNT_POINT}" /busybox ash /fixImage.sh || true | tee -a "${LOG_FILE}"

    print_output "[*] inferFile.sh (chroot)"
    # -> this re-creates init file and builds up the service which is ued from run_service.sh
    cp "${MODULE_SUB_PATH}/inferFile.sh" "${MNT_POINT}" || true
    EMBA_BOOT=${EMBA_BOOT} EMBA_ETC=${EMBA_ETC} timeout --preserve-status --signal SIGINT 120 chroot "${MNT_POINT}" /bash-static /inferFile.sh | tee -a "${LOG_FILE}"

    print_output "[*] inferService.sh (chroot)"
    cp "${MODULE_SUB_PATH}/inferService.sh" "${MNT_POINT}" || true
    EMBA_BOOT=${EMBA_BOOT} EMBA_ETC=${EMBA_ETC} timeout --preserve-status --signal SIGINT 120 chroot "${MNT_POINT}" /bash-static /inferService.sh | tee -a "${LOG_FILE}"

    if [[ -f "${MODULE_SUB_PATH}/injection_check.sh" ]]; then
      # injection checker - future extension
      local lINJECTION_MARKER="${RANDOM}"
      if [[ -d "${MNT_POINT}"/bin ]]; then
        cp "${MODULE_SUB_PATH}/injection_check.sh" "${MNT_POINT}"/bin/a || true
        chmod a+x "${MNT_POINT}/bin/a" || true
        sed -i 's/asdfqwertz/'"d34d_${lINJECTION_MARKER}"'/' "${MNT_POINT}"/bin/a || true
      fi
      if [[ -d "${MNT_POINT}"/sbin ]]; then
        cp "${MODULE_SUB_PATH}/injection_check.sh" "${MNT_POINT}"/sbin/a || true
        chmod a+x "${MNT_POINT}/sbin/a" || true
        sed -i 's/asdfqwertz/'"d34d_${lINJECTION_MARKER}"'/' "${MNT_POINT}"/sbin/a || true
      fi
      if [[ -f "${MNT_POINT}/sbin/a" ]] || [[ -f "${MNT_POINT}/bin/a" ]]; then
        print_output "[*] Generated injection scripts with marker ${ORANGE}${lINJECTION_MARKER}${NC}."
        cat "${MNT_POINT}"/bin/a
      fi
    fi

    if [[ -e "${MNT_POINT}/kernelInit" ]]; then
      print_output "[*] Backup ${MNT_POINT}/kernelInit:"
      tee -a "${LOG_FILE}" < "${MNT_POINT}/kernelInit"
      rm "${MNT_POINT}/kernelInit"
    fi

    rm "${MNT_POINT}/fixImage.sh" || true
    rm "${MNT_POINT}/inferFile.sh" || true
    rm "${MNT_POINT}/busybox" || true
    rm "${MNT_POINT}/bash-static" || true

    print_output "[*] Setting up system mode emulation environment on target filesystem"
    # FirmAE/firmadyne recompiled binaries + addons
    local lBINARIES_ARR=( "busybox" "console" "libnvram_dbg.so" "libnvram_nondbg.so" "libnvram_ioctl_dbg.so" "libnvram_ioctl_nondbg.so" "strace" "netcat" "gdb" "gdbserver" )
    local lBINARY_NAME=""
    local lBINARY_PATH=""
    local lTMP_EXEC_64_CNT=0
    # quick check if we use stat/time or stat64/time64 on the target os - needed for libnvram
    lTMP_EXEC_64_CNT=$(find "${MNT_POINT}" -type f -name "*libc*" -not -path "*/firmadyne*" -exec objdump -t {} \; 2>/dev/null | grep -c " time64" || true)
    # default state for libnvram
    local lMUSL_VER="1.1.24"
    if [[ "${lTMP_EXEC_64_CNT}" -gt 0 ]]; then
      # we use the libnvram compiled with musl 1.2.x which moves all 32-bit archs to 64-bit time_t
      lMUSL_VER="1.2.5"
    fi

    for lBINARY_NAME in "${lBINARIES_ARR[@]}"; do
      lBINARY_PATH=$(get_binary "${lBINARY_NAME}" "${lARCH_END}" "${lMUSL_VER}")
      if [[ ! -f "${lBINARY_PATH}" ]]; then
        print_output "[-] Missing ${ORANGE}${lBINARY_NAME} / ${lBINARY_PATH:-NA} / ${lARCH_END}${NC} - no setup possible"
        continue
      fi
      print_output "[*] Setting up ${ORANGE}${lBINARY_NAME}${NC} - ${ORANGE}${lARCH_END}${NC} (${ORANGE}${lBINARY_PATH}${NC})"
      cp "${lBINARY_PATH}" "${MNT_POINT}/firmadyne/${lBINARY_NAME}"
      chmod a+x "${MNT_POINT}/firmadyne/${lBINARY_NAME}"
    done

    mknod -m 666 "${MNT_POINT}/firmadyne/ttyS1" c 4 65
    mknod -m 666 "${MNT_POINT}/firmadyne/ttyAMA1" c 4 65

    print_output "[*] Setting up emulation scripts"
    cp "${MODULE_SUB_PATH}/preInit.sh" "${MNT_POINT}/firmadyne/preInit.sh" || true
    chmod a+x "${MNT_POINT}/firmadyne/preInit.sh"

    # network.sh
    cp "${MODULE_SUB_PATH}/network.sh" "${MNT_POINT}/firmadyne/network.sh" || true
    chmod a+x "${MNT_POINT}/firmadyne/network.sh"

    # init_service.sh
    cp "${MODULE_SUB_PATH}/init_service.sh" "${MNT_POINT}/firmadyne/init_service.sh" || true
    chmod a+x "${MNT_POINT}/firmadyne/init_service.sh"

    # run_service.sh
    cp "${MODULE_SUB_PATH}/run_service.sh" "${MNT_POINT}/firmadyne/run_service.sh" || true
    chmod a+x "${MNT_POINT}/firmadyne/run_service.sh"

    chmod a+x "${MNT_POINT}/firmadyne/init"
    cp "${MNT_POINT}/firmadyne/init" "${LOG_PATH_MODULE}/firmadyne_init"

    lCURRENT_DIR=$(pwd)
    cd "${MNT_POINT}" || exit
    mapfile -t lNVRAM_FILE_LIST < <(find . -xdev -type f -name "*nvram*")
    for lNVRAM_FILE in "${lNVRAM_FILE_LIST[@]}"; do
      if file "${lNVRAM_FILE}" | grep -q "ASCII text"; then
        if ! [[ -d "${LOG_PATH_MODULE}"/nvram ]]; then
          mkdir "${LOG_PATH_MODULE}"/nvram
        fi
        lNVRAM_FILE="${lNVRAM_FILE/\.}"
        print_output "[*] Found possible NVRAM default file ${ORANGE}${lNVRAM_FILE}${NC} -> setup /firmadyne directory"
        echo "${lNVRAM_FILE}" >> "${LOG_PATH_MODULE}"/nvram/nvram_files
        cp ."${lNVRAM_FILE}" "${LOG_PATH_MODULE}"/nvram/
      fi
    done
    cd "${lCURRENT_DIR}" || exit

  else
    print_output "[!] Filesystem mount failed"
  fi
}

link_libnvram_so() {
  # pre-requisite is the mounted filesytem
  local lMNT_POINT="${1:-}"
  # default to debug mode with a lot of output - usually in the finale emulation mode we use the nondbg mode
  local lDBG_MODE="${2:-dbg}"

  # ensure we have a dbg libnvram for the initial identification
  if [[ -s "${lMNT_POINT}/firmadyne/libnvram.so" ]]; then
    rm "${lMNT_POINT}/firmadyne/libnvram.so"
  fi
  if [[ -s "${lMNT_POINT}/firmadyne/libnvram_ioctl.so" ]]; then
    rm "${lMNT_POINT}/firmadyne/libnvram_ioctl.so"
  fi
  if [[ -f "${lMNT_POINT}/firmadyne/libnvram_${lDBG_MODE}.so" ]]; then
    print_output "[*] Linking to ${lDBG_MODE} libnvram.so"
    ln -sr "${lMNT_POINT}/firmadyne/libnvram_${lDBG_MODE}.so" "${lMNT_POINT}/firmadyne/libnvram.so" || true
  fi
  if [[ -f "${lMNT_POINT}/firmadyne/libnvram_ioctl_${lDBG_MODE}.so" ]]; then
    print_output "[*] Linking to ${lDBG_MODE} libnvram_ioctl.so"
    ln -sr "${lMNT_POINT}/firmadyne/libnvram_ioctl_${lDBG_MODE}.so" "${lMNT_POINT}/firmadyne/libnvram_ioctl.so" || true
  fi
}

main_emulation() {
  R_PATH="${1:-}"
  local lARCH_END="${2:-}"
  export BOOTED="NONE"
  local lINIT_FILES_ARR=()

  create_emulation_filesystem "${R_PATH}" "${lARCH_END}"
  # here we set the global DEVICE which will be later used as local lDEVICE

  if [[ -f "${LOG_PATH_MODULE}"/firmadyne_init ]]; then
    print_ln
    print_output "[*] Processing init files:"
    local lINIT_FILE=""
    while read -r lINIT_FILE; do
      # check the number of '/' in our possible init file
      # if we are too deep (-gt 5) then we will skip this init entry
      # usually this looks the following
      # /bin/linuxrc
      local lINIT_DEPTH="${lINIT_FILE//[^\/]}"
      if [[ "${#lINIT_DEPTH}" -gt 5 ]]; then
        continue
      fi
      lINIT_FILES_ARR+=("${lINIT_FILE}")
      echo "${lINIT_FILE}" | tee -a "${LOG_FILE}"
    done < "${LOG_PATH_MODULE}"/firmadyne_init
  else
    print_output "[-] WARNING: init file not created! Processing backup dummy init"
    lINIT_FILES_ARR+=( "/dummy_init" )
  fi

  local lINDEX=1
  local lBAK_INIT_BACKUP=""
  local lBAK_INIT_ORIG=""
  local lINIT_OUT=""
  local lINIT_FNAME=""
  export IPS_INT_VLAN=()
  export ICMP=""
  export TCP_0=""
  export TCP=""
  local lSERVICE_NAME=""
  local lINIT_FILE=""

  for lINIT_FILE in "${lINIT_FILES_ARR[@]}"; do
    local lDEVICE="NA"
    lINIT_FNAME=$(basename "${lINIT_FILE}")
    # this is the main init entry - we modify it later for special cases:
    export KINIT="init=/firmadyne/preInit.sh"
    lINIT_OUT="${MNT_POINT}/firmadyne/preInit.sh"

    sub_module_title "[*] Processing init file ${ORANGE}${lINIT_FILE} (${lINDEX}/${#lINIT_FILES_ARR[@]})${NC}"
    if ! mount | grep -q "${MNT_POINT}"; then
      local lCNT=0
      while [[ "${lDEVICE:-NA}" == "NA" ]]; do
        lDEVICE="$(add_partition_emulation "${LOG_PATH_MODULE}/${IMAGE_NAME}")"
        lCNT=$((lCNT+1))
        if [[ "${lDEVICE:-NA}" == "NA" ]] && [[ "${lCNT}" -gt 10 ]]; then
          print_output "[-] No Qemu Image device identified - continue now with next init entry"
          continue 2
        fi
        sleep 5
      done
      print_output "[*] Device mapper created at ${ORANGE}${lDEVICE}${NC}"
      print_output "[*] Mounting QEMU Image Partition 1 to ${ORANGE}${MNT_POINT}${NC}"
      mount "${lDEVICE}" "${MNT_POINT}" || true
    elif [[ -n "${DEVICE}" ]]; then
      lDEVICE="${DEVICE}"
    else
      print_output "[-] No Qemu Image device identified"
      break
    fi

    link_libnvram_so "${MNT_POINT}" "dbg"

    if [[ -n "${lBAK_INIT_ORIG}" ]]; then
      print_output "[*] Restoring old init file: ${lBAK_INIT_ORIG}"
      cp -pr "${lBAK_INIT_BACKUP}" "${lBAK_INIT_ORIG}" || print_error "[-] Error restoring old init file ${lBAK_INIT_ORIG}"
      lBAK_INIT_BACKUP=""
      lBAK_INIT_ORIG=""
    fi

    print_ln
    print_output "[*] Firmware Init file details:"
    print_output "$(indent "$(orange "$(file "${MNT_POINT}""${lINIT_FILE}" || true)")")"

    print_output "[*] EMBA Init starter file details:"
    print_output "$(indent "$(orange "$(file "${lINIT_OUT}" || true)")")"
    print_ln

    # we deal with something which is not a script:
    if file "${MNT_POINT}""${lINIT_FILE}" | grep -q "symbolic link\|ELF"; then
      print_output "[*] Backup original init file ${ORANGE}${lINIT_OUT}${NC}"
      lBAK_INIT_ORIG="${lINIT_OUT}"
      lBAK_INIT_BACKUP="${LOG_PATH_MODULE}"/"$(basename "${lINIT_OUT}".init)"

      # write the init ELF file or sym link to the EMBA preInit script:
      # INIT_OUT="${MNT_POINT}""/firmadyne/preInit.sh"
      cp -pr "${lINIT_OUT}" "${lBAK_INIT_BACKUP}" || true

      print_output "[*] Add ${lINIT_FILE} entry to ${ORANGE}${lINIT_OUT}${NC}"
      # we always add the identified init entry to the EMBA preInit script
      if ! (grep -q "${lINIT_FILE}" "${lINIT_OUT}"); then
        echo "${lINIT_FILE} &" >> "${lINIT_OUT}" || true
        # ensure we give the system some time to boot via the original init file
        echo "/firmadyne/busybox sleep 60" >> "${lINIT_OUT}" || true
      fi
    fi

    local lFS_MOUNTS_INIT_ARR=()
    # if we are dealing with a startup script we are going to use this as the init entry
    # and add our starters at the end of the original script
    if file "${MNT_POINT}""${lINIT_FILE}" | grep -q "text executable\|ASCII text"; then
      # we deal with a startup script
      lINIT_OUT="${MNT_POINT}""${lINIT_FILE}"

      export KINIT="init=${lINIT_FILE}"

      find "${lINIT_OUT}" -xdev -maxdepth 1 -ls || true
      print_output "[*] Backup original init file ${ORANGE}${lINIT_OUT}${NC}"
      lBAK_INIT_ORIG="${lINIT_OUT}"
      lBAK_INIT_BACKUP="${LOG_PATH_MODULE}"/"$(basename "${lINIT_OUT}".init)"
      cp -pr "${lINIT_OUT}" "${lBAK_INIT_BACKUP}"

      # identify mount operations for later handling and disabling
      mapfile -t lFS_MOUNTS_INIT_ARR < <(grep -E "^mount\ -t\ .*\ .*mtd.* /.*" "${MNT_POINT}""${lINIT_FILE}" | sort -u || true)

      # just in case we have issues with permissions
      chmod +x "${MNT_POINT}""${lINIT_FILE}"

      # just in case there is an exit in the init -> comment it
      sed -i -r 's/(.*exit\ [0-9])$/\#\ \1/' "${MNT_POINT}""${lINIT_FILE}"
    fi

    # Beside the check of init we also try to find other mounts for further filesystems
    # probably we need to tweak this further to also find mounts in binaries - strings?!?
    local lFS_MOUNTS_FS_ARR=()
    if [[ -d "${FIRMWARE_PATH}" ]]; then
      # TODO: fix the tr commands do escape_print or so
      mapfile -t lFS_MOUNTS_FS_ARR < <(find "${FIRMWARE_PATH}" -xdev -type f -exec grep -a -h -E "^mount\ -t\ .*\ .*mtd.* /.*" {} \; 2>/dev/null | tr -d '"' | tr -d '$' | sort -u || true)
    fi

    local lFS_MOUNTS_ARR=()
    lFS_MOUNTS_ARR=( "${lFS_MOUNTS_INIT_ARR[@]}" "${lFS_MOUNTS_FS_ARR[@]}" )
    mapfile -t lFS_MOUNTS_ARR < <(printf "%s\n" "${lFS_MOUNTS_ARR[@]}" | sort -u)

    handle_fs_mounts "${lINIT_FILE}" "${lFS_MOUNTS_ARR[@]}"

    if (grep -q "preInit.sh" "${MNT_POINT}""${lINIT_FILE}"); then
      # if have our own backup init script we need to remove our own entries now
      sed -i -r 's%(.*preInit.sh.*)%\#\ \1%' "${MNT_POINT}""${lINIT_FILE}"
      sed -i -r 's%(/firmadyne/init_service.sh.*)%\#\ \1%' "${MNT_POINT}""${lINIT_FILE}"
      sed -i -r 's%(/firmadyne/network.sh.*)%\#\ \1%' "${MNT_POINT}""${lINIT_FILE}"
      sed -i -r 's%(/firmadyne/run_service.sh.*)%\#\ \1%' "${MNT_POINT}""${lINIT_FILE}"
    fi

    if [[ "${lINIT_OUT}" != *"preInit.sh" ]]; then
      if ( grep -q "/firmadyne/preInit.sh" "${lINIT_OUT}"); then
        print_output "[*] preInit.sh entry already available in init ${ORANGE}${lINIT_OUT}${NC} -> removing now"
        sed -i '/\/firmadyne\/preInit\.sh\ &/d' "${lINIT_OUT}"
      fi
      echo "/firmadyne/preInit.sh &" >> "${lINIT_OUT}" || print_error "[-] Some error occured while adding the preInit.sh entry to ${lINIT_OUT}"
    fi

    if ( grep -q "/firmadyne/init_service.sh" "${lINIT_OUT}"); then
      print_output "[*] init_server.sh entry already available in init ${ORANGE}${lINIT_OUT}${NC} -> removing now"
      sed -i '/\/firmadyne\/init_service\.sh\ &/d' "${lINIT_OUT}"
    fi
    if [[ -f "${MNT_POINT}/firmadyne/startup_service" ]]; then
      while read -r lSERVICE_NAME; do
        print_output "[*] Created init service entry for starting service ${ORANGE}${lSERVICE_NAME}${NC}"
      done < "${MNT_POINT}/firmadyne/startup_service"
      echo "/firmadyne/init_service.sh &" >> "${lINIT_OUT}" || print_error "[-] Some error occured while adding the init_service entry to ${lINIT_OUT}"
    fi

    if ( grep -q "/firmadyne/network.sh" "${lINIT_OUT}"); then
      print_output "[*] network.sh entry already available in init ${ORANGE}${lINIT_OUT}${NC} -> removing now"
      sed -i '/\/firmadyne\/network\.sh\ &/d' "${lINIT_OUT}"
    fi

    print_output "[*] Add network.sh entry to ${ORANGE}${lINIT_OUT}${NC}"
    echo "" >> "${lINIT_OUT}" || true
    echo "/firmadyne/network.sh &" >> "${lINIT_OUT}" || print_error "[-] Some error occured while adding the network.sh entry to ${lINIT_OUT}"

    if ( grep -q "/firmadyne/run_service.sh" "${lINIT_OUT}"); then
      print_output "[*] run_service.sh entry already available in init ${ORANGE}${lINIT_OUT}${NC} -> removing now"
      sed -i '/\/firmadyne\/run_service\.sh\ &/d' "${lINIT_OUT}"
    fi
    if [[ -f "${MNT_POINT}/firmadyne/service" ]]; then
      while read -r lSERVICE_NAME; do
        print_output "[*] Created service entry for starting service ${ORANGE}${lSERVICE_NAME}${NC}"
      done < "${MNT_POINT}/firmadyne/service"
      echo "/firmadyne/run_service.sh &" >> "${lINIT_OUT}" || print_error "[-] Some error occured while adding the run_service entry to ${lINIT_OUT}"
    fi

    # ensure we have not sleep entry and it is not the EMBA backup init script
    if ( grep -q "/firmadyne/busybox sleep 36000" "${lINIT_OUT}"); then
      print_output "[*] busybox sleep 36000 entry already available in init ${ORANGE}${lINIT_OUT}${NC}  -> removing now"
      sed -i '/\/firmadyne\/busybox\ sleep\ 36000/d' "${lINIT_OUT}"
    fi
    if ! ( grep -q "/firmadyne/busybox sleep 36000" "${lINIT_OUT}") && ! (grep -q "Execute EMBA " "${lINIT_OUT}"); then
      # trendnet TEW-828DRU_1.0.7.2, etc...
      echo "/firmadyne/busybox sleep 36000" >> "${lINIT_OUT}" || print_error "[-] Some error occured while adding the busybox sleep entry to ${lINIT_OUT}"
    fi

    print_ln
    print_output "[*] EMBA init starter file: ${ORANGE}${lINIT_OUT}${NC}"
    tee -a "${LOG_FILE}" < "${lINIT_OUT}" || true
    if file "${MNT_POINT}""${lINIT_FILE}" | grep -q "text executable\|ASCII text"; then
      print_ln
      print_output "[*] Firmware Init file details: ${ORANGE}${lINIT_FILE}${NC}"
      tee -a "${LOG_FILE}" < "${MNT_POINT}""${lINIT_FILE}"
    fi

    print_ln
    print_output "[*] EMBA Target filesytem:"
    find "${MNT_POINT}" -xdev -maxdepth 1 -ls | tee -a "${LOG_FILE}" || true

    print_ln
    print_output "[*] EMBA emulation helpers directory:"
    find "${MNT_POINT}"/firmadyne -xdev -ls | tee -a "${LOG_FILE}" || true
    print_ln

    ### set default network values for network identification mode
    local lIP_ADDRESS="192.168.0.1"
    local lNETWORK_MODE="None"
    local lNETWORK_DEVICE="br0"
    local lETH_INT="eth0"
    set_network_config "${lIP_ADDRESS}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${lETH_INT}"

    print_output "[*] Unmounting QEMU Image" "no_log"
    umount_qemu_image "${lDEVICE}"
    delete_device_entry "${IMAGE_NAME}" "${lDEVICE}" "${MNT_POINT}"

    check_qemu_instance_l10

    identify_networking_emulation "${IMAGE_NAME}" "${lARCH_END}" "${lINIT_FILE}"
    get_networking_details_emulation "${IMAGE_NAME}"

    print_output "[*] Firmware ${ORANGE}${IMAGE_NAME}${NC} finished for identification of the network configuration"

    local lF_STARTUP=0
    if [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
      check_qemu_kernel_output "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${ARCHIVE_PATH:-NA}" "${IMAGE_NAME:-NA}" "${lNETWORK_MODE:-NA}" "${lETH_INT:-NA}" "${lVLAN_ID:-NA}" "${lINIT_FILE:-NA}" "${lNETWORK_DEVICE:-NA}" "${#PANICS[@]}" "${SYS_ONLINE:-0}" "${TCP:-NA}"
      cat "${LOG_PATH_MODULE}"/qemu.initial.serial.log >> "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}".log
      write_link "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}".log

      ###############################################################################################
      # if we were running into issues with the network identification we poke with rdinit vs init:
      # lets check if we have found a startup procedure (preInit script) from EMBA - if not we try it with the other init
      lF_STARTUP=$(grep -a -c "EMBA preInit script starting" "${LOG_PATH_MODULE}"/qemu.initial.serial.log || true)
      lF_STARTUP=$(( "${lF_STARTUP}" + "$(grep -a -c "Network configuration - ACTION" "${LOG_PATH_MODULE}"/qemu.initial.serial.log || true)" ))
    else
      print_output "[-] No Qemu log file generated ... some weird error occured"
      return
    fi
    # print_output "[*] Found $ORANGE$lF_STARTUP$NC EMBA startup entries."
    print_ln

    # the following condition is for switching and testing a different init= -> rdinit=
    if [[ "${#PANICS[@]}" -gt 0 ]] || [[ "${lF_STARTUP}" -eq 0 ]] || [[ "${DETECTED_IP}" -eq 0 ]]; then
      # if we are running into a kernel panic during the network detection we are going to check if the
      # panic is caused from an init failure. If so, we are trying the other init kernel command (init vs rdinit)
      print_output "[*] Info: lF_STARTUP: ${lF_STARTUP} / lNETWORK_MODE: ${lNETWORK_MODE} / DETECTED_IP: ${DETECTED_IP} / PANICS: ${#PANICS[@]}"
      if [[ "${PANICS[*]}" == *"Kernel panic - not syncing: Attempted to kill init!"* || "${PANICS[*]}" == *"Kernel panic - not syncing: No working init found."* ]]; then
        mv "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_base_init.log
        print_output "[!] Identified Kernel panic ... switching init from ${KINIT}"
        switch_inits "${KINIT}"

        # re-identify the network via other init configuration
        identify_networking_emulation "${IMAGE_NAME}" "${lARCH_END}" "${lINIT_FILE}"
        get_networking_details_emulation "${IMAGE_NAME}"

        print_output "[*] Firmware ${ORANGE}${IMAGE_NAME}${NC} finished for identification of the network configuration"
        if [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
          check_qemu_kernel_output "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${ARCHIVE_PATH:-NA}" "${IMAGE_NAME:-NA}" "${lNETWORK_MODE:-NA}" "${lETH_INT:-NA}" "${lVLAN_ID:-NA}" "${lINIT_FILE:-NA}" "${lNETWORK_DEVICE:-NA}" "${#PANICS[@]}" "${SYS_ONLINE:-0}" "${TCP:-NA}"
          mv "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_new_init.log
          write_link "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_new_init.log
        else
          print_output "[-] No Qemu log file generated ... some weird error occured"
        fi
        print_ln

      elif [[ "${lF_STARTUP}" -eq 0 && "${lNETWORK_MODE}" == "None" ]] || \
        [[ "${lF_STARTUP}" -eq 0 && "${lNETWORK_MODE}" == "default" ]] || [[ "${DETECTED_IP}" -eq 0 ]]; then
        print_output "[!] Possible init issue ... switching init from ${KINIT}"
        local lPORTS_1st=0
        local lCOUNTING_1st=0
        mv "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_base_init.log
        lCOUNTING_1st=$(wc -l < "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_base_init.log)
        lPORTS_1st=$(grep -a "inet_bind" "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_base_init.log | sort -u | wc -l | awk '{print $1}' || true)
        switch_inits "${KINIT}"

        # re-identify the network via other init configuration
        identify_networking_emulation "${IMAGE_NAME}" "${lARCH_END}" "${lINIT_FILE}"
        get_networking_details_emulation "${IMAGE_NAME}"

        local lPORTS_2nd=0
        local lCOUNTING_2nd=0
        local lF_STARTUP=0
        if [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
          check_qemu_kernel_output "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${ARCHIVE_PATH:-NA}" "${IMAGE_NAME:-NA}" "${lNETWORK_MODE:-NA}" "${lETH_INT:-NA}" "${lVLAN_ID:-NA}" "${lINIT_FILE:-NA}" "${lNETWORK_DEVICE:-NA}" "${#PANICS[@]}" "${SYS_ONLINE:-0}" "${TCP:-NA}"
          print_output "[*] qemu.initial.serial.log detected and checking for STARTUP and Service data"
          # now we need to check if something is better now or we should switch back to the original init
          lF_STARTUP=$(grep -a -c "EMBA preInit script starting" "${LOG_PATH_MODULE}"/qemu.initial.serial.log || true)
          lF_STARTUP=$(( "${lF_STARTUP}" + "$(grep -a -c "Network configuration - ACTION" "${LOG_PATH_MODULE}"/qemu.initial.serial.log || true)" ))
          lCOUNTING_2nd=$(wc -l < "${LOG_PATH_MODULE}"/qemu.initial.serial.log)
          lPORTS_2nd=$(grep -a "inet_bind" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | sort -u | wc -l | awk '{print $1}' || true)
          # IPS_INT_VLAN is always at least 1 for the default configuration
        else
          print_output "[-] NO qemu.initial.serial.log detected and NO checking for STARTUP and Service data possible"
        fi

        print_output "[*] lPORTS_1st: ${lPORTS_1st} / lPORTS_2nd: ${lPORTS_2nd} / lF_STARTUP: ${lF_STARTUP}"
        if [[ "${#PANICS[@]}" -gt 0 ]] || [[ "${lF_STARTUP}" -eq 0 && "${#IPS_INT_VLAN[@]}" -lt 2 ]] || \
          [[ "${DETECTED_IP}" -eq 0 ]]; then
          if [[ "${#PANICS[@]}" -gt 0 ]]; then
            # on a Kernel panic we always switch back
            print_output "[!] Identified Kernel panic ... switching init back from ${KINIT}"
            switch_inits "${KINIT}"
          elif [[ "${lPORTS_1st}" -gt "${lPORTS_2nd}" ]]; then
            print_output "[!] Network services issue ... switching init back from ${KINIT}"
            switch_inits "${KINIT}"
          # we only switch back if the first check has more output generated
          elif [[ "${lCOUNTING_1st}" -gt "${lCOUNTING_2nd}" ]] && [[ "${lPORTS_1st}" -ge "${lPORTS_2nd}" ]]; then
            print_output "[!] Network services issue and log file size ... switching init back from ${KINIT}"
            switch_inits "${KINIT}"
          fi
        fi

        print_output "[*] Firmware ${ORANGE}${IMAGE_NAME}${NC} finished for identification of the network configuration"
        if [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
          mv "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_new_init.log
          write_link "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_new_init.log
        else
          print_output "[-] No Qemu log file generated ... some weird error occured"
        fi
        print_ln

        export PANICS=()
      fi
    fi
    ###############################################################################################

    if [[ "${#IPS_INT_VLAN[@]}" -gt 0 && "${#PANICS[@]}" -eq 0 ]]; then
      nvram_check "${IMAGE_NAME}"
      print_bar ""
      print_output "[*] Identified the following network configuration options:"
      local lIP_CFG=""
      local lINTERFACE_CFG=""
      local lNETWORK_INTERFACE_CFG=""
      local lVLAN_CFG=""
      local lCFG_CFG=""
      local lIPS_INT_VLAN_CFG=""
      local lNETWORK_MODE=""
      local lNETWORK_DEVICE=""
      local lNW_ENTRY_PRIO=0
      local lIPS_INT_VLAN_TMP=()
      local lMAX_NET_CFG=15
      print_output "[*] Unsorted configuration"
      for lIPS_INT_VLAN_CFG in "${IPS_INT_VLAN[@]}"; do
        lNW_ENTRY_PRIO="${lIPS_INT_VLAN_CFG/\;*}"
        lIP_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f2)
        lINTERFACE_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f3)
        lNETWORK_INTERFACE_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f4)
        lVLAN_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f5)
        lCFG_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f6)
        if [[ "${lIPS_INT_VLAN_TMP[*]}" == *"${lIP_CFG};${lINTERFACE_CFG};${lNETWORK_INTERFACE_CFG};${lVLAN_CFG};${lCFG_CFG}"* ]]; then
          print_output "$(indent "Duplicate: ${lIP_CFG} - ${lINTERFACE_CFG} - ${lNETWORK_INTERFACE_CFG} - ${lVLAN_CFG} - ${lCFG_CFG} - ${lNW_ENTRY_PRIO}")"
        fi
        print_output "$(indent "$(orange "${lIP_CFG} - ${lINTERFACE_CFG} - ${lNETWORK_INTERFACE_CFG} - ${lVLAN_CFG} - ${lCFG_CFG} - ${lNW_ENTRY_PRIO}")")"
      done

      # sort it
      mapfile -t IPS_INT_VLAN < <(printf "%s\n" "${IPS_INT_VLAN[@]}" | sort -t ';' -k 1,1r -k 5,5n)
      # make it unique
      mapfile -t IPS_INT_VLAN < <(printf "%s\n" "${IPS_INT_VLAN[@]}" | uniq)

      print_output "[*] Sorted and unique configuration"
      for lIPS_INT_VLAN_CFG in "${IPS_INT_VLAN[@]}"; do
        lNW_ENTRY_PRIO="${lIPS_INT_VLAN_CFG/\;*}"
        lIP_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f2)
        lINTERFACE_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f3)
        lNETWORK_INTERFACE_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f4)
        lVLAN_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f5)
        lCFG_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f6)
        if [[ "${lIPS_INT_VLAN_TMP[*]}" == *"${lIP_CFG};${lINTERFACE_CFG};${lNETWORK_INTERFACE_CFG};${lVLAN_CFG};${lCFG_CFG}"* ]]; then
          print_output "$(indent "Duplicate: ${lIP_CFG} - ${lINTERFACE_CFG} - ${lNETWORK_INTERFACE_CFG} - ${lVLAN_CFG} - ${lCFG_CFG} - ${lNW_ENTRY_PRIO}")"
        fi
        print_output "$(indent "$(orange "${lIP_CFG} - ${lINTERFACE_CFG} - ${lNETWORK_INTERFACE_CFG} - ${lVLAN_CFG} - ${lCFG_CFG} - ${lNW_ENTRY_PRIO}")")"
      done


      print_output "[*] Final configuration"
      for lIPS_INT_VLAN_CFG in "${IPS_INT_VLAN[@]}"; do
        lNW_ENTRY_PRIO="${lIPS_INT_VLAN_CFG/\;*}"
        lIP_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f2)
        lINTERFACE_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f3)
        lNETWORK_INTERFACE_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f4)
        lVLAN_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f5)
        lCFG_CFG=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f6)
        if [[ "${lIPS_INT_VLAN_TMP[*]}" == *"${lIP_CFG};${lINTERFACE_CFG};${lNETWORK_INTERFACE_CFG};${lVLAN_CFG};${lCFG_CFG}"* ]]; then
          continue
        fi
        lIPS_INT_VLAN_TMP+=( "${lNW_ENTRY_PRIO}"\;"${lIP_CFG}"\;"${lINTERFACE_CFG}"\;"${lNETWORK_INTERFACE_CFG}"\;"${lVLAN_CFG}"\;"${lCFG_CFG}" )
        print_output "$(indent "$(orange "${lIP_CFG}"" - ""${lINTERFACE_CFG}"" - ""${lNETWORK_INTERFACE_CFG}"" - ""${lVLAN_CFG}"" - ""${lCFG_CFG}"" - ""${lNW_ENTRY_PRIO}")")"
        if [[ "${#lIPS_INT_VLAN_TMP[@]}" -ge "${lMAX_NET_CFG}" ]]; then
          print_output "[*] INFO: More then ${lMAX_NET_CFG} detected -> adding a default backup config and testing only ${lMAX_NET_CFG} most relevant configuration options"
          lIPS_INT_VLAN_TMP+=( "1;192.168.0.1;br0;eth0;NONE;default" )
          print_output "$(indent "$(orange "192.168.0.1 - br0 - eth0 - NONE - default - 1")")"
          break
        fi
      done
      print_ln

      IPS_INT_VLAN=("${lIPS_INT_VLAN_TMP[@]}")

      for lIPS_INT_VLAN_CFG in "${IPS_INT_VLAN[@]}"; do
        emulation_with_config "${lIPS_INT_VLAN_CFG}"

        if [[ "${TCP}" != "ok" ]]; then
          print_output "[*] We are in the emergency init switch mode now"
          # just in case we have no running TCP service detected we try the other init mechanism (rdinit vs init)
          # this is only done if we have already switched inits and our first detection run has also network services detected
          switch_inits "${KINIT}"
          emulation_with_config "${lIPS_INT_VLAN_CFG}"
          # we do not care about the results and switch back to the original init
          # later on we are running the same process again
          switch_inits "${KINIT}"
        fi
        if [[ $(grep -h "\/tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null | awk '{print $1}' | sort -u | wc -l || true) -ge "${MIN_TCP_SERV}" ]]; then
          break 2
        fi
      done
    else
      print_output "[!] No further emulation steps are performed"
    fi

    cleanup_emulator "${IMAGE_NAME}"

    print_output "[*] Processing init file ${ORANGE}${lINIT_FILE}${NC} (${lINDEX}/${#lINIT_FILES_ARR[@]}) finished"
    print_bar ""
    ((lINDEX+=1))
  done

  delete_device_entry "${IMAGE_NAME}" "${lDEVICE:-NA}" "${MNT_POINT}"
}

# Function to check the kernel log entries.
# We have seen multiple times that the kernel just stops responding and we do not get logs
# This prints a warning message and also a message to the error log for further processing.
# check_qemu_kernel_output "${LOG_PATH_MODULE}"/qemu.final.serial.log "${ARCHIVE_PATH:-NA}" "${IMAGE_NAME:-NA}" "${lNETWORK_MODE:-NA}" "${lETH_INT:-NA}" "${lVLAN_ID:-NA}" "${lINIT_FILE:-NA}" "${lNETWORK_DEVICE:-NA}" "${#PANICS[@]}" "${SYS_ONLINE:-0}" "${TCP:-NA}"
check_qemu_kernel_output() {
  local lQEMU_LOG_TO_CHECK="${1:-}"
  local lARCHIVE_PATH="${2:-}"
  local lIMAGE_NAME="${3:-}"
  local lNETWORK_MODE="${4:-}"
  local lETH_INT="${5:-}"
  local lVLAN_ID="${6:-}"
  local lINIT_FILE="${7:-}"
  local lNETWORK_DEVICE="${8:-}"
  local lPANIC_CNT="${9:-0}"
  local lSYS_ONLINE="${10:-0}"
  local lTCP="${11:-NA}"

  # if we have a kernel panic we do not need to further analyze the logs
  [[ "${lPANIC_CNT}" -gt 0 ]] && return
  [[ "${lSYS_ONLINE}" -gt 0 ]] && return
  [[ "${lTCP}" == "TCP ok" ]] && return

  local lKERNEL_MIN_RUNTIME=300
  local lQEMU_RUN_TIME_KERNEL=0

  lQEMU_RUN_TIME_KERNEL=$(grep -a -o -E "^\[[[:space:]]+[0-9]+\.[0-9]+.*\] EMBA" "${lQEMU_LOG_TO_CHECK}" | tail -1 || true)
  lQEMU_RUN_TIME_KERNEL=${lQEMU_RUN_TIME_KERNEL//\.*}
  lQEMU_RUN_TIME_KERNEL=${lQEMU_RUN_TIME_KERNEL//*\ }

  if [[ "${lQEMU_RUN_TIME_KERNEL}" -lt "${lKERNEL_MIN_RUNTIME}" ]]; then
    print_output "[-] WARNING: QEMU log (${lQEMU_LOG_TO_CHECK}) has less then ${lKERNEL_MIN_RUNTIME} seconds of kernel runtime entries. Probably something is going wrong with your emulation environment:"
    print_output "$(indent "$(orange "$(grep -a -E "^\[[[:space:]]+[0-9]+\.[0-9]+.*\] EMBA" "${lQEMU_LOG_TO_CHECK}" | tail -10 || true)")")"
    print_output "$(indent "lARCHIVE_PATH: ${lARCHIVE_PATH} - lIMAGE_NAME: ${lIMAGE_NAME} - lNETWORK_MODE: ${lNETWORK_MODE}")"
    print_output "$(indent "lETH_INT: ${lETH_INT} - lVLAN_ID: ${lVLAN_ID} - lINIT_FILE: ${lINIT_FILE} - lNETWORK_DEVICE: ${lNETWORK_DEVICE}")"
  fi
}

emulation_with_config() {
  lIPS_INT_VLAN_CFG="${1:-}"
  local lRESTARTED_EMULATION="${2:-0}"

  SYS_ONLINE=0

  print_ln
  print_output "[*] Testing system emulation with configuration: ${ORANGE}${lIPS_INT_VLAN_CFG//\;/-}${NC}."

  cleanup_tap
  check_qemu_instance_l10

  local lENTRY_PRIO=""
  local lVLAN_ID=""
  lENTRY_PRIO="${lIPS_INT_VLAN_CFG/\;*}"
  IP_ADDRESS_=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f2)
  lNETWORK_DEVICE=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f3)
  lETH_INT=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f4)
  lVLAN_ID=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f5)
  lNETWORK_MODE=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f6)
  export NMAP_LOG="nmap_emba_${lIPS_INT_VLAN_CFG//\;/-}.txt"

  setup_network_emulation "${lIPS_INT_VLAN_CFG}"
  run_emulated_system "${IP_ADDRESS_}" "${IMAGE_NAME}" "${lINIT_FILE}" "${lARCH_END}"

  check_online_stat "${lIPS_INT_VLAN_CFG}" "${IMAGE_NAME}" &
  local lCHECK_ONLINE_STAT_PID="$!"

  print_keepalive "${LOG_PATH_MODULE}/qemu.final.serial.log" "${IMAGE_NAME}" &
  local lALIVE_PID="$!"
  disown "${lALIVE_PID}" 2> /dev/null || true

  # we kill this process from "check_online_stat"
  tail -F "${LOG_PATH_MODULE}/qemu.final.serial.log" 2>/dev/null | grep -a -v "klogd" || true
  if [[ -e /proc/"${lCHECK_ONLINE_STAT_PID}" ]]; then
    kill -9 "${lCHECK_ONLINE_STAT_PID}" || true
  fi

  kill "${lALIVE_PID}" || true

  # set default state
  ICMP="not ok"
  TCP_0="not ok"
  TCP="not ok"
  if [[ -f "${TMP_DIR}"/online_stats.tmp ]]; then
    if grep -q -E "Host with .* is reachable via ICMP." "${TMP_DIR}"/online_stats.tmp; then
      ICMP="ok"
      SYS_ONLINE=1
      BOOTED="yes"
    fi
    if grep -q -E "Host with .* is reachable on TCP port 0 via hping." "${TMP_DIR}"/online_stats.tmp; then
      TCP_0="ok"
      SYS_ONLINE=1
      BOOTED="yes"
    fi
    if grep -q "udp.*open\ \|tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null; then
      TCP="ok"
      SYS_ONLINE=1
      BOOTED="yes"
    fi

    # remove tmp files for next round
    rm "${TMP_DIR}"/online_stats.tmp || true
  fi

  # if our ip address has changed during analysis we restore this ip address now
  if [[ -f "${TMP_DIR}/emulation_changed_ip_address.tmp" ]]; then
    IP_ADDRESS_="$(cat "${TMP_DIR}/emulation_changed_ip_address.tmp")"
    rm "${TMP_DIR}/emulation_changed_ip_address.tmp" || true
  fi

  write_results "${ARCHIVE_PATH}" "${R_PATH}" "${RESULT_SOURCE:-EMBA}" "${lNETWORK_MODE}" "${lETH_INT}" "${lVLAN_ID}" "${lINIT_FILE}" "${lNETWORK_DEVICE}"
  print_output "[*] Call to stop emulation process - Source ${FUNCNAME[0]}" "no_log"
  stopping_emulation_process "${IMAGE_NAME}"
  cleanup_emulator "${IMAGE_NAME}"

  if [[ -f "${LOG_PATH_MODULE}"/qemu.final.serial.log ]]; then
    check_qemu_kernel_output "${LOG_PATH_MODULE}"/qemu.final.serial.log "${ARCHIVE_PATH:-NA}" "${IMAGE_NAME:-NA}" "${lNETWORK_MODE:-NA}" "${lETH_INT:-NA}" "${lVLAN_ID:-NA}" "${lINIT_FILE:-NA}" "${lNETWORK_DEVICE:-NA}" 0 "${SYS_ONLINE:-0}" "${TCP:-NA}"
    mv "${LOG_PATH_MODULE}"/qemu.final.serial.log "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log
  fi

  if [[ "${SYS_ONLINE}" -eq 1 ]]; then
    print_ln
    print_output "[+] System emulation was successful."
    if [[ -f "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log ]]; then
      print_output "[+] System should be available via IP ${ORANGE}${IP_ADDRESS_}${GREEN}." "" "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log
    else
      print_output "[+] System should be available via IP ${ORANGE}${IP_ADDRESS_}${GREEN}."
    fi
    print_ln

    if [[ "${TCP}" == "ok" ]]; then
      if [[ $(grep -h "\/tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null | awk '{print $1}' | sort -u | wc -l || true) -ge "${MIN_TCP_SERV}" ]]; then
        print_output "[+] More than ${MIN_TCP_SERV} TCP based Network services are available - no further emulation runs are needed" "" "${ARCHIVE_PATH}/${NMAP_LOG}"
      else
        print_output "[+] Less than ${MIN_TCP_SERV} TCP based Network services are available - further emulation runs are needed." "" "${ARCHIVE_PATH}/${NMAP_LOG}"
      fi
      print_ln
    fi

    create_emulation_archive "${KERNEL}" "${IMAGE}" "${ARCHIVE_PATH}" "${lIPS_INT_VLAN_CFG//\;/-}"
  else
    if [[ "${L10_DEBUG_MODE}" -eq 1 ]]; then
      print_output "[-] ${ORANGE}Debug mode:${NC} No working emulation - ${ORANGE}creating${NC} emulation archive ${ORANGE}${ARCHIVE_PATH}${NC}."
      create_emulation_archive "${KERNEL}" "${IMAGE}" "${ARCHIVE_PATH}" "${lIPS_INT_VLAN_CFG//\;/-}"
    else
      print_output "[-] No working emulation - removing emulation archive ${ORANGE}${ARCHIVE_PATH}${NC}."
      if [[ -f "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log ]]; then
        write_link "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log
      fi
      # print_output "[-] Emulation archive: $ARCHIVE_PATH."
      # create_emulation_archive "$ARCHIVE_PATH"
      rm -r "${ARCHIVE_PATH}" || true
    fi
  fi

  if [[ -f "${LOG_PATH_MODULE}"/nvram/nvram_files_final_ ]]; then
    mv "${LOG_PATH_MODULE}"/nvram/nvram_files_final_ "${LOG_PATH_MODULE}"/nvram/nvram_files_"${IMAGE_NAME}".bak
  fi
  if ! [[ -f "${LOG_PATH_MODULE}/qemu.final.serial_${IMAGE_NAME}-${lIPS_INT_VLAN_CFG//\;/-}-${lINIT_FNAME}.log" ]]; then
    print_output "[!] Warning: No Qemu log file generated for ${ORANGE}${IMAGE_NAME}-${lIPS_INT_VLAN_CFG//\;/-}-${lINIT_FNAME}${NC}"
  fi

  # if we have created our qemu log file and TCP is not ok we check for additional IP addresses and
  # rerun the emulation if a different IP address was found
  if [[ -f "${LOG_PATH_MODULE}/qemu.final.serial_${IMAGE_NAME}-${lIPS_INT_VLAN_CFG//\;/-}-${lINIT_FNAME}.log" ]]; then
    local lTEMP_RUN_IPs_ARR=()
    local lTMP_IP=""
    # lets check if the system has configured some different IP address then expected
    # we use the output of ipconfig from the qemu logs for this check
    # first: generate an array with the possible ip addresses (remove already local addresses like 127.0.0.)
    mapfile -t lTEMP_RUN_IPs_ARR < <(grep -a -o -E "inet addr:[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" \
      "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log | \
      grep -v "127.0.0." | grep -v "${IP_ADDRESS_}" | cut -d ':' -f2 | sort -u || true)
    for lTMP_IP in "${lTEMP_RUN_IPs_ARR[@]}"; do
      # check every detected ip address against our real system ip address
      # if we have some other ip address detected we move on:
      if [[ "${lTMP_IP}" != "${IP_ADDRESS_}" ]]; then
        # check every ip address for our used interfaces (ethX/brX)
        # if we find a typical used interface with the changed IP address we will check it again
        if (grep -a -B1 "inet addr:${lTMP_IP}" "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log | grep -q "^eth\|^br"); then
          print_output "[!] WARNING: Detected possible IP address change during emulation process from ${ORANGE}${IP_ADDRESS_}${MAGENTA} to address ${ORANGE}${lTMP_IP}${NC}"
          # we restart the emulation with the identified IP address for a maximum of one time
          if [[ $(grep -a -h "\/tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null | awk '{print $1}' | sort -u | wc -l || true) -lt "${MIN_TCP_SERV}" ]]; then
            if [[ "${lRESTARTED_EMULATION:-1}" -eq 0 ]]; then
              print_output "[!] Emulation re-run with IP ${ORANGE}${lTMP_IP}${MAGENTA} needed and executed"
              lIPS_INT_VLAN_CFG="${lENTRY_PRIO}"\;"${lTMP_IP}"\;"${lNETWORK_DEVICE}"\;"${lETH_INT}"\;"${lVLAN_ID}"\;"${lNETWORK_MODE}"
              IPS_INT_VLAN+=( "${lIPS_INT_VLAN_CFG}" )
              emulation_with_config "${lIPS_INT_VLAN_CFG}" 1
            else
              print_output "[!] Emulation re-run with IP ${ORANGE}${lTMP_IP}${MAGENTA} needed but ${ORANGE}not executed${NC}"
            fi
          else
            print_output "[!] Emulation re-run with IP ${ORANGE}${lTMP_IP}${MAGENTA} could be performed but ${ORANGE}network services already available${NC}"
          fi
        fi
      fi
    done
  fi
}

switch_inits() {
  # KINIT is global but for readability:
  KINIT="${1:-}"
  if [[ "${KINIT:0:2}" == "rd" ]]; then
    print_output "[*] Note: Switching rdinit to init"
    # strip rd from rdinit
    KINIT="${KINIT:2}"
  else
    print_output "[*] Note: Switching init to rdinit"
    # make rdinit from init
    KINIT="rd""${KINIT}"
  fi
}

umount_qemu_image() {
  local lDEVICE=${1:-}
  sync
  disable_strict_mode "${STRICT_MODE}" 0
  if ! umount "${lDEVICE}"; then
    print_output "[*] Warning: Normal umount was not successful. Trying to enforce unmounting of ${ORANGE}${lDEVICE}${NC}."
    umount -l "${lDEVICE}" || true
    umount -f "${lDEVICE}" || true
    sleep 5
  fi
  enable_strict_mode "${STRICT_MODE}" 0
}

handle_fs_mounts() {
  # WARNING: This code needs to be adjusted and tested
  # Currently it was created for the TP-Link camera set (at the end it was not working as expected!)
  # Idea: we identify areas that are mounted during bootup process:
  # mount -t jffs2 /dev/mtdblock5 /usr/local
  # mount -t jffs2 /dev/mtdblock6 /usr/local/config/ipcamera
  # Next we are trying to find them in the extracted data. If we identify something
  # with jffs2 in the name we copy it to the original root filesystem
  # This is very dirty but if it works ... it works ;)
  local lINIT_FILE=${1:-}
  shift 1
  local lFS_MOUNTS_ARR=("$@")
  local lFS_MOUNT=""

  for lFS_MOUNT in "${lFS_MOUNTS_ARR[@]}"; do
    if [[ -z "${lFS_MOUNT}" ]]; then
      continue
    fi
    local lMOUNT_PT=""
    local lMOUNT_FS=""
    local lFS_FIND=""

    local lINIT_FILE_PATH="${MNT_POINT}${lINIT_FILE}"
    print_output "[*] Found filesystem mount and analysing it: ${ORANGE}${lFS_MOUNT}${NC}"
    # as the original mount will not work, we need to remove it from the startup file:
    if [[ -f "${lINIT_FILE_PATH}" ]]; then
      sed -i 's|'"${lFS_MOUNT}"'|\#'"${lFS_MOUNT}"'|g' "${lINIT_FILE_PATH}"
    else
      print_error "[-] Init file ${lINIT_FILE_PATH} NOT available ... returning but this could result in further issues"
      return
    fi

    lMOUNT_PT=$(echo "${lFS_MOUNT}" | awk '{print $5}')
    lMOUNT_FS=$(echo "${lFS_MOUNT}" | grep " \-t " | sed 's/.*-t //g' | awk '{print $1}')
    if [[ "${lMOUNT_FS}" != *"jffs"* ]] && [[ "${lMOUNT_FS}" != *"cramfs"* ]]; then
      print_output "[-] Warning: ${ORANGE}${lMOUNT_FS}${NC} filesystem currently not supported"
      print_output "[-] Warning: If further results are wrong please open a ticket"
    fi
    if [[ "${lMOUNT_PT}" != *"/"* ]]; then
      lMOUNT_PT=$(echo "${lFS_MOUNT}" | awk '{print $NF}')
      if [[ "${lMOUNT_PT}" != *"/"* ]]; then
        print_output "[-] Warning: Mount point ${ORANGE}${lMOUNT_PT}${NC} currently not supported"
        print_output "[-] Warning: If further results are wrong please open a ticket"
      fi
    fi
    # we test for paths including the lMOUNT_FS part like "jffs2" in the path
    lFS_FIND=$(find "${LOG_DIR}"/firmware -path "*/*${lMOUNT_FS}*_extract" | head -1 || true)

    print_output "[*] Identified mount point: ${ORANGE}${lMOUNT_PT}${NC}"
    print_output "[*] Identified mounted fs: ${ORANGE}${lMOUNT_FS}${NC}"

    if [[ "${lFS_FIND}" =~ ${lMOUNT_FS} ]]; then
      print_output "[*] Possible FS target found: ${ORANGE}${lFS_FIND}${NC}"
    else
      print_output "[-] No FS target found"
    fi
    print_output "[*] Root system mount point: ${ORANGE}${MNT_POINT}${NC}"

    if [[ "${R_PATH}" == *"${lFS_FIND}"* ]]; then
      print_output "[-] Found our own root directory ... skipping"
      print_output "[*] R_PATH: ${R_PATH}"
      print_output "[*] FS_FIND: ${lFS_FIND}"
      continue
    fi

    find "${lFS_FIND}" -xdev -ls || true

    print_output "[*] Identify system areas in the to-mount area:"
    local lLINUX_PATHS_ARR=( "bin" "boot" "dev" "etc" "home" "lib" "mnt" "opt" "proc" "root" "sbin" "srv" "tmp" "usr" "var" )
    local lL_PATH=""
    local lN_PATH=""
    local lX_PATH=""
    local lNEWPATH_ARR=()
    local lNEWPATH_tmp_ARR=()
    local lNEWPATH_test_ARR=()

    for lL_PATH in "${lLINUX_PATHS_ARR[@]}"; do
      mapfile -t lNEWPATH_tmp_ARR < <(find "${lFS_FIND}" -path "*/${lL_PATH}" -type d | sed "s/\/${lL_PATH}\/*/\//g")
      mapfile -t lNEWPATH_test_ARR < <(find "${lFS_FIND}" -path "*/${lL_PATH}" -type d)
      lNEWPATH_ARR+=( "${lNEWPATH_tmp_ARR[@]}" )
      if [[ -d "${MNT_POINT}"/"${lL_PATH}" ]]; then
        for lX_PATH in "${lNEWPATH_test_ARR[@]}"; do
          print_output "[*] Copy ${lX_PATH} to ${MNT_POINT}/${lL_PATH}/"
          cp -pr --update=none "${lX_PATH}"/* "${MNT_POINT}"/"${lL_PATH}"/
        done
      fi
    done

    mapfile -t lNEWPATH_ARR < <(printf "%s\n" "${lNEWPATH_ARR[@]}" | sort -u)

    for lN_PATH in "${lNEWPATH_ARR[@]}"; do
      if [[ -z "${lN_PATH}" ]]; then
        continue
      fi
      print_output "[*] PATH found: ${lN_PATH}"
      find "${lN_PATH}" -xdev -ls || true

      if ! [[ -d "${MNT_POINT}""${lMOUNT_PT}" ]]; then
        print_output "[*] Creating target directory ${MNT_POINT}${lMOUNT_PT}"
        mkdir -p "${MNT_POINT}""${lMOUNT_PT}"
      fi
      print_output "[*] Let's copy the identified area to the root filesystem - ${ORANGE}${lN_PATH}${NC} to ${ORANGE}${MNT_POINT}${lMOUNT_PT}${NC}"
      cp -pr --update=none "${lN_PATH}"* "${MNT_POINT}""${lMOUNT_PT}"
      find "${MNT_POINT}""${lMOUNT_PT}" -xdev -ls || true
    done

    print_output "[*] Final copy of ${ORANGE}${lFS_FIND}${NC} to ${ORANGE}${MNT_POINT}${lMOUNT_PT}${NC} ..."
    cp -pr --update=none "${lFS_FIND}"/* "${MNT_POINT}""${lMOUNT_PT}" || true
    # find "$MNT_POINT""$lMOUNT_PT" -xdev -ls || true
    ls -lh "${MNT_POINT}""${lMOUNT_PT}" || true
  done

  # now we need to startup the inferFile/inferService script again
  cp "$(command -v bash-static)" "${MNT_POINT}" || true
  cp "$(command -v busybox)" "${MNT_POINT}" || true
  cp "${MODULE_SUB_PATH}/inferService.sh" "${MNT_POINT}" || true
  print_output "[*] inferService.sh (chroot)"
  EMBA_BOOT=${EMBA_BOOT} EMBA_ETC=${EMBA_ETC} timeout --preserve-status --signal SIGINT 120 chroot "${MNT_POINT}" /bash-static /inferService.sh | tee -a "${LOG_FILE}"
  rm "${MNT_POINT}"/inferService.sh || true
  rm "${MNT_POINT}"/bash-static|| true
  rm "${MNT_POINT}"/busybox || true

  if [[ -f "${MNT_POINT}"/firmadyne/service ]]; then
    # tp-link camset fix (e.g. NC200_2.1.8_Build_171109_Rel.28679.bin):
    if grep -q "lighttpd" "${MNT_POINT}"/firmadyne/service; then
      if ! [[ -d "${MNT_POINT}"/var/run/lighttpd ]]; then
        print_output "[*] Creating pid directory for lighttpd service"
        mkdir -p "${MNT_POINT}"/var/run/lighttpd || true
      fi
    fi
  fi
}

cleanup_emulator() {
  local lIMAGE_NAME="${1:-}"
  if [[ -v ARCHIVE_PATH ]] && [[ -f "${ARCHIVE_PATH}"/run.sh ]]; then
    reset_network_emulation "${lIMAGE_NAME}" 1
  else
    reset_network_emulation "${lIMAGE_NAME}" 2
  fi

  # ugly cleanup:
  rm -rf /tmp/qemu."${lIMAGE_NAME}" 2>/dev/null || true
  rm -rf /tmp/qemu."${lIMAGE_NAME}".S1 2>/dev/null || true
  if [[ -f /tmp/do_not_create_run.sh ]]; then
    rm /tmp/do_not_create_run.sh || true
  fi

  # losetup
  losetup -D
}

delete_device_entry() {
  local lIMAGE_NAME="${1:-}"
  local lDEVICE="${2:-}"
  local lMNT_POINT="${3:-}"

  print_output "[*] Deleting device mapper for ${lIMAGE_NAME} / ${lDEVICE}" "no_log"

  kpartx -v -d "${LOG_PATH_MODULE}/${lIMAGE_NAME}"
  losetup -d "${lDEVICE}" &>/dev/null || true
  # just in case we check the output and remove our device:
  if losetup | grep -q "$(basename "${lIMAGE_NAME}")"; then
    losetup -d "$(losetup | grep "$(basename "${lIMAGE_NAME}")" | awk '{print $1}' || true)"
  fi
  dmsetup remove "$(basename "${lDEVICE}")" &>/dev/null || true
  rm -rf "${lMNT_POINT:?}/"* || true
  sleep 1
}

identify_networking_emulation() {
  # based on the original firmadyne and FirmAE script:
  # https://github.com/firmadyne/firmadyne/blob/master/scripts/inferNetwork.sh

  local lIMAGE_NAME="${1:-}"
  export IMAGE=""
  IMAGE=$(abs_path "${LOG_PATH_MODULE}/${lIMAGE_NAME}")

  local lARCH_END="${2:-}"
  local lINIT_FILE="${3:-}"

  sub_module_title "Network identification ${lINIT_FILE} - ${KINIT} - ${lARCH_END} - ${lIMAGE_NAME}"

  print_output "[*] Test basic emulation and identify network settings.\\n"
  print_output "[*] Running firmware ${ORANGE}${lIMAGE_NAME}${NC}: Terminating after 660 secs..."

  local lCPU=""
  local lKERNEL=""
  local lQEMU_BIN=""
  local lQEMU_MACHINE=""
  local lQEMU_DISK=""
  local lQEMU_PARAMS=""
  local lQEMU_NETWORK=""
  local lQEMU_ROOTFS=""
  local lCONSOLE="ttyS0"

  lKERNEL="vmlinux"
  lQEMU_ROOTFS="/dev/sda1"
  lQEMU_DISK="-drive if=ide,format=raw,file=${IMAGE}"
  # default network configuration with e1000 interface:
  lQEMU_NETWORK="-netdev socket,id=net0,listen=:2000 -device e1000,netdev=net0"
  lQEMU_NETWORK+=" -netdev socket,id=net1,listen=:2001 -device e1000,netdev=net1"
  lQEMU_NETWORK+=" -netdev socket,id=net2,listen=:2002 -device e1000,netdev=net2"
  lQEMU_NETWORK+=" -netdev socket,id=net3,listen=:2003 -device e1000,netdev=net3"

  if [[ "${lARCH_END}" == "mipsel" ]]; then
    lQEMU_BIN="qemu-system-${lARCH_END}"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mips64r2el" ]]; then
    lQEMU_BIN="qemu-system-mips64el"
    lCPU="-cpu MIPS64R2-generic"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mipseb" ]]; then
    lQEMU_BIN="qemu-system-mips"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mips64r2eb" ]]; then
    lQEMU_BIN="qemu-system-mips64"
    lCPU="-cpu MIPS64R2-generic"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mips64v1eb" ]]; then
    lQEMU_BIN="qemu-system-mips64"
    # lCPU="-cpu MIPS64R2-generic"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mips64v1el" ]]; then
    lQEMU_BIN="qemu-system-mips64el"
    # lCPU="-cpu MIPS64R2-generic"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mips64n32eb" ]]; then
    lQEMU_BIN="qemu-system-mips64"
    lCPU="-cpu MIPS64R2-generic"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "armel"* ]]; then
    lKERNEL="zImage"
    lQEMU_BIN="qemu-system-arm"
    lQEMU_MACHINE="virt"
    lQEMU_DISK="-drive if=none,file=${IMAGE},format=raw,id=rootfs -device virtio-blk-device,drive=rootfs"
    lQEMU_ROOTFS="/dev/vda1"
    lQEMU_NETWORK="-device virtio-net-device,netdev=net0 -netdev socket,listen=:2000,id=net0"
    # lQEMU_NETWORK+=" -device virtio-net-device,netdev=net1 -netdev socket,listen=:2001,id=net1"
    # lQEMU_NETWORK+=" -device virtio-net-device,netdev=net2 -netdev socket,listen=:2002,id=net2"
    # lQEMU_NETWORK+=" -device virtio-net-device,netdev=net3 -netdev socket,listen=:2003,id=net3"
  elif [[ "${lARCH_END}" == "arm64el"* ]]; then
    lKERNEL="Image"
    lQEMU_BIN="qemu-system-aarch64"
    lQEMU_MACHINE="virt"
    lCPU="-cpu cortex-a57"
    # lCONSOLE="ttyAMA0"
    lQEMU_DISK="-drive if=none,file=${IMAGE},format=raw,id=rootfs -device virtio-blk-device,drive=rootfs"
    lQEMU_ROOTFS="/dev/vda1"
    lQEMU_NETWORK="-device virtio-net-device,netdev=net0 -netdev socket,listen=:2000,id=net0"
    # lQEMU_NETWORK+=" -device virtio-net-device,netdev=net1 -netdev socket,listen=:2001,id=net1"
    # lQEMU_NETWORK+=" -device virtio-net-device,netdev=net2 -netdev socket,listen=:2002,id=net2"
    # lQEMU_NETWORK+=" -device virtio-net-device,netdev=net3 -netdev socket,listen=:2003,id=net3"
  elif [[ "${lARCH_END}" == "x86el"* ]]; then
    lKERNEL="bzImage"
    # lKERNEL="vmlinux"
    lQEMU_BIN="qemu-system-x86_64"
    # lQEMU_BIN="qemu-system-i386"
    # lQEMU_MACHINE="pc-i440fx-3.1"
    lQEMU_MACHINE="pc-i440fx-8.2"
  elif [[ "${lARCH_END}" == "nios2el" ]]; then
    # not implemented -> Future
    lQEMU_BIN="qemu-system-nios2"
    lQEMU_MACHINE="10m50-ghrd"
    lQEMU_DISK="-drive file=${IMAGE},format=raw"
    lQEMU_NETWORK=""
  else
    print_output "[-] WARNING: No supported configuration found for ${ORANGE}${lARCH_END}${NC}."
    return
  fi

  run_network_id_emulation "${lCONSOLE}" "${lCPU}" "${lKERNEL}" "${lQEMU_BIN}" "${lQEMU_MACHINE}" "${lQEMU_DISK}" "${lQEMU_PARAMS}" "${lQEMU_NETWORK}" "${lQEMU_ROOTFS}" "${lIMAGE_NAME}" "${lINIT_FILE}" "${lARCH_END}" &

  local lPID="$!"
  disown "${lPID}" 2> /dev/null || true

  print_keepalive "${LOG_PATH_MODULE}/qemu.initial.serial.log" "${lIMAGE_NAME}" &
  local lALIVE_PID="$!"
  disown "${lALIVE_PID}" 2> /dev/null || true

  timeout --preserve-status --signal SIGINT 660 tail -F "${LOG_PATH_MODULE}/qemu.initial.serial.log" 2>/dev/null | grep -a -v "klogd" || true
  local lPID="$!"
  disown "${lPID}" 2> /dev/null || true

  kill "${lALIVE_PID}" || true
  print_output "[*] Call to stop emulation process - Source ${FUNCNAME[0]}" "no_log"
  stopping_emulation_process "${lIMAGE_NAME}"
  cleanup_emulator "${lIMAGE_NAME}"

  if ! [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
    print_output "[-] No ${ORANGE}${LOG_PATH_MODULE}/qemu.initial.serial.log${NC} log file generated."
  fi
}

print_keepalive() {
  # needed for run_kpanic_identification which we are calling from the keepalive printer
  local lLOG_FILE="${1:-}"
  local lIMAGE_NAME="${2:-}"

  # we give the whole system a few seconds until we start printing the keepalives
  # and also check for kernel panics
  sleep 10
  while(true); do
    print_output "[*] $(date) - EMBA emulation engine is live" "no_log"
    run_kpanic_identification_single "${lLOG_FILE}" "${lIMAGE_NAME}"
    sleep 5
  done
}

run_kpanic_identification_single() {
  local lLOG_FILE="${1:-}"
  local lIMAGE_NAME="${2:-}"

  if ! [[ -f "${lLOG_FILE}" ]]; then
    return
  fi

  lKPANIC=$(tail -n 20 "${lLOG_FILE}" | grep -a -c "Kernel panic - " || true)
  if [[ "${lKPANIC}" -gt 0 ]]; then
    print_output "[*] Kernel Panic detected - stopping emulation"
    tail -n 20 "${lLOG_FILE}" | grep -a "Kernel panic - " | tee -a "${LOG_FILE}" || true
    print_output "[*] Call to stop emulation process - Source ${FUNCNAME[0]}" "no_log"
    stopping_emulation_process "${lIMAGE_NAME}"
    pkill -9 -f tail.*-F.*"${lLOG_FILE}" &>/dev/null || true
  fi
}

#  run_network_id_emulation "${lCONSOLE}" "${lCPU}" "${lKERNEL}" "${lQEMU_BIN}" "${lQEMU_MACHINE}" "${lQEMU_DISK}" "${lQEMU_PARAMS}" "${lQEMU_NETWORK}" "${lQEMU_ROOTFS}" "${lIMAGE_NAME}" &
run_network_id_emulation() {
  local lCONSOLE="${1:-}"
  local lCPU="${2:-}"
  local lKERNEL="${3:-}"
  local lQEMU_BIN="${4:-}"
  local lQEMU_MACHINE="${5:-}"
  local lQEMU_DISK="${6:-}"
  local lQEMU_PARAMS="${7:-}"
  local lQEMU_NETWORK="${8:-}"
  local lQEMU_ROOTFS="${9:-}"
  local lIMAGE_NAME="${10:-}"
  local lINIT_FILE="${11:-}"
  local lARCH_END="${12:-}"

  print_output "[*] Qemu network identification run for ${ORANGE}${lARCH_END}${NC} - ${ORANGE}${lIMAGE_NAME}${NC}"

  # temp code for future use - currently only kernel v4 is supported
  if [[ "${lARCH_END}" == *"mips"* ]]; then
    export KERNEL_V=""
    get_kernel_version
    if [[ -n "${KERNEL_V}" ]]; then
      print_output "[*] Kernel ${KERNEL_V}.x detected -> Using Kernel v4.x"
      KERNEL_V=".${KERNEL_V}"
    else
      KERNEL_V=".4"
    fi
    # hard code v4.x
    KERNEL_V=".4"
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/${lKERNEL}.${lARCH_END}${KERNEL_V}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/${lKERNEL}.${lARCH_END}${KERNEL_V}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
  elif [[ "${lARCH_END}" == *"x86el"* ]] && [[ "${L10_KERNEL_V_LONG}" == "4.1.52" ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v4.1.17/${lKERNEL}.${lARCH_END}" ]]; then
      # x86el kernel has issues in version 4.1.52 - need further investigation
      print_output "[!] Bypassing known issues with kernel v${L10_KERNEL_V_LONG} - switching to v4.1.17"
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v4.1.17/${lKERNEL}.${lARCH_END}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
  else
    # ARM/x86 architecture
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/${lKERNEL}.${lARCH_END}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/${lKERNEL}.${lARCH_END}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
  fi

  check_qemu_instance_l10

  print_output "[*] Qemu parameters used in network detection mode:"
  print_output "$(indent "MACHINE: ${ORANGE}${lQEMU_MACHINE}${NC}")"
  print_output "$(indent "KERNEL: ${ORANGE}${lKERNEL}${NC}")"
  print_output "$(indent "DRIVE: ${ORANGE}${lQEMU_DISK}${NC}")"
  print_output "$(indent "KINIT: ${ORANGE}${KINIT}${NC}")"
  print_output "$(indent "ROOT_DEV: ${ORANGE}${lQEMU_ROOTFS}${NC}")"
  print_output "$(indent "QEMU binary: ${ORANGE}${lQEMU_BIN}${NC}")"
  print_output "$(indent "NETWORK: ${ORANGE}${lQEMU_NETWORK}${NC}")"
  print_output "$(indent "Init file: ${ORANGE}${lINIT_FILE}${NC}")"
  print_output "$(indent "Console interface: ${ORANGE}${lCONSOLE}${NC}")"
  print_ln
  print_output "[*] Starting firmware emulation for network identification - ${ORANGE}${lQEMU_BIN} / ${lARCH_END} / ${lIMAGE_NAME}${NC} ... use Ctrl-a + x to exit"
  print_ln

  # timeout ensures we are able to end this somewhere in the future - just in case something goes wrong
  write_script_exec "timeout --preserve-status --signal SIGINT 2000 ${lQEMU_BIN} -m 2048 -M ${lQEMU_MACHINE} ${lCPU} -kernel ${lKERNEL} ${lQEMU_DISK} -append \"root=${lQEMU_ROOTFS} console=${lCONSOLE} nandsim.parts=64,64,64,64,64,64,64,64,64,64 ${KINIT} rw debug ignore_loglevel print-fatal-signals=1 EMBA_NET=${EMBA_NET} EMBA_NVRAM=${EMBA_NVRAM} EMBA_KERNEL=${EMBA_KERNEL} EMBA_ETC=${EMBA_ETC} user_debug=0 firmadyne.syscall=1\" -nographic ${lQEMU_NETWORK} ${lQEMU_PARAMS} -serial file:${LOG_PATH_MODULE}/qemu.initial.serial.log -serial telnet:localhost:4321,server,nowait -serial unix:/tmp/qemu.${lIMAGE_NAME}.S1,server,nowait -monitor unix:/tmp/qemu.${lIMAGE_NAME},server,nowait ; pkill -9 -f tail.*-F.*\"${LOG_PATH_MODULE}\"" /tmp/do_not_create_run.sh 2
}

get_networking_details_emulation() {
  IMAGE_NAME="${1:-}"

  sub_module_title "Network identification - ${IMAGE_NAME}"
  export PANICS=()
  export DETECTED_IP=0
  export MISSING_FILES=()

  if [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
    local lETH_INT="NONE"
    local lVLAN_ID="NONE"
    local lNETWORK_MODE="bridge"
    local lNETWORK_DEVICE=""

    export NVRAMS=()
    export TCP_SERVICES_STARTUP=()
    export UDP_SERVICES_STARTUP=()

    local lNVRAM_ARR=()
    local lNVRAM_TMP=()
    local lNVRAM_ENTRY=""
    local lBRIDGE_INTERFACES=()
    local lBRIDGE_INT=""
    local lINTERFACE_CANDIDATES=()
    local lINTERFACE_CAND=""
    local lVLAN_INFOS=()
    local lVLAN_INFO=""
    local lVLAN_HW_INFO_DEV=()
    local lPORTS_ARR=()
    local lPORT=""

    local lTCP_PORT=""
    local lUDP_PORT=""
    local lMISSING_FILES_TMP=()
    local lMISSING_DIRS_TMP=()
    local lSERVICE_NAME=""

    mapfile -t lINTERFACE_CANDIDATES < <(grep -a "__inet_insert_ifa" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | cut -d: -f2- | sed -E 's/.*__inet_insert_ifa\[PID:\ [0-9]+\ //' \
     | sort -u | grep -v "device:lo ifa:0x0100007f" | grep -v -E " = -[0-9][0-9]" | sed 's/\[.*\]\ EMBA.*//' || true)
    mapfile -t lBRIDGE_INTERFACES < <(grep -a "br_add_if\|br_dev_ioctl" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | cut -d: -f4- | sort -u || true)
                #               br_add_if[PID: 246 (brctl)]: br:br0 dev:vlan1
    mapfile -t lVLAN_INFOS < <(grep -a "register_vlan_dev" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | cut -d: -f2- | sort -u | grep -v -E " = -[0-9][0-9]" || true)
    # mapfile -t PANICS < <(grep -a "Kernel panic - " "${LOG_PATH_MODULE}"/qemu.initial.serial.log | sort -u || true)
    # # ensure we only stop if we have a panic near the end - otherwise the system probably has rebooted and recovered
    mapfile -t PANICS < <(tail -n 50 "${LOG_PATH_MODULE}"/qemu.initial.serial.log | grep -a "Kernel panic - " | sort -u || true)
    mapfile -t lNVRAM_ARR < <(grep -a "\[NVRAM\] " "${LOG_PATH_MODULE}"/qemu.initial.serial.log | awk '{print $3}' | grep -a -E '[[:alnum:]]{3,50}' | sort -u || true)
    # we check all available qemu logs for services that are started:
    mapfile -t lPORTS_ARR < <(grep -a "inet_bind" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | sed -E 's/.*inet_bind\[PID:\ [0-9]+\ //' | sort -u || true)
    mapfile -t lVLAN_HW_INFO_DEV < <(grep -a -E "adding VLAN [0-9] to HW filter on device eth[0-9]" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | awk -F\  '{print $NF}' | sort -u || true)

    # we handle missing files in setup_network_config -> there we already remount the filesystem and we can perform the changes
    mapfile -t lMISSING_FILES_TMP < <(grep -a -E "No such file or directory" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | tr ' ' '\n' | grep -a "/" | grep -a -v proc | tr -d ':' | tr -d "'" | tr -d '`' | sort -u || true)
    MISSING_FILES+=( "${lMISSING_FILES_TMP[@]}" )
    mapfile -t lMISSING_DIRS_TMP < <(grep -a -E "nonexistent directory" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | tr ' ' '\n' | grep -a "/" | grep -a -v proc | tr -d ':' | tr -d "'" | tr -d '`' | grep -a "^/" | sort -u || true)
    MISSING_FILES+=( "${lMISSING_DIRS_TMP[@]}" )

    lNVRAM_TMP=( "${lNVRAM_ARR[@]}" )

    if [[ "${#lINTERFACE_CANDIDATES[@]}" -gt 0 || "${#lBRIDGE_INTERFACES[@]}" -gt 0 || "${#lVLAN_INFOS[@]}" -gt 0 || "${#lPORTS_ARR[@]}" -gt 0 || "${#lNVRAM_TMP[@]}" -gt 0 ]]; then
      print_output "[+] Booted system detected."
      BOOTED="yes"
    fi

    if [[ -v lNVRAM_TMP[@] ]]; then
      for lNVRAM_ENTRY in "${lNVRAM_TMP[@]}"; do
        if [[ "${lNVRAM_ENTRY}" =~ [[:print:]] ]]; then
          if [[ ! " ${NVRAMS[*]} " =~  ${lNVRAM_ENTRY}  ]]; then
            NVRAMS+=( "${lNVRAM_ENTRY}" )
          fi
        fi
      done
      print_output "[*] NVRAM access detected ${ORANGE}${#NVRAMS[@]}${NC} times."
      print_ln
    fi

    if [[ -v lPORTS_ARR[@] ]]; then
      for lPORT in "${lPORTS_ARR[@]}"; do
        lSERVICE_NAME=$(strip_color_codes "$(echo "${lPORT}" | sed -e 's/.*\((.*)\).*/\1/g' | tr -d "(" | tr -d ")")")
        lSERVICE_NAME="${lSERVICE_NAME//[![:print:]]/}"
        lTCP_PORT=$(strip_color_codes "$(echo "${lPORT}" | grep "SOCK_STREAM" | sed 's/.*SOCK_STREAM,\ //' | sort -u | cut -d: -f2)" || true)
        lTCP_PORT="${lTCP_PORT//[![:print:]]/}"
        lUDP_PORT=$(strip_color_codes "$(echo "${lPORT}" | grep "SOCK_DGRAM" | sed 's/.*SOCK_DGRAM,\ //' | sort -u | cut -d: -f2)" || true)
        lUDP_PORT="${lUDP_PORT//[![:print:]]/}"

        if [[ "${lTCP_PORT}" =~ [0-9]+ ]]; then
          print_output "[*] Detected TCP service startup: ${ORANGE}${lSERVICE_NAME}${NC} / ${ORANGE}${lTCP_PORT}${NC}"
          TCP_SERVICES_STARTUP+=( "${lTCP_PORT}" )
        fi
        if [[ "${lUDP_PORT}" =~ [0-9]+ ]]; then
          print_output "[*] Detected UDP service startup: ${ORANGE}${lSERVICE_NAME}${NC} / ${ORANGE}${lUDP_PORT}${NC}"
          UDP_SERVICES_STARTUP+=( "${lUDP_PORT}" )
        fi

        SERVICES_STARTUP+=( "${lSERVICE_NAME}" )
      done
    fi

    mapfile -t SERVICES_STARTUP < <(printf "%s\n" "${SERVICES_STARTUP[@]}" | sort -u)
    mapfile -t UDP_SERVICES_STARTUP < <(printf "%s\n" "${UDP_SERVICES_STARTUP[@]}" | sort -u)
    mapfile -t TCP_SERVICES_STARTUP < <(printf "%s\n" "${TCP_SERVICES_STARTUP[@]}" | sort -u)

    for lVLAN_INFO in "${lVLAN_INFOS[@]}"; do
      # register_vlan_dev[PID: 128 (vconfig)]: dev:eth1.1 vlan_id:1
      print_output "[*] Possible VLAN details detected: ${ORANGE}${lVLAN_INFO}${NC}"
    done

    if [[ -v lBRIDGE_INTERFACES[@] ]]; then
      mapfile -t lBRIDGE_INTERFACES < <(printf "%s\n" "${lBRIDGE_INTERFACES[@]}" | sort -u)
      print_ln
    fi

    for lINTERFACE_CAND in "${lINTERFACE_CANDIDATES[@]}"; do
      local l_NW_ENTRY_PRIO=1
      local lADJUST_PRIO=0  # adjust priority for detected network configuration

      lINTERFACE_CAND="${lINTERFACE_CAND//[![:print:]]/}"
      print_output "[*] Possible interface candidate detected: ${ORANGE}${lINTERFACE_CAND}${NC}"
      # lINTERFACE_CAND -> __inet_insert_ifa[PID: 139 (ifconfig)]: device:br0 ifa:0xc0a80001
      local lIP_ADDRESS_HEX=()
      local lIP_CAND=""
      lIP_CAND=$(echo "${lINTERFACE_CAND}" | tr ' ' '\n' | grep ifa | cut -d: -f2 | sed 's/0x//')
      # shellcheck disable=SC2001
      mapfile -t lIP_ADDRESS_HEX < <(echo "${lIP_CAND:0:8}" | sed 's/../0x&\n/g')
      # lIP_ADDRESS_HEX -> c0a80001
      # as I don't get it to change the hex ip to dec with printf, we do it the poor way:
      local lIP=""
      local lCNT=0
      for _IPs in "${lIP_ADDRESS_HEX[@]}"; do
        lCNT=$((lCNT+1))
        if [[ "${_IPs}" == "0x"* ]]; then
          # shellcheck disable=SC2004
          lIP="${lIP}.$((${_IPs}))"
        fi
        # ensure we only check a valid ip address - this is needed if our IP address extraction gets mangled data:
        [[ "${lCNT}" -ge 4 ]] && break
      done

      lIP="${lIP/\.}"

      IP_ADDRESS_=""
      if [[ "${D_END,,}" == "eb" ]]; then
        IP_ADDRESS_="${lIP}"
      elif [[ "${D_END,,}" == "el" ]]; then
        IP_ADDRESS_=$(echo "${lIP}" | tr '.' '\n' | tac | tr '\n' '.' | sed 's/\.$//')
      fi

      # we try to extract a backup IP address from the nvram log
      # afterwards we can use this ip if we have a bridge interface with "0.0.0.0"
      local lNVRAM_BACKUP_IP=""
      lNVRAM_BACKUP_IP=$(grep -E -h "nvram_get_buf.*[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" "${LOG_PATH_MODULE}"/qemu.initial.serial.log \
        | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | grep -v "0\.0\.0\.0\|127\.0\.\|255\." | sort -u | head -1 || true)

      # handle IP addresses 0.0.0.0 somehow:
      if [[ "${IP_ADDRESS_}" == "0.0.0.0" ]]; then
        lADJUST_PRIO=$((lADJUST_PRIO-2))
        # we use one of the idenfied IP addresses. If no IP address available we switch to default 192.168.0.1
        if [[ "${lNVRAM_BACKUP_IP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
          IP_ADDRESS_="${lNVRAM_BACKUP_IP}"
          print_output "[*] Originally identified IP 0.0.0.0 -> using backup IP ${IP_ADDRESS_}"
        elif [[ -s "${L10_SYS_EMU_RESULTS}" ]]; then
          IP_ADDRESS_=$(cut -d\; -f8 "${L10_SYS_EMU_RESULTS}" | sort -u | tail -n1)
          IP_ADDRESS_="${IP_ADDRESS_/*\ /}"
          print_output "[*] Originally identified IP 0.0.0.0 -> using backup IP ${IP_ADDRESS_}"
        else
          IP_ADDRESS_="192.168.0.1"
          print_output "[*] Originally identified IP 0.0.0.0 -> using default IP ${IP_ADDRESS_}"
        fi
      fi

      # filter for non usable IP addresses:
      if [[ "${IP_ADDRESS_}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && ! [[ "${IP_ADDRESS_}" == "127.0.0."* ]]; then
        print_output "[*] Identified IP address: ${ORANGE}${IP_ADDRESS_}${NC} / ${ORANGE}${lINTERFACE_CAND}${NC}"
        DETECTED_IP=1
        # get the network device from our interface candidate
        lNETWORK_DEVICE="$(echo "${lINTERFACE_CAND}" | grep device | cut -d: -f2- | sed "s/^.*\]:\ //" | awk '{print $1}' | cut -d: -f2 || true)"
        # lINTERFACE_CAND -> __inet_insert_ifa[PID: 139 (ifconfig)]: device:br0 ifa:0xc0a80001
        #                   __inet_insert_ifa[PID: 899 (udhcpc)]: device:eth0 ifa:0xbea48f41
        # lNETWORK_DEVICE -> eth0, eth1.1, br0 ...

        if [[ -n "${lNETWORK_DEVICE}" ]]; then
          # if the network device is not a eth it is a bridge interface
          # if we have lBRIDGE_INTERFACES we also check it here (this way we can correct the br interface entry):
          if [[ "${lNETWORK_DEVICE}" != *"eth"* ]] || [[ "${#lBRIDGE_INTERFACES[@]}" -gt 0 ]]; then
            print_output "[*] Possible br interface detected: ${ORANGE}${lNETWORK_DEVICE}${NC} / IP: ${ORANGE}${IP_ADDRESS_}${NC}"
            lNETWORK_MODE="bridge"
            if [[ "${#lBRIDGE_INTERFACES[@]}" -gt 0 ]]; then
              for lBRIDGE_INT in "${lBRIDGE_INTERFACES[@]}"; do
                # lBRIDGE_INT -> br_add_if[PID: 494 (brctl)]: br:br0 dev:eth0.1
                #               br_add_if[PID: 246 (brctl)]: br:br0 dev:vlan1
                # lNETWORK_DEVICE -> br0
                lBRIDGE_INT="${lBRIDGE_INT//[![:print:]]/}"
                print_output "[*] Testing bridge interface: ${ORANGE}${lBRIDGE_INT}${NC}" "no_log"
                lVLAN_ID="NONE"
                # the lBRIDGE_INT entry also includes our lNETWORK_DEVICE ... eg br:br0 dev:eth1.1
                if [[ "${lBRIDGE_INT}" == *"${lNETWORK_DEVICE}"* ]]; then
                  # matching is quite good. This means that the bridge entry (br_add_if[PID: 494 (brctl)]: br:br0 dev:eth0)
                  # is matching our interface candidate entry (__inet_insert_ifa[PID: 139 (ifconfig)]: device:eth0 ifa:0xc0a80001)
                  # Nevertheless, we also need to process non matching results where we have network entries without a matching
                  # bridge interface
                  print_output "[+] Processing matching bridge interface: ${ORANGE}${lBRIDGE_INT}${GREEN} / network device: ${ORANGE}${lNETWORK_DEVICE}${NC}"
                  lADJUST_PRIO=$((lADJUST_PRIO+1))
                else
                  print_output "[*] Processing NON matching bridge interface: ${ORANGE}${lBRIDGE_INT}${NC} / network device: ${ORANGE}${lNETWORK_DEVICE}${NC}"
                  lADJUST_PRIO=$((lADJUST_PRIO-1))
                fi
                # br_add_if[PID: 138 (brctl)]: br:br0 dev:eth1.1
                # extract the eth1 from dev:eth1
                lETH_INT="$(echo "${lBRIDGE_INT}" | grep -o "dev:.*" | cut -d. -f1 | cut -d: -f2)"
                lETH_INT="${lETH_INT//[![:print:]]/}"
                # do we have vlans?
                if [[ -v lVLAN_INFOS[@] ]]; then
                  iterate_vlans "${lETH_INT}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${IP_ADDRESS_}" "${lADJUST_PRIO}" "${lVLAN_INFOS[@]}"
                fi
                if echo "${lBRIDGE_INT}" | awk '{print $2}' | cut -d: -f2 | grep -q -E "[0-9]\.[0-9]"; then
                  # we have a vlan entry in our lBRIDGE_INT entry br:br0 dev:eth1.1:
                  lVLAN_ID="$(echo "${lBRIDGE_INT}" | grep -o "dev:.*" | cut -d. -f2)"
                  lVLAN_ID="${lVLAN_ID//[![:print:]]/}"
                fi
                if [[ -v lVLAN_HW_INFO_DEV[@] ]]; then
                  # lets store the current details before we do this VLAN iteration
                  l_NW_ENTRY_PRIO=$((3+lADJUST_PRIO))
                  store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
                  # if we have found some entry "adding VLAN [0-9] to HW filter on device ethX" in our qemu logs
                  # we check all these entries now and generate additional configurations for further evaluation
                  for lETH_INT in "${lVLAN_HW_INFO_DEV[@]}"; do
                    # if we found multiple interfaces belonging to a vlan we need to store all of them:
                    lETH_INT="${lETH_INT//[![:print:]]/}"
                    lVLAN_ID=$(grep -a -o -E "adding VLAN [0-9] to HW filter on device ${lETH_INT}" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | awk '{print $3}' | sort -u)
                    # initial entry with possible vlan information
                    l_NW_ENTRY_PRIO=$((5+lADJUST_PRIO))
                    store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"

                    # entry with vlan NONE (just in case as backup)
                    store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "NONE" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"

                    if ! [[ "${lNETWORK_DEVICE}" == *br[0-9]* ]] && ! [[ "${lNETWORK_DEVICE}" == *eth[0-9]* ]]; then
                      # entry with vlan NONE and interface br0 - just as another fallback solution
                      local lNETWORK_DEVICE="br0"
                      print_output "[*] Fallback bridge interface - #1 ${ORANGE}${lNETWORK_DEVICE}${NC}"
                      l_NW_ENTRY_PRIO=$((3+lADJUST_PRIO))
                      store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
                    fi
                  done
                fi
                # now we set the orig. network_device with the new details (lVLAN_ID=NONE):
                store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"

                if ! [[ "${lNETWORK_DEVICE}" == *br[0-9]* ]] && ! [[ "${lNETWORK_DEVICE}" == *eth[0-9]* ]]; then
                  # if we have a bridge device like br-lan we ensure we also have an entry with a usual br0 interface
                  local lNETWORK_DEVICE="br0"
                  print_output "[*] Fallback bridge interface - #2 ${ORANGE}${lNETWORK_DEVICE}${NC}"
                  l_NW_ENTRY_PRIO=$((3+lADJUST_PRIO))
                  store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
                fi
                # if we have found that the br entry has for eg an ethX interface, we now check for the real br interface entry -> lNETWORK_DEVICE
                lNETWORK_DEVICE="$(echo "${lBRIDGE_INT}" | grep -o "br:.*" | cut -d\  -f1 | cut -d: -f2)"
                lNETWORK_DEVICE="${lNETWORK_DEVICE//[![:print:]]/}"
                l_NW_ENTRY_PRIO=$((4+lADJUST_PRIO))
                store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE:-br0}" "${lETH_INT:-eth0}" "${lVLAN_ID:-0}" "${lNETWORK_MODE:-bridge}" "${l_NW_ENTRY_PRIO}"
              done
            else
              # set typical default values - this is just in case we have not found br_add_if entries:
              lVLAN_ID="NONE"
              l_NW_ENTRY_PRIO=$((3+lADJUST_PRIO))
              if [[ "$(grep -ac "eth0" "${LOG_PATH_MODULE}"/qemu.initial.serial.log)" -gt 0 ]]; then
                lETH_INT="eth0"
                store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
              fi
              if [[ "$(grep -ac "eth1" "${LOG_PATH_MODULE}"/qemu.initial.serial.log)" -gt 0 ]]; then
                lETH_INT="eth1"
                store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
              fi
            fi
          elif [[ "${lNETWORK_DEVICE}" == *"eth"* ]]; then
            print_output "[*] Possible eth network interface detected: ${ORANGE}${lNETWORK_DEVICE}${GREEN} / IP: ${ORANGE}${IP_ADDRESS_}${NC}"
            lNETWORK_MODE="normal"
            if echo "${lNETWORK_DEVICE}" | grep -q -E "[0-9]\.[0-9]"; then
              # now we know that there is a vlan number - extract the vlan number now:
              l_NW_ENTRY_PRIO=$((4+lADJUST_PRIO))
              lVLAN_ID="$(echo "${lNETWORK_DEVICE}" | cut -d. -f2 | grep -E "[0-9]+")"
              lVLAN_ID="${lVLAN_ID//[![:print:]]/}"
            elif [[ -v lVLAN_INFOS[@] ]]; then
              lETH_INT="${lNETWORK_DEVICE/\.*}"
              iterate_vlans "${lETH_INT}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${IP_ADDRESS_}" "${lADJUST_PRIO}" "${lVLAN_INFOS[@]}"
            else
              l_NW_ENTRY_PRIO=$((3+lADJUST_PRIO))
              lVLAN_ID="NONE"
            fi
            lNETWORK_DEVICE="${lNETWORK_DEVICE/\.*}"
            lETH_INT="${lNETWORK_DEVICE/\.*}"
            store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
          else
            # could not happen - just for future extension
            print_output "[+] Possible other interface detected: ${ORANGE}${lNETWORK_DEVICE}${NC}"
            lVLAN_ID="NONE"
            lNETWORK_MODE="normal"
            lNETWORK_DEVICE="${lNETWORK_DEVICE/\.*}"
            lETH_INT="${lNETWORK_DEVICE}"
            l_NW_ENTRY_PRIO=1
            store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
          fi
        fi
        # this is a default (fallback) entry with the correct ip address:
        l_NW_ENTRY_PRIO=$((2+lADJUST_PRIO))
        store_interface_details "${IP_ADDRESS_}" "br0" "${lETH_INT:-eth0}" "${lVLAN_ID:-NONE}" "default" "${l_NW_ENTRY_PRIO}"
        # this is a default (fallback) entry with the correct ip address:
        l_NW_ENTRY_PRIO=$((1+lADJUST_PRIO))
        store_interface_details "${IP_ADDRESS_}" "${lETH_INT:-eth0}" "${lETH_INT:-eth0}" "${lVLAN_ID:-NONE}" "interface" "${l_NW_ENTRY_PRIO}"
      fi
    done

    # this is for testing. Probably we can improve it in the future to have a better fallback handling
    if [[ "${L10_DEBUG_MODE}" -eq 2 ]]; then
      if [[ "${#lINTERFACE_CANDIDATES[@]}" -eq 0 ]] || [[ "${L10_DEBUG_MODE}" -eq 2 ]]; then
        # in this case we do not have valid ip addresses
        # this mechanism is very alpha and just as fallback mechanism designed
        # we need to further improve this mechanism to include VLAN detection, bridge vs interface vs normal ...
        local lIP_ADDR_BACKUP_ARR=()
        local lIP_ADDR_BACKUP=""
        mapfile -t lIP_ADDR_BACKUP_ARR < <(grep -h "ip.*addr" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | grep -o -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" \
          | grep -E -v "\.255$" | grep -v -E "\.0$" | grep -v -E "^127\." | grep -v "^255\." | sort -u || true)
        for lIP_ADDR_BACKUP in "${lIP_ADDR_BACKUP_ARR[@]}"; do
          # if we have bridge interfaces found and we have some eth0 entries in our qemu log we guess a shiny configuration
          if [[ -v lBRIDGE_INTERFACES[@] ]]; then
            if [[ "$(grep -ac "eth0" "${LOG_PATH_MODULE}"/qemu.initial.serial.log)" -gt 0 ]]; then
              l_NW_ENTRY_PRIO=$((2+lADJUST_PRIO))
              store_interface_details "${lIP_ADDR_BACKUP}" "br0" "eth0" "NONE" "bridge" "${l_NW_ENTRY_PRIO}"
              store_interface_details "${lIP_ADDR_BACKUP}" "br0" "eth0" "0" "bridge" "${l_NW_ENTRY_PRIO}"
            fi
          fi
          l_NW_ENTRY_PRIO=1
          if [[ "$(grep -ac "eth0" "${LOG_PATH_MODULE}"/qemu.initial.serial.log)" -gt 0 ]]; then
            store_interface_details "${lIP_ADDR_BACKUP}" "eth0" "eth0" "NONE" "interface" "${l_NW_ENTRY_PRIO}"
            store_interface_details "${lIP_ADDR_BACKUP}" "br0" "eth0" "NONE" "default" "${l_NW_ENTRY_PRIO}"
          fi
          if [[ "$(grep -ac "eth1" "${LOG_PATH_MODULE}"/qemu.initial.serial.log)" -gt 0 ]]; then
            store_interface_details "${lIP_ADDR_BACKUP}" "eth1" "eth1" "NONE" "interface" "${l_NW_ENTRY_PRIO}"
            store_interface_details "${lIP_ADDR_BACKUP}" "br0" "eth1" "NONE" "default" "${l_NW_ENTRY_PRIO}"
          fi
        done
      fi
    fi

    if [[ "${#IPS_INT_VLAN[@]}" -eq 0 ]]; then
      # this section is if we have a brctl entry but no IP address
      for lBRIDGE_INT in "${lBRIDGE_INTERFACES[@]}"; do
        # br_add_if[PID: 138 (brctl)]: br:br0 dev:eth1.1
        # lBRIDGE_INT -> br_add_if[PID: 494 (brctl)]: br:br0 dev:eth0.1
        # lNETWORK_DEVICE -> br0
        print_output "[*] Possible bridge interface candidate detected: ${ORANGE}${lBRIDGE_INT}${NC}"
        lETH_INT="$(echo "${lBRIDGE_INT}" | grep -o "dev:.*" | cut -d. -f1 | cut -d: -f2 || true)"
        lETH_INT="${lETH_INT//[![:print:]]/}"
        lNETWORK_DEVICE="$(echo "${lBRIDGE_INT}" | sed "s/^.*\]:\ //" | grep -o "br:.*" | cut -d\  -f1 | cut -d: -f2 || true)"
        lNETWORK_DEVICE="${lNETWORK_DEVICE//[![:print:]]/}"
        IP_ADDRESS_="192.168.0.1"
        lNETWORK_MODE="bridge"
        if echo "${lBRIDGE_INT}" | awk '{print $2}' | cut -d: -f2 | grep -q -E "[0-9]\.[0-9]"; then
          # we have a vlan entry:
          # lVLAN_ID="$(echo "${lBRIDGE_INT}" | sed "s/^.*\]:\ //" | grep -o "dev:.*" | cut -d. -f2 | tr -dc '[:print:]' || true)"
          lVLAN_ID="$(echo "${lBRIDGE_INT}" | grep -o "dev:.*" | cut -d. -f2 || true)"
          lVLAN_ID="${lVLAN_ID//[![:print:]]/}"
        else
          lVLAN_ID="NONE"
          if [[ -v lVLAN_INFOS[@] ]]; then
            iterate_vlans "${lETH_INT}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${IP_ADDRESS_}" "${lADJUST_PRIO}" "${lVLAN_INFOS[@]}"
          fi
        fi
        l_NW_ENTRY_PRIO=$((2+lADJUST_PRIO))
        store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
      done
    fi

    # fallback - default network configuration:
    # we always add this as the last resort - with this at least ICMP should be possible in most cases
    if [[ ! " ${IPS_INT_VLAN[*]} " =~ "normal" ]]; then
      # print_output "[*] No IP address - use default address: ${ORANGE}192.168.0.1${NC}."
      # print_output "[*] No VLAN."
      # print_output "[*] No Network interface - use ${ORANGE}eth0${NC} network."
      IP_ADDRESS_="192.168.0.1"
      lNETWORK_MODE="normal"
      l_NW_ENTRY_PRIO=1
      if [[ "${FW_VENDOR:-}" == "AVM" ]]; then
        # for AVM fritzboxen the default IP is set to the correct one:
        IP_ADDRESS_="192.168.178.1"
        l_NW_ENTRY_PRIO=$((2+lADJUST_PRIO))
      fi
      lVLAN_ID="NONE"
      lETH_INT="eth0"
      lNETWORK_DEVICE="br0"
      store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
    fi

    # fallback - default network configuration:
    # we always add this as the last resort - with this at least ICMP should be possible in most cases
    if [[ ! " ${IPS_INT_VLAN[*]} " =~ "default" ]]; then
      # print_output "[*] No IP address - use default address: ${ORANGE}192.168.0.1${NC}."
      # print_output "[*] No VLAN."
      # print_output "[*] No Network interface - use ${ORANGE}eth0${NC} network."
      IP_ADDRESS_="192.168.0.1"
      lNETWORK_MODE="default"
      l_NW_ENTRY_PRIO=1
      if [[ "${FW_VENDOR:-}" == "AVM" ]]; then
        # for AVM fritzboxen the default IP is set to the correct one:
        IP_ADDRESS_="192.168.178.1"
        l_NW_ENTRY_PRIO=$((2+lADJUST_PRIO))
      fi
      lVLAN_ID="NONE"
      lETH_INT="eth0"
      lNETWORK_DEVICE="br0"
      store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
    fi

    for PANIC in "${PANICS[@]}"; do
      print_output "[!] WARNING: Kernel Panic detected: ${ORANGE}${PANIC}${NC}"
      print_output "${NC}"
      PANICS=()
    done
    color_qemu_log "${LOG_PATH_MODULE}/qemu.initial.serial.log"
  else
    print_output "[-] No ${ORANGE}${LOG_PATH_MODULE}/qemu.initial.serial.log${NC} log file generated."
  fi
  print_ln
}

store_interface_details() {
  local lIP_ADDRESS="${1:-192.168.0.1}"
  local lNETWORK_DEVICE="${2:-br0}"
  local lETH_INT="${3:-eth0}"
  local lVLAN_ID="${4:-NONE}"
  local lNETWORK_MODE="${5:-bridge}"
  local lENTRY_PRIO="${6:-1}"

  print_output "[+] Interface details detected: IP address: ${ORANGE}${lIP_ADDRESS}${GREEN} / bridge dev: ${ORANGE}${lNETWORK_DEVICE}${GREEN} / network device: ${ORANGE}${lETH_INT}${GREEN} / vlan id: ${ORANGE}${lVLAN_ID}${GREEN} / network mode: ${ORANGE}${lNETWORK_MODE}${GREEN} / priority: ${ORANGE}${lENTRY_PRIO}${NC}"

  IPS_INT_VLAN+=( "${lENTRY_PRIO}"\;"${lIP_ADDRESS}"\;"${lNETWORK_DEVICE}"\;"${lETH_INT}"\;"${lVLAN_ID}"\;"${lNETWORK_MODE}" )
}

iterate_vlans() {
  local lETH_INT="${1:-}"
  local lNETWORK_MODE="${2:-}"
  local lNETWORK_DEVICE="${3:-}"
  local lIP_ADDRESS="${4:-}"
  local lADJUST_PRIO="${5:-}"
  shift 5
  local lVLAN_INFOS_ARR=("$@")

  local lETH_INT_=""
  local lETH_INTS_ARR=()
  local lVLAN_DEV=""
  local lVLAN_ID="NONE"
  local lVLAN_INFO=""

  for lVLAN_INFO in "${lVLAN_INFOS_ARR[@]}"; do
    print_output "[*] Analyzing VLAN details ${ORANGE}${lVLAN_INFO}${NC}"
    if ! [[ "${lVLAN_INFO}" == *"register_vlan_dev"* ]]; then
      continue
    fi
    # lVLAN_INFO -> register_vlan_dev[PID: 848 (vconfig)]: dev:eth2.1 vlan_id:1
    #              register_vlan_dev[PID: 213 (vconfig)]: dev:vlan1 vlan_id:1
    lVLAN_DEV=$(echo "${lVLAN_INFO}" | sed "s/^.*\]:\ //" | awk '{print $1}' | cut -d: -f2 | cut -d\. -f1)
    print_output "[*] VLAN details: ${ORANGE}${lVLAN_INFO}${NC}"
    print_output "[*] Interface details: ${ORANGE}${lETH_INT}${NC}"
    if [[ "${lVLAN_DEV}" == *"${lETH_INT}"* ]]; then
      print_output "[*] Possible matching VLAN details detected: ${ORANGE}${lVLAN_INFO}${NC}"
      l_NW_ENTRY_PRIO=$((5+lADJUST_PRIO))
      lVLAN_ID=$(echo "${lVLAN_INFO}" | sed "s/.*vlan_id://" | grep -E -o "[0-9]+" )
      lVLAN_ID="${lVLAN_ID//[![:print:]]/}"
    else
      l_NW_ENTRY_PRIO=$((2+lADJUST_PRIO))
      lVLAN_ID="NONE"
    fi
    store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"

    # check this later
    # store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "eth0" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
    # store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "eth0" "0" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
    # store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "eth1" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
    # store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "eth1" "0" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"

    # if we have entries without an interface name, we need to identify an interface name:
    # register_vlan_dev[PID: 212 (vconfig)]: dev:vlan1 vlan_id:1
    # for this we try to check the qemu output for vlan entries and generate the configuration entry
    if grep -a -q "adding VLAN [0-9] to HW filter on device eth[0-9]" "${LOG_PATH_MODULE}"/qemu.initial.serial.log; then
      mapfile -t lETH_INTS_ARR < <(grep -a -E "adding VLAN [0-9] to HW filter on device eth[0-9]" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | awk -F\  '{print $NF}' | sort -u)
      for lETH_INT_ in "${lETH_INTS_ARR[@]}"; do
        # if we found multiple interfaces belonging to a vlan we need to store all of them:
        lETH_INT_="${lETH_INT_//[![:print:]]/}"
        l_NW_ENTRY_PRIO=$((4+lADJUST_PRIO))
        store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "${lETH_INT_}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
      done
    fi
  done
}

setup_network_emulation() {
  local lIPS_INT_VLAN_CFG="${1:-}"

  local lIP_ADDRESS=""
  local lNETWORK_DEVICE=""
  local lETH_INT=""
  local lNETWORK_MODE=""
  local lTAP_ID=""
  local lHOSTIP=""
  local lVLAN_ID=""
  export BR_NUM=0
  export ETH_NUM=0

  sub_module_title "Setup networking - ${lIPS_INT_VLAN_CFG//\;/-}"

  # Source: IPS_INT_VLAN+=( "PRIO"-"${IP_ADDRESS_}"-"${lNETWORK_DEVICE}"-"${lETH_INT}"-"${lVLAN_ID}"-"${lNETWORK_MODE}" )
  lIP_ADDRESS=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f2)
  lNETWORK_DEVICE=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f3)
  lETH_INT=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f4)
  lVLAN_ID=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f5)
  lNETWORK_MODE=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f6)

  # a br interface with a number ... eg br0, br1 ... but no br-lan interface
  if [[ "${lNETWORK_DEVICE}" == *"br"* ]] && [[ "${lNETWORK_DEVICE}" == *[0-9]* ]]; then
    BR_NUM="${lNETWORK_DEVICE/br}"
    BR_NUM="${BR_NUM//[![:print:]]/}"
  fi
  if [[ "${lETH_INT}" == *"eth"* ]]; then
    ETH_NUM="${lETH_INT/eth}"
    ETH_NUM="${ETH_NUM//[![:print:]]/}"
  fi

  # used for generating startup scripts for offline analysis
  export ARCHIVE_PATH="${LOG_PATH_MODULE}"/archive-"${IMAGE_NAME}"-"${RANDOM}"

  if ! [[ -d "${ARCHIVE_PATH}" ]]; then
    mkdir "${ARCHIVE_PATH}"
  fi

  lTAP_ID=$(shuf -i 1-1000 -n 1)

  # bridge, no vlan, ip address
  export TAPDEV_0="tap${lTAP_ID}_0"
  if ifconfig | grep -q "${TAPDEV_0}"; then
    lTAP_ID=$(shuf -i 1-1000 -n 1)
    TAPDEV_0="tap${lTAP_ID}_0"
  fi
  export HOSTNETDEV_0="${TAPDEV_0}"
  print_output "[*] Creating TAP device ${ORANGE}${TAPDEV_0}${NC} ..."
  write_script_exec "echo -e \"Creating TAP device ${TAPDEV_0}\n\"" "${ARCHIVE_PATH}"/run.sh 0
  write_script_exec "command -v tunctl > /dev/null || (echo \"Missing tunctl ... check your installation - install uml-utilities package\" && exit 1)" "${ARCHIVE_PATH}"/run.sh 0
  write_script_exec "tunctl -t ${TAPDEV_0}" "${ARCHIVE_PATH}"/run.sh 1

  if [[ "${lVLAN_ID}" != "NONE" ]]; then
    HOSTNETDEV_0="${TAPDEV_0}"."${lVLAN_ID}"
    print_output "[*] Bringing up HOSTNETDEV ${ORANGE}${HOSTNETDEV_0}${NC} / VLAN ID ${ORANGE}${lVLAN_ID}${NC} / TAPDEV ${ORANGE}${TAPDEV_0}${NC}."
    write_script_exec "echo -e \"Bringing up HOSTNETDEV ${ORANGE}${HOSTNETDEV_0}${NC} / VLAN ID ${ORANGE}${lVLAN_ID}${NC} / TAPDEV ${ORANGE}${TAPDEV_0}${NC}.\n\"" "${ARCHIVE_PATH}"/run.sh 0
    write_script_exec "ip link add link ${TAPDEV_0} name ${HOSTNETDEV_0} type vlan id ${lVLAN_ID}" "${ARCHIVE_PATH}"/run.sh 1
    write_script_exec "ip link set ${TAPDEV_0} up" "${ARCHIVE_PATH}"/run.sh 1
  fi

  if [[ "${lIP_ADDRESS}" != "NONE" ]]; then
    # we change the host IP based on the identified IP address:
    if [[ "$(echo "${lIP_ADDRESS}" | sed 's/\./&\n/g' | grep -v -E "[0-9]+\.$")" -ne 2 ]]; then
      lHOSTIP="$(echo "${lIP_ADDRESS}" | sed 's/\./&\n/g' | sed -E 's/^[0-9]+$/2/' | tr -d '\n')"
    else
      lHOSTIP="$(echo "${lIP_ADDRESS}" | sed 's/\./&\n/g' | sed -E 's/^[0-9]+$/3/' | tr -d '\n')"
    fi
    print_output "[*] Bringing up HOSTIP ${ORANGE}${lHOSTIP}${NC} / IP address ${ORANGE}${lIP_ADDRESS}${NC} / TAPDEV ${ORANGE}${TAPDEV_0}${NC}."
    write_script_exec "echo -e \"Bringing up HOSTIP ${ORANGE}${lHOSTIP}${NC} / IP address ${ORANGE}${lIP_ADDRESS}${NC} / TAPDEV ${ORANGE}${TAPDEV_0}${NC}.\n\"" "${ARCHIVE_PATH}"/run.sh 0

    write_script_exec "ip link set ${HOSTNETDEV_0} up" "${ARCHIVE_PATH}"/run.sh 1

    write_script_exec "ip addr add ${lHOSTIP}/8 dev ${HOSTNETDEV_0}" "${ARCHIVE_PATH}"/run.sh 1

    write_script_exec "ifconfig -a" "${ARCHIVE_PATH}"/run.sh 1
    write_script_exec "route -n" "${ARCHIVE_PATH}"/run.sh 1
  fi

  print_ln
  write_network_config_to_filesystem "${IMAGE_NAME}" "${lETH_INT}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${lIP_ADDRESS}"
}

write_network_config_to_filesystem() {
  local lIMAGE_NAME="${1:-}"
  local lETH_INT="${2:-}"
  local lNETWORK_MODE="${3:-}"
  local lNETWORK_DEVICE="${4:-}"
  local lIP_ADDRESS="${5:-}"

  local lDEVICE="NA"
  local lFILE_PATH_MISSING=""
  local lFILENAME_MISSING=""
  local lDIR_NAME_MISSING=""
  local lFOUND_MISSING=""

  # mount filesystem again for network config:
  print_output "[*] Identify Qemu Image device for ${ORANGE}${LOG_PATH_MODULE}/${lIMAGE_NAME}${NC}"
  local lCNT=0
  while [[ "${lDEVICE:-NA}" == "NA" ]]; do
    lDEVICE="$(add_partition_emulation "${LOG_PATH_MODULE}/${lIMAGE_NAME}")"
    lCNT=$((lCNT+1))
    if [[ "${lDEVICE:-NA}" == "NA" ]] && [[ "${lCNT}" -gt 10 ]]; then
      print_output "[-] No Qemu Image device identified - return from ${FUNCNAME[0]}"
      return
    fi
    sleep 5
  done
  sleep 1
  print_output "[*] Device mapper created at ${ORANGE}${lDEVICE}${NC}"
  print_output "[*] Mounting QEMU Image Partition 1 to ${ORANGE}${MNT_POINT}${NC}"
  mount "${lDEVICE}" "${MNT_POINT}" || true
  if mount | grep -q "${MNT_POINT}"; then
    print_output "[*] Setting network configuration in target filesystem:"
    print_output "$(indent "Network interface: ${ORANGE}${lETH_INT}${NC}")"
    print_output "$(indent "Network mode: ${ORANGE}${lNETWORK_MODE}${NC}")"
    print_output "$(indent "Bridge interface: ${ORANGE}${lNETWORK_DEVICE}${NC}")"
    print_output "$(indent "IP address: ${ORANGE}${lIP_ADDRESS}${NC}")"

    set_network_config "${lIP_ADDRESS}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${lETH_INT}"

    # if there were missing files found -> we try to fix this now
    if [[ -v MISSING_FILES[@] ]]; then
      mapfile -t MISSING_FILES < <(printf "%s\n" "${MISSING_FILES[@]}" | sort -u)

      for lFILE_PATH_MISSING in "${MISSING_FILES[@]}"; do
        lFILE_PATH_MISSING="${lFILE_PATH_MISSING//[![:print:]]/}"
        print_output "[*] Checking for missing area ${ORANGE}${lFILE_PATH_MISSING}${NC} in filesystem ..."
        [[ "${lFILE_PATH_MISSING}" == *"firmadyne"* ]] && continue
        [[ "${lFILE_PATH_MISSING}" == *"/proc/"* ]] && continue
        [[ "${lFILE_PATH_MISSING}" == *"/sys/"* ]] && continue
        [[ "${lFILE_PATH_MISSING}" == *"/dev/"* ]] && continue
        [[ "${lFILE_PATH_MISSING}" == *"reboot"* ]] && continue
        # ugly false positive cleanup
        [[ "${lFILE_PATH_MISSING}" == *"EMBA_"* ]] && continue

        lFILENAME_MISSING=$(basename "${lFILE_PATH_MISSING}")
        # ensure the found path is nothing with a '*' in it:
        [[ "${lFILENAME_MISSING}" =~ \* ]] && continue
        print_output "[*] Found missing area ${ORANGE}${lFILE_PATH_MISSING}${NC} in filesystem ... trying to fix this now"
        lDIR_NAME_MISSING=$(dirname "${lFILE_PATH_MISSING}")
        if ! [[ -d "${MNT_POINT}/${lDIR_NAME_MISSING#/}" ]]; then
          print_output "[*] Create missing directory ${ORANGE}/${lDIR_NAME_MISSING#/}${NC} in filesystem ... trying to fix this now"
          mkdir -p "${MNT_POINT}/${lDIR_NAME_MISSING#/}" 2>/dev/null || true
        fi
        lFOUND_MISSING=$(find "${MNT_POINT}" -type f -name "${lFILENAME_MISSING}" | head -1 || true)
        if [[ -f ${lFOUND_MISSING} ]] && ! [[ -f "${MNT_POINT}/${lDIR_NAME_MISSING#/}/${lFILENAME_MISSING}" ]]; then
          print_output "[*] Recover missing file ${ORANGE}${lFILENAME_MISSING}${NC} in filesystem (${ORANGE}${MNT_POINT}/${lDIR_NAME_MISSING#/}/${lFILENAME_MISSING}${NC}) ... trying to fix this now"
          cp --update=none "${lFOUND_MISSING}" "${MNT_POINT}/${lDIR_NAME_MISSING#/}"/ || true
        fi
      done
    fi

    # as we have the filesytem mounted right before the final run we can link libnvram now
    link_libnvram_so "${MNT_POINT}" "dbg"

    # if we have a /tmp/EMBA_config_state from a previous emulation run we need to remove it
    # before the next emulation testrun
    # This file is an indiator that the initial network config was done and we can start checking
    # the network config during emulation
    rm "${MNT_POINT}"/tmp/EMBA_config_state 2>/dev/null || true

    # umount filesystem:
    umount_qemu_image "${lDEVICE}"
    delete_device_entry "${lIMAGE_NAME}" "${lDEVICE}" "${MNT_POINT}"
  fi
}

nvram_check() {
  local lIMAGE_NAME="${1:-}"
  local lMAX_THREADS_NVRAM=$((4*"$(nproc || echo 1)"))
  local lDEVICE=""
  local lWAIT_PIDS_AE=()
  local lCURRENT_DIR=""
  local lNVRAM_FILE_LIST=()
  local lNVRAM_FILE=""

  # mount filesystem again for network config:
  print_output "[*] Identify Qemu Image device for ${ORANGE}${LOG_PATH_MODULE}/${lIMAGE_NAME}${NC}"
  local lCNT=0
  while [[ "${lDEVICE:-NA}" == "NA" ]]; do
    lDEVICE="$(add_partition_emulation "${LOG_PATH_MODULE}/${lIMAGE_NAME}")"
    lCNT=$((lCNT+1))
    if [[ "${lDEVICE:-NA}" == "NA" ]] && [[ "${lCNT}" -gt 10 ]]; then
      print_output "[-] No Qemu Image device identified - return from ${FUNCNAME[0]}"
      return
    fi
    sleep 5
  done

  print_output "[*] Device mapper created at ${ORANGE}${lDEVICE}${NC}"
  print_output "[*] Mounting QEMU Image Partition 1 to ${ORANGE}${MNT_POINT}${NC}"
  mount "${lDEVICE}" "${MNT_POINT}" || true

  if mount | grep -q "${MNT_POINT}"; then
    # we check for NVRAM access. Threshold value is a random 5
    if [[ -v NVRAMS[@] ]] && [[ "${#NVRAMS[@]}" -gt 5 ]]; then
      print_output "[*] NVRAM access detected ${ORANGE}${#NVRAMS[@]}${NC} times. Testing NVRAM access now."
      lCURRENT_DIR=$(pwd)
      cd "${MNT_POINT}" || exit
      # generate a file list of the firmware
      mapfile -t lNVRAM_FILE_LIST < <(find . -xdev -type f -not -path "*/firmadyne*" -exec file {} \; | grep "ASCII text" || true)

      if ! [[ -d "${LOG_PATH_MODULE}"/nvram ]]; then
        mkdir "${LOG_PATH_MODULE}"/nvram
      fi

      # need to check for firmadyne string in path
      for lNVRAM_FILE in "${lNVRAM_FILE_LIST[@]}"; do
        nvram_searcher_emulation "${lNVRAM_FILE/:*}" &
        lWAIT_PIDS_AE+=( "$!" )
        max_pids_protection "${lMAX_THREADS_NVRAM}" lWAIT_PIDS_AE
      done
      wait_for_pid "${lWAIT_PIDS_AE[@]}"
      cd "${lCURRENT_DIR}" || exit
    fi

    if [[ -f "${LOG_PATH_MODULE}"/nvram/nvram_files_final ]]; then
      if [[ "$(wc -l < "${LOG_PATH_MODULE}"/nvram/nvram_files_final)" -gt 0 ]]; then
        # print_output "[*] Identified the following NVRAM files:"
        # tee -a "${LOG_FILE}" < "${LOG_PATH_MODULE}"/nvram/nvram_files_final

        sort -u -r -h -k2 "${LOG_PATH_MODULE}"/nvram/nvram_files_final | sort -u -k1,1 | sort -r -h -k2 | head -10 > "${MNT_POINT}"/firmadyne/nvram_files || true
        # store a copy in the log dir
        cp "${MNT_POINT}"/firmadyne/nvram_files "${LOG_PATH_MODULE}"/nvram/nvram_files_final_ || true

        print_ln
        print_output "[*] Setting up ${ORANGE}nvram_files${NC} in target filesystem:"
        tee -a "${LOG_FILE}" < "${LOG_PATH_MODULE}"/nvram/nvram_files_final_
      fi
    fi
  fi

  # umount filesystem:
  umount_qemu_image "${lDEVICE}"
  delete_device_entry "${lIMAGE_NAME}" "${lDEVICE}" "${MNT_POINT}"
}

nvram_searcher_emulation() {
  local lNVRAM_FILE="${1:-}"

  # lets store it in tmp var for supporting binary files in the future
  local lNVRAM_FILE_TMP="${lNVRAM_FILE}"
  local lMAX_VALUES=""
  local lCOUNT=0

  if [[ "${#NVRAMS[@]}" -gt 1000 ]]; then
    lMAX_VALUES=1000
  else
    lMAX_VALUES="${#NVRAMS[@]}"
  fi

  for (( j=0; j<"${lMAX_VALUES}"; j++ )); do
    lNVRAM_ENTRY="${NVRAMS[${j}]}"
    lNVRAM_KEY=""
    # check https://github.com/pr0v3rbs/FirmAE/blob/master/scripts/inferDefault.py
    echo "${lNVRAM_ENTRY}" >> "${LOG_PATH_MODULE}"/nvram/nvram_keys.tmp
    lNVRAM_KEY=$(echo "${lNVRAM_ENTRY}" | tr -s '[:blank:]')
    lNVRAM_KEY="${lNVRAM_KEY//[![:print:]]/}"
    if [[ "${lNVRAM_KEY}" =~ [a-zA-Z0-9_] && "${#lNVRAM_KEY}" -gt 3 ]]; then
      # print_output "[*] NVRAM access detected: $ORANGE$NVRAM_KEY$NC"
      if grep -q "${lNVRAM_KEY}" "${lNVRAM_FILE_TMP}" 2>/dev/null; then
        # print_output "[*] Possible NVRAM access via key ${ORANGE}${lNVRAM_KEY}${NC} found in NVRAM file ${ORANGE}${lNVRAM_FILE}${NC}."
        lCOUNT=$((lCOUNT + 1))
      fi
      echo "${lNVRAM_KEY}" >> "${LOG_PATH_MODULE}"/nvram/nvram_keys.log
    fi
  done

  if [[ "${lCOUNT}" -gt 5 ]]; then
    print_output "[*] ${lNVRAM_FILE/\.} ${lCOUNT} ASCII_text"
    echo "${lNVRAM_FILE/\.} ${lCOUNT} ASCII_text" >> "${LOG_PATH_MODULE}"/nvram/nvram_files_final
  fi
}

run_emulated_system() {
  local lIP_ADDRESS="${1:-}"
  local lIMAGE_NAME="${2:-}"
  local lINIT_FILE="${3:-}"
  local lARCH_END="${4:-}"

  sub_module_title "Final system emulation for ${lIP_ADDRESS} - ${lINIT_FILE} - ${KINIT} - ${lARCH_END} - ${lIMAGE_NAME}"

  local IMAGE="${LOG_PATH_MODULE}/${lIMAGE_NAME}"

  export KERNEL_V=".4"
  get_kernel_version
  if [[ -n "${KERNEL_V:-}" ]]; then
    print_output "[*] Kernel ${KERNEL_V}.x detected -> Using Kernel v4.x"
    # KERNEL_V=".$KERNEL_V"
    KERNEL_V=".4"
  fi

  local lNET_NUM=0
  local lNET_ID=0
  local lCPU=""
  local lKERNEL=""
  local lQEMU_BIN=""
  local lQEMU_MACHINE=""
  local lQEMU_DISK=""
  local lQEMU_PARAMS=""
  local lQEMU_NETWORK=""
  local lQEMU_ROOTFS=""
  local lCONSOLE="ttyS0"
  local lQEMU_NET_DEVICE=""

  if [[ "${lARCH_END}" == "mipsel" ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
    lQEMU_BIN="qemu-system-${lARCH_END}"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mips64r2el" ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
    lQEMU_BIN="qemu-system-${lARCH_END}"
    lCPU="-cpu MIPS64R2-generic"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mipseb" ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
    lQEMU_BIN="qemu-system-mips"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mips64r2eb" ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
    lQEMU_BIN="qemu-system-mips64"
    lCPU="-cpu MIPS64R2-generic"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mips64v1eb" ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
    lQEMU_BIN="qemu-system-mips64"
    # lCPU="-cpu MIPS64R2-generic"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mips64v1el" ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
    lQEMU_BIN="qemu-system-mips64el"
    # lCPU="-cpu MIPS64R2-generic"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "mips64n32eb" ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
    lQEMU_BIN="qemu-system-mips64"
    lCPU="-cpu MIPS64R2-generic"
    lQEMU_MACHINE="malta"
  elif [[ "${lARCH_END}" == "armel"* ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/zImage.${lARCH_END}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/zImage.${lARCH_END}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
    lQEMU_BIN="qemu-system-arm"
    lQEMU_MACHINE="virt"
  elif [[ "${lARCH_END}" == "arm64el"* ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/Image.${lARCH_END}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/Image.${lARCH_END}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
    lQEMU_BIN="qemu-system-aarch64"
    # lCONSOLE="ttyAMA0"
    lCPU="-cpu cortex-a57"
    lQEMU_MACHINE="virt"
  elif [[ "${lARCH_END}" == "x86el"* ]]; then
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/bzImage.${lARCH_END}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/bzImage.${lARCH_END}"
    else
      print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
      return
    fi
    lQEMU_BIN="qemu-system-x86_64"
    lQEMU_MACHINE="pc-i440fx-8.2"
  elif [[ "${lARCH_END}" == "nios2el" ]]; then
    # not implemented -> Future
    if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}" ]]; then
      lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}"
    else
      lKERNEL="${BINARY_DIR}/vmlinux.${lARCH_END}"
    fi
    lQEMU_BIN="qemu-system-nios2"
    lQEMU_MACHINE="10m50-ghrd"
  else
    lQEMU_BIN="NA"
  fi

  if [[ "${ARCH}" == "ARM"* ]]; then
    lQEMU_DISK="-drive if=none,file=${IMAGE},format=raw,id=rootfs -device virtio-blk-device,drive=rootfs"
    lQEMU_PARAMS="-audiodev driver=none,id=none"
    lQEMU_ROOTFS="/dev/vda1"
    # newer kernels use virtio only
    lQEMU_NET_DEVICE="virtio-net-device"
  elif [[ "${ARCH}" == "NIOS2" ]]; then
    lQEMU_PARAMS="-monitor none"
    lQEMU_DISK="-drive file=${IMAGE},format=raw"
    lQEMU_NET_DEVICE="virtio-net-device"
  elif [[ "${ARCH}" == "MIPS" ]] || [[ "${lARCH_END}" == "x86el" ]] || [[ "${lARCH_END}" == "mips64"* ]]; then
    lQEMU_DISK="-drive if=ide,format=raw,file=${IMAGE}"
    lQEMU_PARAMS=""
    lQEMU_ROOTFS="/dev/sda1"
    lQEMU_NET_DEVICE="e1000"
  fi

  if [[ "${ARCH}" == "MIPS" ]] || [[ "${lARCH_END}" == "x86el" ]] || [[ "${lARCH_END}" == "mips64"* ]] || [[ "${ARCH}" == "ARM"* ]]; then
    if [[ -n "${ETH_NUM}" ]]; then
      # if we found an eth interface we use this
      lNET_NUM="${ETH_NUM}"
    elif [[ -n "${BR_NUM}" ]]; then
      # if we found no eth interface but a br interface we use this
      lNET_NUM="${BR_NUM}"
    else
      # fallback - we connect id 0
      lNET_NUM=0
    fi
    if [[ "${lNET_NUM}" -gt 5 ]]; then
      print_output "[*] NET_NUM ${lNET_NUM} issues -> setting default NET_NUM to 0"
      lNET_NUM=0
    fi

    # 6 Interfaces -> 0-5
    for lNET_ID in {0..5}; do
      print_output "[*] Network ID ${lNET_ID} connector / lNET_NUM: ${lNET_NUM}"
      if [[ "${lNET_ID}" == "${lNET_NUM}" ]];then
        # if MATCH in IPS_INT -> connect this interface to host
        print_output "[*] Connect interface: ${ORANGE}${lNET_ID}${NC} to host"
        lQEMU_NETWORK+=" -device ${lQEMU_NET_DEVICE},netdev=net${lNET_ID}"
        lQEMU_NETWORK+=" -netdev tap,id=net${lNET_ID},ifname=${TAPDEV_0},script=no"
      else
        # only 0-3 are handled via placeholder interfaces
        if [[ "${lNET_ID}" -gt 3 ]]; then
          print_output "[*] Network ID ${lNET_ID} bypass"
          continue
        fi
        # on ARM we have currently only one interface and we need to connect this to the host
        # This means we do not place placeholder interfaces for ARM architecture
        if [[ "${ARCH}" != "ARM"* ]]; then
          print_output "[*] Create socket placeholder interface: ${ORANGE}${lNET_ID}${NC}"
          # place a socket connection placeholder:
          lQEMU_NETWORK+=" -device ${lQEMU_NET_DEVICE},netdev=net${lNET_ID}"
          lQEMU_NETWORK+=" -netdev socket,id=net${lNET_ID},listen=:200${lNET_ID}"
        fi
      fi
    done
  fi

  if [[ -z "${lQEMU_NETWORK}" ]]; then
    print_output "[!] No network interface config created ... creating backup configuration"
    lNET_ID=0
    print_output "[*] Connect interface: ${ORANGE}${lNET_ID}${NC} to host"
    lQEMU_NETWORK+=" -device ${lQEMU_NET_DEVICE},netdev=net${lNET_ID}"
    lQEMU_NETWORK+=" -netdev tap,id=net${lNET_ID},ifname=${TAPDEV_0},script=no"
  fi

  # dirty workaround to fill the KERNEL which is used later on
  export KERNEL="${lKERNEL}"

  if [[ "${lQEMU_BIN}" != "NA" ]]; then
    run_qemu_final_emulation "${lCONSOLE}" "${lCPU}" "${lKERNEL}" "${lQEMU_BIN}" "${lQEMU_MACHINE}" "${lQEMU_DISK}" "${lQEMU_PARAMS}" "${lQEMU_NETWORK}" "${lQEMU_ROOTFS}" "${lIP_ADDRESS}" "${lIMAGE_NAME}" "${lINIT_FILE}" "${lARCH_END}" &
  else
    print_output "[-] No firmware emulation ${ORANGE}${ARCH}${NC} / ${ORANGE}${lIMAGE_NAME}${NC} possible"
  fi
}

run_qemu_final_emulation() {
  local lCONSOLE="${1:-}"
  local lCPU="${2:-}"
  local lKERNEL="${3:-}"
  local lQEMU_BIN="${4:-}"
  local lQEMU_MACHINE="${5:-}"
  local lQEMU_DISK="${6:-}"
  local lQEMU_PARAMS="${7:-}"
  local lQEMU_NETWORK="${8:-}"
  local lQEMU_ROOTFS="${9:-}"
  local lIP_ADDRESS="${10:-}"
  local lIMAGE_NAME="${11:-}"
  local lINIT_FILE="${12:-}"
  local lARCH_END="${13:-}"

  check_qemu_instance_l10

  print_output "[*] Qemu parameters used in run mode:"
  print_output "$(indent "MACHINE: ${ORANGE}${lQEMU_MACHINE}${NC}")"
  print_output "$(indent "KERNEL: ${ORANGE}${lKERNEL}${NC}")"
  print_output "$(indent "DISK: ${ORANGE}${lQEMU_DISK}${NC}")"
  print_output "$(indent "KINIT: ${ORANGE}${KINIT}${NC}")"
  print_output "$(indent "ROOT_DEV: ${ORANGE}${lQEMU_ROOTFS}${NC}")"
  print_output "$(indent "QEMU: ${ORANGE}${lQEMU_BIN}${NC}")"
  print_output "$(indent "NETWORK: ${ORANGE}${lQEMU_NETWORK}${NC}")"
  print_output "$(indent "Init file: ${ORANGE}${lINIT_FILE}${NC}")"
  print_output "$(indent "Console interface: ${ORANGE}${lCONSOLE}${NC}")"
  print_ln
  print_output "[*] Starting firmware emulation ${ORANGE}${lQEMU_BIN} / ${lARCH_END} / ${lIMAGE_NAME} / ${lIP_ADDRESS}${NC} ... use Ctrl-a + x to exit"
  print_ln

  write_script_exec "echo -e \"[*] Starting firmware emulation ${ORANGE}${lQEMU_BIN} / ${lARCH_END} / ${lIMAGE_NAME} / ${lIP_ADDRESS}${NC} ... use Ctrl-a + x to exit\n\"" "${ARCHIVE_PATH}"/run.sh 0
  write_script_exec "echo -e \"[*] For emulation state please monitor the ${ORANGE}qemu.serial.log${NC} file\n\"" "${ARCHIVE_PATH}"/run.sh 0
  write_script_exec "echo -e \"[*] For shell access check localhost port ${ORANGE}4321${NC} via telnet\n\"" "${ARCHIVE_PATH}"/run.sh 0

  date +%s > "${TMP_DIR}/emu_starter.log"
  write_script_exec "timeout --preserve-status --signal SIGINT 2000 ${lQEMU_BIN} -m 2048 -M ${lQEMU_MACHINE} ${lCPU} -kernel ${lKERNEL} ${lQEMU_DISK} -append \"root=${lQEMU_ROOTFS} console=${lCONSOLE} nandsim.parts=64,64,64,64,64,64,64,64,64,64 ${KINIT} rw debug ignore_loglevel print-fatal-signals=1 EMBA_NET=${EMBA_NET} EMBA_NVRAM=${EMBA_NVRAM} EMBA_KERNEL=${EMBA_KERNEL} EMBA_ETC=${EMBA_ETC} user_debug=0 firmadyne.syscall=1\" -nographic ${lQEMU_NETWORK} ${lQEMU_PARAMS} -serial file:${LOG_PATH_MODULE}/qemu.final.serial.log -serial telnet:localhost:4321,server,nowait -serial unix:/tmp/qemu.${lIMAGE_NAME}.S1,server,nowait -monitor unix:/tmp/qemu.${lIMAGE_NAME},server,nowait ; pkill -9 -f tail.*-F.*\"${LOG_PATH_MODULE}\"" "${ARCHIVE_PATH}"/run.sh 1
}

get_emu_runtime() {
  local lEMU_START_DATE=""
  local lCURRENT_DATE=""
  local lRUN_TIME=""

  if [[ -f "${TMP_DIR}/emu_starter.log" ]]; then
    lEMU_START_DATE=$(cat "${TMP_DIR}/emu_starter.log")
    lCURRENT_DATE="$(date +%s)"
    lRUN_TIME=$((lCURRENT_DATE-lEMU_START_DATE))
  else
    lRUN_TIME="NA"
  fi
  echo "${lRUN_TIME}"
}

check_online_stat() {
  local lIPS_INT_VLAN_CFG="${1:-}"
  local lIMAGE_NAME="${3:-}"

  local lIP_ADDRESS=""
  lIP_ADDRESS=$(echo "${lIPS_INT_VLAN_CFG}" | cut -d\; -f2)

  local lNMAP_LOG="nmap_emba_${lIPS_INT_VLAN_CFG//\;/-}.txt"

  local lPING_CNT=0
  local lSYS_ONLINE=0
  local lTCP_SERV_NETSTAT_ARR=()
  local lUDP_SERV_NETSTAT_ARR=()
  local lNMAP_SERV_UDP_ARR=()
  local lNMAP_SERV_TCP_ARR=()

  # wait 20 secs after boot before starting pinging
  sleep 20

  # lMAX_PING_CNT is a backup to get out in case something goes weird
  local lMAX_PING_CNT=240
  local lMAX_RUN_TIME=900
  local lRUN_TIME=""
  lRUN_TIME=$(get_emu_runtime)
  # we write the results to a tmp file. This is needed to only have the results of the current emulation round
  # for further processing available
  # we try pinging the system for 10mins with 5 secs sleeptime in between
  # if the system is reachable we go ahead
  while [[ "${lRUN_TIME}" -lt "${lMAX_RUN_TIME}" && "${lSYS_ONLINE}" -eq 0 ]]; do
    # lets use the default ping command first
    if ping -c 1 "${lIP_ADDRESS}" &> /dev/null; then
      print_output "[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable via ICMP."
      ping -c 1 "${lIP_ADDRESS}" | tee -a "${LOG_FILE}" || true
      print_ln
      write_log "${GREEN}[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable via ICMP." "${TMP_DIR}"/online_stats.tmp
      lSYS_ONLINE=1
    fi

    # we check for alternative ip addresses found in our Qemu logs
    # Usually these are extracted from the output of ifconfig in qemu logs
    # we check for these ip addresses via ping/hping and if such an IP address is working
    # we can use this address for further analysis
    if [[ "${lSYS_ONLINE}" -ne 1 ]]; then
      local lIP_ADDRESS_TMP_ARR=()
      mapfile -t lIP_ADDRESS_TMP_ARR < <(grep -a -o -E "inet addr:[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" "${LOG_PATH_MODULE}/qemu.final.serial.log" \
        | grep -v "127.0.0." | grep -v "${lIP_ADDRESS}" | cut -d ':' -f2 | sort -u || true)
      for lIP_ADDRESS_TMP in "${lIP_ADDRESS_TMP_ARR[@]}"; do
        if [[ "${lIP_ADDRESS_TMP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
          print_output "[*] Testing for changed IP address ${lIP_ADDRESS_TMP}" "no_log"
          if ping -c 1 "${lIP_ADDRESS_TMP}" &> /dev/null; then
            print_output "[+] Host with changed ip address ${ORANGE}${lIP_ADDRESS_TMP}${GREEN} is reachable via ICMP."
            print_output "[*] Changing testing ip address to ${ORANGE}${lIP_ADDRESS_TMP}${NC}."
            ping -c 1 "${lIP_ADDRESS_TMP}" | tee -a "${LOG_FILE}" || true
            print_ln
            write_log "${GREEN}[+] Host with changed ip address ${ORANGE}${lIP_ADDRESS_TMP}${GREEN} is reachable via ICMP." "${TMP_DIR}"/online_stats.tmp
            lSYS_ONLINE=1
            lIP_ADDRESS="${lIP_ADDRESS_TMP}"
            # let us store the information of a changed ip address for later
            write_log "${lIP_ADDRESS}" "${TMP_DIR}/emulation_changed_ip_address.tmp"
            break
          fi
          if [[ "$(hping3 -n -c 1 "${lIP_ADDRESS_TMP}" 2>/dev/null | grep -c "^len=")" -gt 0 ]]; then
            print_output "[+] Host with changed ip address ${ORANGE}${lIP_ADDRESS_TMP}${GREEN} is reachable via hping."
            print_output "[!] NOT further handled"
          fi
        fi
      done
    fi

    # and as second check we can use hping
    if [[ "$(hping3 -n -c 1 "${lIP_ADDRESS}" 2>/dev/null | grep -c "^len=")" -gt 0 ]]; then
      print_output "[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable on TCP port 0 via hping."
      hping3 -n -c 1 "${lIP_ADDRESS}" | tee -a "${LOG_FILE}" || true
      print_ln
      if [[ "${lSYS_ONLINE}" -ne 1 ]]; then
        if ping -c 1 "${lIP_ADDRESS}" &> /dev/null; then
          print_output "[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable via ICMP."
          ping -c 1 "${lIP_ADDRESS}" | tee -a "${LOG_FILE}" || true
          print_ln
          write_log "${GREEN}[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable via ICMP." "${TMP_DIR}"/online_stats.tmp
        fi
      fi
      print_ln
      write_log "${GREEN}[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable on TCP port 0 via hping." "${TMP_DIR}"/online_stats.tmp
      lSYS_ONLINE=1
    fi

    lPING_CNT=$((lPING_CNT+1))
    if [[ "${lSYS_ONLINE}" -eq 0 ]]; then
      print_output "[*] Host with ${ORANGE}${lIP_ADDRESS}${NC} is not reachable for ${lPING_CNT} time(s) - runtime $(date -ud@"${lRUN_TIME}" +%H:%M:%S)." "no_log"
      lSYS_ONLINE=0
      sleep 5
    fi
    if [[ "${lPING_CNT}" -gt "${lMAX_PING_CNT}" ]]; then
      print_output "[!] Max ping count reached after runtime $(date -ud@"${lRUN_TIME}" +%H:%M:%S) - proceeding now"
      break
    fi
    lRUN_TIME=$(get_emu_runtime)
  done

  # looks as we can ping the system. Now, we wait some time before doing our Nmap portscan
  if [[ "${lSYS_ONLINE}" -ne 1 ]]; then
    print_output "[*] Host with ${ORANGE}${lIP_ADDRESS}${NC} is not reachable."
  else
    print_output "[*] Give the system another 30 seconds to ensure the boot process is finished.\n" "no_log"
    sleep 30
    print_output "[*] Default Nmap portscan for ${ORANGE}${lIP_ADDRESS}${NC}"
    # write_link "${ARCHIVE_PATH}"/"${lNMAP_LOG}"
    print_ln

    # this is just for the logfile
    if ! ping -c 1 "${lIP_ADDRESS}" | tee -a "${LOG_FILE}"; then
      print_output "[-] Warning: System was already available but it does not respond to ping anymore."
      print_output "[-] Probably the IP address of the system has changed."
      local lIP_ADDRESS_TMP_ARR=()
      mapfile -t lIP_ADDRESS_TMP_ARR < <(grep -a -o -E "inet addr:[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" "${LOG_PATH_MODULE}/qemu.final.serial.log" \
        | grep -v "127.0.0." | grep -v "${lIP_ADDRESS}" | cut -d ':' -f2 | sort -u || true)
      for lIP_ADDRESS_TMP in "${lIP_ADDRESS_TMP_ARR[@]}"; do
        if [[ "${lIP_ADDRESS_TMP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
          print_output "[*] Testing for changed IP address ${lIP_ADDRESS_TMP}"
          if ping -c 1 "${lIP_ADDRESS_TMP}" &> /dev/null; then
            print_output "[*] System available via changed IP address ${lIP_ADDRESS_TMP}"
          fi
        fi
      done
    fi

    print_ln
    local lCNT=1
    local lMAX_NMAP_RETRIES=15
    nmap -Pn -n -A -sSV --host-timeout 10m -oA "${ARCHIVE_PATH}/${lCNT}_$(basename "${lNMAP_LOG}")" "${lIP_ADDRESS}" | tee -a "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}" || true
    if grep -q "open" "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}"; then
      tee -a "${LOG_FILE}" < "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}"
    fi

    lMAX_NMAP_RETRIES=40
    lRUN_TIME=$(get_emu_runtime)
    # at the end we are primarly interested in TCP based network services. This means we stop after reaching
    # our MIN_TCP_SERV threshold
    while [[ "$(grep -c "\/tcp.*open\ " "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}")" -lt "${MIN_TCP_SERV}" ]]; do
      # just to ensure we also detect udp services we can check them here and print a nice message that we have something:
      if [[ "$(grep -c "udp.*open\ \|/tcp.*open\ " "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}")" -gt 0 ]]; then
        print_ln
        print_output "[+] Already dedected running network services via Nmap ... further detection active - CNT: ${lCNT}"
        grep -c "/udp.*open\ \|/tcp.*open\ " "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}" >> "${LOG_FILE}"
        write_link "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}"
        print_ln
      fi
      lCNT=$((lCNT+1))
      print_output "[*] Give the system another 60 seconds to ensure the boot process is finished - ${lCNT}/${lMAX_NMAP_RETRIES}.\n" "no_log"
      sleep 60
      # we store our Nmap logs in dedicated files (${lCNT}_nmap_log_file):
      nmap -Pn -n -A -sSV --host-timeout 10m -oA "${ARCHIVE_PATH}/${lCNT}_$(basename "${lNMAP_LOG}")" "${lIP_ADDRESS}" | tee -a "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}" || true
      # ensure we have the last results also in our main Nmap log file:
      # cp "${ARCHIVE_PATH}"/"${lCNT}_${lNMAP_LOG}" "${ARCHIVE_PATH}"/"${lNMAP_LOG}"
      if grep -q "/open\ " "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}"; then
        tee -a "${LOG_FILE}" < "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}"
      fi
      # lMAX_NMAP_RETRIES is as backup to exit somehow from this loop
      [[ "${lCNT}" -ge "${lMAX_NMAP_RETRIES}" ]] && break

      # runtime checks is the prefered way to exit now
      lRUN_TIME=$(get_emu_runtime)
      if [[ "${lRUN_TIME}" -gt "${lMAX_RUN_TIME}" ]]; then
        break
      fi
    done
    # get a backup of our current results and add the later nmap scans to this file for the web report
    cp "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}" "${ARCHIVE_PATH}/${lNMAP_LOG}"

    mapfile -t lTCP_SERV_NETSTAT_ARR < <(grep -a "^tcp.*LISTEN" "${LOG_PATH_MODULE}"/qemu*.log | grep -v "127.0.0.1" | awk '{print $4}' | rev | cut -d: -f1 | rev | sort -u || true)
    mapfile -t lUDP_SERV_NETSTAT_ARR < <(grep -a "^udp.*" "${LOG_PATH_MODULE}"/qemu*.log | grep -v "127.0.0.1" | awk '{print $4}' | rev | cut -d: -f1 | rev | sort -u || true)
    # check the already created nmap log for open services to include these services in the final scan
    mapfile -t lNMAP_SERV_TCP_ARR < <(grep -o -E "[0-9]+/open/tcp" "${ARCHIVE_PATH}/${lNMAP_LOG}" | cut -d '/' -f1 | sort -u || true)
    mapfile -t lNMAP_SERV_UDP_ARR < <(grep -o -E "[0-9]+/open/udp" "${ARCHIVE_PATH}/${lNMAP_LOG}" | cut -d '/' -f1 | sort -u || true)

    if [[ "${#SERVICES_STARTUP[@]}" -gt 0 ]] || [[ "${#lTCP_SERV_NETSTAT_ARR[@]}" -gt 0 ]] || \
      [[ "${#lUDP_SERV_NETSTAT_ARR[@]}" -gt 0 ]] || [[ "${#lNMAP_SERV_TCP_ARR[@]}" -gt 0 ]] || \
      [[ "${#lNMAP_SERV_UDP_ARR[@]}" -gt 0 ]]; then
      local lUDP_SERV_NETSTAT=""
      local lUDP_SERV_STARTUP=""
      local lUDP_SERV=""
      local lTCP_SERV_NETSTAT=""
      local lTCP_SERV_STARTUP=""
      local lTCP_SERV=""
      local lTCP_SERV_ARR=()
      local lUDP_SERV_ARR=()
      local lPORTS_TO_SCAN=""

      # write all services into a one liner for output:
      print_ln
      shopt -s extglob
      # rewrite our array into a nice string for printing it
      if [[ "${#TCP_SERVICES_STARTUP[@]}" -gt 0 ]]; then
        printf -v lTCP_SERV "%s " "${TCP_SERVICES_STARTUP[@]}"
        # # replace \n and ' ' with ,
        lTCP_SERV_STARTUP=${lTCP_SERV//+([$'\n'\ ])/,}
        [[ "${lTCP_SERV_STARTUP}" != "," ]] && print_output "[*] TCP Services detected via startup: ${ORANGE}${lTCP_SERV_STARTUP}${NC}"
      fi
      # rewrite our array into a nice string for printing it
      if [[ "${#UDP_SERVICES_STARTUP[@]}" -gt 0 ]]; then
        printf -v lUDP_SERV "%s " "${UDP_SERVICES_STARTUP[@]}"
        lUDP_SERV_STARTUP=${lUDP_SERV//+([$'\n'\ ])/,}
        [[ "${lUDP_SERV_STARTUP}" != "," ]] && print_output "[*] UDP Services detected via startup: ${ORANGE}${lUDP_SERV_STARTUP}${NC}"
      fi

      # rewrite our array into a nice string for printing it
      if [[ "${#lTCP_SERV_NETSTAT_ARR[@]}" -gt 0 ]]; then
        printf -v lTCP_SERV "%s " "${lTCP_SERV_NETSTAT_ARR[@]}"
        lTCP_SERV_NETSTAT=${lTCP_SERV//+([$'\n'\ ])/,}
        [[ "${lTCP_SERV_NETSTAT}" != "," ]] && print_output "[*] TCP Services detected via netstat: ${ORANGE}${lTCP_SERV_NETSTAT}${NC}"
      fi
      # rewrite our array into a nice string for printing it
      if [[ "${#lUDP_SERV_NETSTAT_ARR[@]}" -gt 0 ]]; then
        printf -v lUDP_SERV "%s " "${lUDP_SERV_NETSTAT_ARR[@]}"
        lUDP_SERV_NETSTAT=${lUDP_SERV//+([$'\n'\ ])/,}
        [[ "${lUDP_SERV_NETSTAT}" != "," ]] && print_output "[*] UDP Services detected via netstat: ${ORANGE}${lUDP_SERV_NETSTAT}${NC}"
      fi
      if [[ "${#lNMAP_SERV_TCP_ARR[@]}" -gt 0 ]]; then
        printf -v lTCP_SERV "%s " "${lNMAP_SERV_TCP_ARR[@]}"
        lTCP_SERV_NMAP=${lTCP_SERV//+([$'\n'\ ])/,}
        [[ "${lTCP_SERV_NMAP}" != "," ]] && print_output "[*] TCP Services detected via Nmap: ${ORANGE}${lTCP_SERV_NMAP}${NC}"
      fi
      if [[ "${#lNMAP_SERV_UDP_ARR[@]}" -gt 0 ]]; then
        printf -v lUDP_SERV "%s " "${lNMAP_SERV_UDP_ARR[@]}"
        lUDP_SERV_NMAP=${lUDP_SERV//+([$'\n'\ ])/,}
        [[ "${lUDP_SERV_NMAP}" != "," ]] && print_output "[*] UDP Services detected via Nmap: ${ORANGE}${lUDP_SERV_NMAP}${NC}"
      fi

      print_ln

      # work with this:
      lUDP_SERV_ARR=( "${UDP_SERVICES_STARTUP[@]}" "${lUDP_SERV_NETSTAT_ARR[@]}" "${#lNMAP_SERV_UDP_ARR[@]}")
      lTCP_SERV_ARR=( "${TCP_SERVICES_STARTUP[@]}" "${lTCP_SERV_NETSTAT_ARR[@]}" "${#lNMAP_SERV_TCP_ARR[@]}")
      # we add some default services that we always check in our final Nmap scan
      lTCP_SERV_ARR+=(21)
      lTCP_SERV_ARR+=(22)
      lTCP_SERV_ARR+=(80)
      lTCP_SERV_ARR+=(443)
      lTCP_SERV_ARR+=(8080)

      mapfile -t lTCP_SERV_ARR < <(printf "%s\n" "${lTCP_SERV_ARR[@]}" | sort -u)
      mapfile -t lUDP_SERV_ARR < <(printf "%s\n" "${lUDP_SERV_ARR[@]}" | sort -u)
      if [[ "${#lTCP_SERV_ARR[@]}" -gt 0 ]]; then
        printf -v lTCP_SERV "%s " "${lTCP_SERV_ARR[@]}"
        lTCP_SERV="${lTCP_SERV//+([$'\n'\ ])/,}"
        # print_output "[*] TCP Services detected: ${ORANGE}${lTCP_SERV}${NC}"
      fi
      if [[ "${#lUDP_SERV_ARR[@]}" -gt 0 ]]; then
        printf -v lUDP_SERV "%s " "${lUDP_SERV_ARR[@]}"
        lUDP_SERV="${lUDP_SERV//+([$'\n'\ ])/,}"
        # print_output "[*] UDP Services detected: ${ORANGE}${lUDP_SERV}${NC}"
      fi

      lUDP_SERV="U:${lUDP_SERV#,}"
      lTCP_SERV="T:${lTCP_SERV#,}"
      # remove the last ',' ... 123,234,345, -> 123,234,345
      lTCP_SERV="${lTCP_SERV%,}"
      lUDP_SERV="${lUDP_SERV%,}"
      shopt -u extglob

      if [[ "${lTCP_SERV}" =~ ^T:[0-9].* ]]; then
        print_output "[*] Checking TCP services ${ORANGE}${lTCP_SERV}${NC}"
        lPORTS_TO_SCAN="${lTCP_SERV}"
      fi
      if [[ "${lUDP_SERV}" =~ ^U:[0-9].* ]]; then
        print_output "[*] Checking UDP services ${ORANGE}${lUDP_SERV}${NC}"
        if [[ "${lPORTS_TO_SCAN}" =~ ^T:[0-9].* ]]; then
          lPORTS_TO_SCAN+=",${lUDP_SERV}"
        else
          lPORTS_TO_SCAN="${lUDP_SERV}"
        fi
      fi

      if [[ "${lTCP_SERV}" =~ ^T:[0-9].* ]] || [[ "${lUDP_SERV}" =~ ^U:[0-9].* ]]; then
        print_ln
        print_output "[*] Nmap portscan for network services (${ORANGE}${lPORTS_TO_SCAN}${NC}) started during system init on ${ORANGE}${lIP_ADDRESS}${NC}"
        # link is for the next Nmap results:
        write_link "${ARCHIVE_PATH}/${lNMAP_LOG}"
        print_ln
        nmap -Pn -n -sSUV --host-timeout 30m -p "${lPORTS_TO_SCAN}" -oA "${ARCHIVE_PATH}/nmap_emba_${lIPS_INT_VLAN_CFG//\;/-}"_dedicated "${lIP_ADDRESS}" | tee -a "${ARCHIVE_PATH}/${lNMAP_LOG}" "${LOG_FILE}" || true
      fi
    fi
  fi

  stopping_emulation_process "${lIMAGE_NAME}"
  cleanup_emulator "${lIMAGE_NAME}"

  color_qemu_log "${LOG_PATH_MODULE}/qemu.final.serial.log"

  pkill -9 -f "tail -F ${LOG_PATH_MODULE}/qemu.final.serial.log" || true &>/dev/null
}

stopping_emulation_process() {
  local lIMAGE_NAME="${1:-}"

  print_output "[*] Stopping emulation process" "no_log"
  pkill -9 -f "qemu-system-.*${lIMAGE_NAME}.*" &>/dev/null || true
  sleep 1
}

create_emulation_archive() {
  sub_module_title "Archive to re-run emulated environment"
  print_output "With the following archive it is possible to rebuild the created emulation environment fully automated."

  local lKERNEL="${1:-}"
  local lIMAGE="${2:-}"
  local lARCHIVE_PATH="${3:-}"
  local lIPS_INT_VLAN_CFG_mod="${4:-}"
  local lARCH_NAME=""
  local lDEVICE="NA"

  if [[ "${FINAL_FW_RM}" -ne 1 ]]; then
    # we only copy the kernel and the firmware image to the archive if FINAL_FW_RM is not set
    cp "${lKERNEL}" "${lARCHIVE_PATH}" || print_error "[-] Error in kernel copy procedure"

    # we need to ensure that the EMBA_config_state file gets removed
    local lCNT=0
    while [[ "${lDEVICE:-NA}" == "NA" ]]; do
      lDEVICE="$(add_partition_emulation "${lIMAGE}")"
      lCNT=$((lCNT+1))
      if [[ "${lDEVICE:-NA}" == "NA" ]] && [[ "${lCNT}" -gt 10 ]]; then
        print_output "[-] No Qemu Image device identified - return now from ${FUNCNAME[0]}"
        return
      fi
      sleep 5
    done

    mount "${lDEVICE}" "${MNT_POINT}" || true
    rm "${MNT_POINT}"/tmp/EMBA_config_state 2>/dev/null || true
    umount_qemu_image "${lDEVICE}"
    delete_device_entry "$(basename "${lIMAGE}")" "${lDEVICE}" "${MNT_POINT}"

    cp "${lIMAGE}" "${lARCHIVE_PATH}" || print_error "[-] Error in image copy procedure"
  fi

  if [[ -f "${LOG_PATH_MODULE}"/"${NMAP_LOG}" ]]; then
    mv "${LOG_PATH_MODULE}"/"${NMAP_LOG}" "${lARCHIVE_PATH}" || print_error "[-] Error in Nmap results copy procedure"
    mv "${LOG_PATH_MODULE}"/nmap_emba_"${lIPS_INT_VLAN_CFG_mod}"* "${lARCHIVE_PATH}" || print_error "[-] Error in Nmap results copy procedure"
  fi

  echo "${lIPS_INT_VLAN_CFG_mod}" >> "${lARCHIVE_PATH}"/emulation_config.txt || true
  cat "${L10_SYS_EMU_RESULTS}" >> "${lARCHIVE_PATH}"/emulation_config.txt || true

  if [[ -v ARCHIVE_PATH ]] && [[ -f "${lARCHIVE_PATH}"/run.sh ]]; then
    chmod +x "${lARCHIVE_PATH}"/run.sh
    sed -i 's/-serial\ file:.*\/l10_system_emulation\/qemu\.final\.serial\.log/-serial\ file:\.\/qemu\.serial\.log/g' "${lARCHIVE_PATH}"/run.sh
    # fix the path for the kernel which is currently something like ./Linux-Kernel/vmlinux.mipsel.4
    # and should be ./vmlinux.mipsel.4
    local lL10_KERNEL_V_LONG_TMP="${L10_KERNEL_V_LONG}"
    if [[ "${lARCH_END}" == *"x86el"* ]] && [[ "${L10_KERNEL_V_LONG}" == "4.1.52" ]]; then
      # for x86el we currently have kernel issues
      lL10_KERNEL_V_LONG_TMP="4.1.17"
    fi
    sed -i "s/\.\/Linux-Kernel-v${lL10_KERNEL_V_LONG_TMP}\//\.\//g" "${lARCHIVE_PATH}"/run.sh

    if [[ "${FINAL_FW_RM}" -ne 1 ]]; then
      # create archive
      lARCH_NAME="$(basename "${lARCHIVE_PATH}")".tar.gz
      tar -czvf "${LOG_PATH_MODULE}"/"${lARCH_NAME}" "${lARCHIVE_PATH}"
      if [[ -f "${LOG_PATH_MODULE}"/"${lARCH_NAME}" ]]; then
        print_ln
        print_output "[*] Qemu emulation archive created in log directory: ${ORANGE}${lARCH_NAME}${NC}" "" "${LOG_PATH_MODULE}/${lARCH_NAME}"
        print_ln
      fi
    else
      print_output "[*] NO Qemu emulation archive created - FINAL_FW_RM was set or \'-r\' parameter was used."
    fi
  else
    print_output "[-] No run script created ..."
  fi
}

get_binary() {
  local lBINARY_NAME="${1:-}"
  local lARCH_END="${2:-}"
  local lMUSL_VER="${3:-}"

  # '${lBINARY_NAME/\.*}' -> strip the .so from libnvram.so and libnvram_ioctl.so
  if [[ "${lBINARY_NAME}" == *"busybox"* ]] && [[ -f "${BINARY_DIR}/${lBINARY_NAME}-v${L10_BB_VER}/${lBINARY_NAME}.${lARCH_END}" ]]; then
    echo "${BINARY_DIR}/${lBINARY_NAME}-v${L10_BB_VER}/${lBINARY_NAME}.${lARCH_END}"
  elif [[ -f "${BINARY_DIR}/${lBINARY_NAME/_dbg*}/${lBINARY_NAME}.${lARCH_END}_musl_${lMUSL_VER}" ]]; then
    # use sub-directories for the different binaries:
    # will be used in the future
    echo "${BINARY_DIR}/${lBINARY_NAME/_dbg*}/${lBINARY_NAME}.${lARCH_END}_musl_${lMUSL_VER}"
  elif [[ -f "${BINARY_DIR}/${lBINARY_NAME/_nondbg*}/${lBINARY_NAME}.${lARCH_END}_musl_${lMUSL_VER}" ]]; then
    # use sub-directories for the different binaries:
    # will be used in the future
    echo "${BINARY_DIR}/${lBINARY_NAME/_nondbg*}/${lBINARY_NAME}.${lARCH_END}_musl_${lMUSL_VER}"
  elif [[ -f "${BINARY_DIR}/${lBINARY_NAME}/${lBINARY_NAME}.${lARCH_END}" ]]; then
    echo "${BINARY_DIR}/${lBINARY_NAME}/${lBINARY_NAME}.${lARCH_END}"
  else
    echo "NA"
  fi
}

add_partition_emulation() {
  local lIMAGE_PATH=""
  local lDEV_PATH="NA"
  local lFOUND=false
  local lCNT=0
  local lDEV_NR=0

  while (losetup | grep -q "${1}"); do
    local lLOOP=""
    ((lCNT+=1))
    lLOOP=$(losetup -a | grep "${1}" | sort -u)
    # we try to get rid of the entry nicely
    losetup -d "${lLOOP/:*}"
    if losetup -a | grep -q "${1}"; then
      # and now we go the brutal way
      losetup -D
      dmsetup remove_all -f &>/dev/null || true
    fi
    if [[ "${lCNT}" -gt 10 ]]; then
      break
    fi
    sleep 5
  done

  local lCNT=0
  while (! losetup -Pf "${1}"); do
    ((lCNT+=1))
    if [[ "${lCNT}" -gt 10 ]]; then
      break
    fi
    sleep 5
  done

  local lCNT=0
  while (! "${lFOUND}"); do
    sleep 1
    ((lCNT+=1))
    local lLOSETUP_OUT_ARR=()
    mapfile -t lLOSETUP_OUT_ARR < <(losetup | grep -v "BACK-FILE" || true)
    local lLINE=""
    for lLINE in "${lLOSETUP_OUT_ARR[@]}"; do
      lIMAGE_PATH=$(echo "${lLINE}" | awk '{print $6}')
      if [[ "${lIMAGE_PATH}" == "${1}" ]]; then
        lDEV_PATH=$(echo "${lLINE}" | awk '{print $1}')
        if [[ "$(dirname "${lDEV_PATH}")" == "/dev/loop" ]]; then
          # if we have the new naming like /dev/loop/0 -> dirname results in /dev/loop
          lDEV_NR=$(echo "${lDEV_PATH}" | rev | cut -d '/' -f1 | rev)
          lDEV_PATH="/dev/loop${lDEV_NR}p1"
        else
          # old naming like /dev/loop0 -> dirname results in /dev/
          lDEV_PATH=$(echo "${lLINE}" | awk '{print $1}')p1
        fi
        if [[ -b "${lDEV_PATH}" ]]; then
          lFOUND=true
        fi
      fi
    done
    if [[ "${lCNT}" -gt 600 ]]; then
      # get an exit if nothing happens
      break
    fi
  done

  if [[ "${lDEV_PATH}" != "NA" ]]; then
    local lCNT=0
    while (! find "${lDEV_PATH}" -ls 2>/dev/null | grep -q "disk"); do
      sleep 1
      ((lCNT+=1))
      if [[ "${lCNT}" -gt 600 ]]; then
        # get an exit if nothing happens
        break
      fi
    done
  fi
  echo "${lDEV_PATH}"
}

get_kernel_version() {
  local lKV=""
  local lKERNELV_ARR=()

  if [[ -f "${S25_LOG}" ]]; then
    mapfile -t lKERNELV_ARR < <(grep "Statistics:" "${S25_LOG}" | cut -d: -f2 | sort -u || true)
    if [[ -v lKERNELV_ARR[@] ]]; then
      # if we have found a kernel it is a Linux system:$
      for lKV in "${lKERNELV_ARR[@]}"; do
        if [[ "${lKV}" == "2"* ]]; then
          KERNEL_V=2
          break
        elif [[ "${lKV}" == "4"* ]]; then
          KERNEL_V=4
          break
        else
          # just to have some fallback solution
          KERNEL_V=4
          break
        fi
      done
    fi
  else
    # just to have some fallback solution
    KERNEL_V=4
  fi
}

set_network_config() {
  local lIP_ADDRESS="${1:-192.168.0.1}"
  local lNETWORK_MODE="${2:-bridge}"
  local lNETWORK_DEVICE="${3:-br0}"
  local lETH_INT="${4:-eth0}"

  echo "${lNETWORK_MODE}" > "${MNT_POINT}/firmadyne/network_type"
  echo "${lNETWORK_DEVICE}" > "${MNT_POINT}/firmadyne/net_bridge"
  echo "${lETH_INT}" > "${MNT_POINT}/firmadyne/net_interface"
  if [[ -z "${lIP_ADDRESS}" ]]; then
    lIP_ADDRESS="192.168.0.1"
  fi
  echo "${lIP_ADDRESS}" > "${MNT_POINT}/firmadyne/ip_default"
}

write_results() {
  if [[ "${IN_DOCKER}" -eq 1 ]] && [[ -f "${TMP_DIR}"/fw_name.log ]]; then
    local lFIRMWARE_PATH_orig=""
    lFIRMWARE_PATH_orig="$(cat "${TMP_DIR}"/fw_name.log)"
  fi

  local lARCHIVE_PATH="${1:-}"
  local lR_PATH="${2:-}"
  local lRESULT_SOURCE="${3:-}"
  local lNETWORK_MODE="${4:-}"
  local lETH_INT="${5:-}"
  local lVLAN_ID="${6:-}"
  local lINIT_FILE="${7:-}"
  local lNETWORK_DEVICE="${8:-}"

  local lR_PATH_mod=""
  lR_PATH_mod="${lR_PATH/${LOG_DIR}/}"
  local lTCP_SERV_CNT=0
  local lSERVICES=""

  lTCP_SERV_CNT="$(grep -h "udp.*open\ \|tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null | awk '{print $1}' | sort -u | wc -l || true)"
  # to get an overview of which services are available
  lSERVICES="$(grep -h "\/udp.*open\ \|\/tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null | awk '{print $1}' | sort -u | tr '\n' ',' || true)"

  [[ "${lTCP_SERV_CNT}" -gt 0 ]] && TCP="ok"
  lARCHIVE_PATH="$(echo "${lARCHIVE_PATH}" | rev | cut -d '/' -f1 | rev)"
  if ! [[ -f "${L10_SYS_EMU_RESULTS}" ]]; then
    write_log "FIRMWARE_PATH;RESULT_SOURCE;Booted state;ICMP state;TCP-0 state;TCP state;online services cnt;available network services;IP address;Network mode (NETWORK_DEVICE|ETH_INT|VLAN_ID|INIT_FILE|INIT_MECHANISM);ARCHIVE_PATH_;R_PATH" "${L10_SYS_EMU_RESULTS}"
  fi
  write_log "${lFIRMWARE_PATH_orig:-NA};${lRESULT_SOURCE};Booted ${BOOTED};ICMP ${ICMP};TCP-0 ${TCP_0};TCP ${TCP};${lTCP_SERV_CNT};${lSERVICES%,};IP address: ${IP_ADDRESS_};Network mode: ${lNETWORK_MODE} (${lNETWORK_DEVICE}|${lETH_INT}|${lVLAN_ID}|${lINIT_FILE}|${KINIT/=*});${lARCHIVE_PATH};${lR_PATH_mod}" "${L10_SYS_EMU_RESULTS}"
  print_bar ""
}

set_firmae_arbitration() {
  local lFIRMAE_STATE="${1:-true}"
  # FirmAE arbitration - enable all mechanisms
  export EMBA_BOOT="${lFIRMAE_STATE}"
  export EMBA_NET="${lFIRMAE_STATE}"
  export EMBA_NVRAM="${lFIRMAE_STATE}"
  export EMBA_KERNEL="${lFIRMAE_STATE}"
  export EMBA_ETC="${lFIRMAE_STATE}"
}

color_qemu_log() {
  local lQEMU_LOG_FILE="${1:-}"
  if ! [[ -f "${lQEMU_LOG_FILE:-}" ]]; then
    return
  fi

  # GREEN: keywords for network identification:
  sed -i -r "s/.*br_add_if.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*br_dev_ioctl.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*__inet_insert_ifa.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*ioctl_SIOCSIFHWADDR.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*register_vlan_dev.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*\[NVRAM\]\ .*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*inet_bind.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*adding VLAN [0-9] to HW filter on device eth[0-9].*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"

  # Green: other interesting areas:
  sed -i -r "s/.*Kernel\ command\ line:\ .*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*Starting\ services\ in\ emulated\ environment.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*Network configuration - ACTION.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*starting\ network\ configuration.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*Current\ network\ configuration.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*Netstat\ output\ .*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
  sed -i -r "s/.*Starting\ .*\ service\ .*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"

  # RED:
  sed -i -r "s/.*Kernel\ panic\ -\ .*/\x1b[31m&\x1b[0m/" "${lQEMU_LOG_FILE}"
}
