#!/usr/bin/env bash

# SPDX-FileCopyrightText: 2024 3mdeb <contact@3mdeb.com>
#
# SPDX-License-Identifier: Apache-2.0

# shellcheck source=../include/dts-environment.sh
source $DTS_ENV
# shellcheck source=../include/dts-functions.sh
source $DTS_FUNCS

update_result() {
  TOOL=$1
  ERRORFILE=$2
  LOGFILE=`printf $2 | sed 's/[.].*$//' && echo ".log"`

  # check if status was set as a unknown
  if [ ! -v $3 ]; then
   echo -e [$YELLOW"UNKNOWN"$NORMAL]"\t"$TOOL >> result
   return
  fi

  ERR=$(stat -c%s "$ERRORFILE" 2> /dev/null)
  LOG=$(stat -c%s "$LOGFILE" 2> /dev/null)

  # if ERR or LOG var is empty, set it to 1 so we will go into UNKNOWN state
  if [ -z "$LOG" ]; then
    LOG=1
  fi
  if [ -z "$ERR" ]; then
    ERR=1
  fi
  # specific check for firmware dump
  if [ $LOGFILE == "logs/flashrom_read.log" ]; then
    if [ $LOG -ne 0 ] && [ -f "logs/rom.bin" ]; then
      echo -e [$GREEN"OK"$NORMAL]"\t\t"$TOOL >> result
    else
      echo -e [$RED"ERROR"$NORMAL]"\t\t"$TOOL >> result
    fi
    return
  fi

  # generic checks
  if [ $LOG -ne 0 ] && [ $ERR -eq 0 ]; then
   echo -e [$GREEN"OK"$NORMAL]"\t\t"$TOOL >> result
  elif [ $LOG -eq 0 ] && [ $ERR -ne 0 ]; then
   echo -e [$RED"ERROR"$NORMAL]"\t\t"$TOOL >> result
  else
   echo -e [$YELLOW"UNKNOWN"$NORMAL]"\t"$TOOL >> result
  fi
}

CMD_DASHARO_DEPLOY="/usr/sbin/dasharo-deploy"

if [ "$(id -u)" -ne 0 ]; then
  echo "This script must be started as root!"
  exit 1
fi

if [ -d logs ]; then
  rm -rf logs
fi

FULL_UPLOAD_URL="https://cloud.3mdeb.com/index.php/s/"${CLOUDSEND_LOGS_URL}

check_flash_chip

mkdir logs
if [ $DEPLOY_REPORT = "false" ]; then
  echo "Getting hardware information. It will take a few minutes..."
fi
# echo "Dumping PCI configuration space and topology..."
lspci -nnvvvxxxx > logs/lspci.log 2> logs/lspci.err.log
update_result "PCI configuration space and topology" logs/lspci.err.log
printf '##                                                                 |\r'

# echo "Dumping USB devices and topology..."
lsusb -vvv > logs/lsusb.log 2> logs/lsusb.err.log
update_result "USB devices and topology" logs/lsusb.err.log
printf '####                                                               |\r'

# echo "Dumping Super I/O configuration..."
superiotool -deV > logs/superiotool.log 2> logs/superiotool.err.log
update_result "Super I/O configuration" logs/superiotool.err.log
printf '######                                                             |\r'

# echo "Dumping Embedded Controller configuration (this may take a while if EC is not present)..."
ectool -ip > logs/ectool.log 2> logs/ectool.err.log
update_result "EC configuration" logs/ectool.err.log
printf '########                                                           |\r'

# echo "Dumping MSRs..."
msrtool > logs/msrtool.log 2> logs/msrtool.err.log
update_result "MSRs" logs/msrtool.err.log
printf '##########                                                         |\r'

# echo "Dumping SMBIOS tables..."
dmidecode > logs/dmidecode.log 2> logs/dmidecode.err.log
update_result "SMBIOS tables" logs/dmidecode.err.log
printf '############                                                       |\r'

# echo "Decoding BIOS information..."
biosdecode > logs/biosdecode.log 2> logs/biosdecode.err.log
update_result "BIOS information" logs/biosdecode.err.log
printf '##############                                                     |\r'

# echo "Extracting CMOS NVRAM..."
nvramtool -x > logs/nvramtool.log 2> logs/nvramtool.err.log
update_result "CMOS NVRAM" logs/nvramtool.err.log
printf '################                                                   |\r'

# echo "Dumping Intel configuration registers..."
inteltool -a > logs/inteltool.log 2> logs/inteltool.err.log
update_result "Intel configuration registers" logs/inteltool.err.log
printf '##################                                                 |\r'

# echo "Generating GPIO configuration C header files for coreboot..."
intelp2m -file logs/inteltool.log -fld cb -i -p snr -o logs/gpio_snr.h > logs/intelp2m.log 2> logs/intelp2m.err.log
intelp2m -file logs/inteltool.log -fld cb -i -p cnl -o logs/gpio_cnl.h >> logs/intelp2m.log 2>> logs/intelp2m.err.log
intelp2m -file logs/inteltool.log -fld cb -i -p apl -o logs/gpio_apl.h >> logs/intelp2m.log 2>> logs/intelp2m.err.log
intelp2m -file logs/inteltool.log -fld cb -i -p lbg -o logs/gpio_lbg.h >> logs/intelp2m.log 2>> logs/intelp2m.err.log
update_result "GPIO configuration C header files" logs/intelp2m.err.log
printf '####################                                               |\r'

# echo "Dumping kernel dmesg..."
dmesg > logs/dmesg.log 2> logs/dmesg.err.log
update_result "kernel dmesg" logs/dmesg.err.log
printf '######################                                             |\r'

# echo "Dumping ACPI tables..."
acpidump > logs/acpidump.log 2> logs/acpidump.err.log
update_result "ACPI tables" logs/acpidump.err.log
printf '########################                                           |\r'

# echo "Dumping Audio devices configuration..."

# This is a workaround to soundcard's files absence in short time after booting.
# Thread is continued here https://github.com/Dasharo/dasharo-issues/issues/247
for t in {1..12}
do
  SND_HW_FILES="/sys/class/sound/card0/hw*/init_pin_configs"
  SND_CODEC_FILES="/proc/asound/card0/codec#*"
  SND_HW_FILE=`echo $SND_HW_FILES | cut -d ' ' -f 1`
  SND_CODEC_FILE=`echo $SND_CODEC_FILES | cut -d ' ' -f 1`

  if [ -f "$SND_HW_FILE" ] && [ -f "$SND_CODEC_FILE" ]; then
    break
  else
    sleep 5
    if [ $t -eq 12 ]; then
      if [ $DEPLOY_REPORT = "false" ]; then
        echo "Sound card files are missing!"
      fi
    fi
  fi
done

for x in /sys/class/sound/card0/hw*; do cat "$x/init_pin_configs" > logs/pin_"$(basename "$x")" 2> logs/pin_"$(basename "$x")".err.log; done
for x in /proc/asound/card0/codec#*; do cat "$x" > logs/"$(basename "$x")" 2> logs/"$(basename "$x")".err.log; done
update_result "Audio devices configuration" 0 UNKNOWN
printf '##########################                                         |\r'

# echo "Dumping CPU info..."
cat /proc/cpuinfo > logs/cpuinfo.log 2> logs/cpuinfo.err.log
update_result "CPU info" logs/cpuinfo.err.log
printf '############################                                       |\r'

# echo "Dumping I/O ports..."
cat /proc/ioports > logs/ioports.log 2> logs/ioports.err.log
update_result "I/O ports" logs/ioports.err.log
printf '##############################                                     |\r'

# echo "Dumping input bus types..."
cat /sys/class/input/input*/id/bustype > logs/input_bustypes.log
update_result "Input bus types"  logs/ioports.err.log
printf '################################                                   |\r'

# echo "Trying to read firmware image with flashrom..."
# Some regions may be not available so we need to use specific regions to read
check_intel_regions
if [ $BOARD_HAS_FD_REGION -eq 1 ]; then
  # Use safe defaults. Descriptor may contain additional regions not detected
  # by flashrom and will return failure when attempted to be read. BIOS and
  # Flash descriptor regions should always be readable. If not, then we have
  # some ugly case, hard to deal with.
  FLASHROM_ADD_OPT_READ="--ifd -i fd -i bios"
  if [ $BOARD_HAS_ME_REGION -eq 1 ] && [ $BOARD_ME_REGION_LOCKED -eq 0 ]; then
    # ME region is not locked, read it as well
    FLASHROM_ADD_OPT_READ+=" -i me"
  fi
  if [ $BOARD_HAS_GBE_REGION -eq 1 ] && [ $BOARD_GBE_REGION_LOCKED -eq 0 ]; then
    # GBE region is present and not locked, read it as well
    FLASHROM_ADD_OPT_READ+=" -i gbe"
  fi
  else
      # No descriptor, probably safe to read everything
      FLASHROM_ADD_OPT_READ=""
fi

$FLASHROM -V -p internal:laptop=force_I_want_a_brick ${FLASH_CHIP_SELECT} -r logs/rom.bin ${FLASHROM_ADD_OPT_READ} > logs/flashrom_read.log 2> logs/flashrom_read.err.log
if [ $? -ne 0 ]; then
  echo "CRITICAL ERROR: cannot dump firmware"
fi
update_result "Firmware image" logs/flashrom_read.err.log
printf '##################################                                 |\r'

# echo "Probing all I2C buses..."
MAX_I2C_ID=$(i2cdetect -l | awk 'BEGIN{c1=0} //{c1++} END{print "",--c1}')
for bus in $(seq 0 "$MAX_I2C_ID");
do
  echo "I2C bus number: $bus" >> logs/i2cdetect.log 2>> logs/i2cdetect.err.log
  i2cdetect -y "$bus" >> logs/i2cdetect.log 2>> logs/i2cdetect.err.log
done
update_result "I2C bus" logs/i2cdetect.err.log
printf '####################################                               |\r'

# echo "Decompiling ACPI tables..."
mkdir -p logs/acpi
if pushd logs/acpi &> /dev/null; then
  acpixtract -a ../acpidump.log &>/dev/null
  iasl -d ./*.dat &>/dev/null
  popd &> /dev/null || return 1
fi
update_result "ACPI tables" 0 UNKNOWN
printf '######################################                             |\r'

# echo "Getting touchpad information..."
touchpad-info > logs/touchpad.log 2> logs/touchpad.err.log
update_result "Touchpad information" logs/touchpad.err.log
printf '########################################                           |\r'

# echo "Getting DIMMs information..."
decode-dimms > logs/decode-dimms.log 2> logs/decode-dimms.err.log
update_result "DIMMs information" logs/decode-dimms.err.log
printf '##########################################                         |\r'

# echo "Getting CBMEM table..."
cbmem > logs/cbmem.log 2> logs/cbmem.err.log
update_result "CBMEM table information" logs/cbmem.err.log
printf '############################################                       |\r'

# echo "Getting TPM information..."
find "$(realpath /sys/class/tpm/tpm*)" -type f -print -exec cat {} \; > logs/tpm_version.log 2> logs/tpm_version.err.log
update_result "TPM information" logs/tpm_version.err.log
printf '#############################################                      |\r'

# echo "Checking AMT..."
mei-amt-check > logs/amt-check.log 2> logs/amt-check.err.log
update_result "AMT information" logs/amt-check.err.log
printf '###############################################                    |\r'

# echo "Checking ME..."
intelmetool -m > logs/intelmetool.log 2> logs/intelmetool.err.log
update_result "ME information" logs/intelmetool.err.log
printf '################################################                   |\r'

printf '##################################################                 |\r'
printf '####################################################               |\r'
printf '######################################################             |\r'
printf '########################################################           |\r'
printf '##########################################################         |\r'
printf '############################################################       |\r'
printf '##############################################################     |\r'
printf '################################################################   |\r'
printf '################################################################## |\r'
printf '###################################################################|\r'
# next two echo cmds helps with printing
echo
echo

echo "Results of getting data:" >> result
echo -e "\nLegend:" >> result
echo -e [$GREEN"OK"$NORMAL]"\t\t Data get successfully" >> result
echo -e [$YELLOW"UNKNOWN"$NORMAL]"\t Result is unknown" >> result
echo -e [$RED"ERROR"$NORMAL]"\t\t Error during getting data\n" >> result

mv result logs/result
if [ $DEPLOY_REPORT = "false" ]; then
  cat logs/result
fi

# Create name for generated report
filename="$(dmidecode -s system-manufacturer)"
filename+=" $(dmidecode -s system-product-name)"
filename+=" $(dmidecode -s bios-version)"

# MAC address of device that is used to connect the internet
# it could return none only when there is no internet connection but
# in those cases report will be stored locally only.
# Ignore "SC2046 (warning): Quote this to prevent word splitting" shellcheck
# warning:
# shellcheck disable=SC2046
uuid_string="$(cat /sys/class/net/$(ip route show default | head -1 | awk '/default/ {print $5}')/address)"
# next two values are hardware related so they will be always the same
uuid_string+="_$(dmidecode -s system-product-name)"
uuid_string+="_$(dmidecode -s system-manufacturer)"

# using values from above should generate the same uuid all the time if only
# the MAC address will not change.
uuid=`uuidgen -n @x500 -N $uuid_string -s`

filename+="_$uuid"
filename+="_$(date +'%Y_%m_%d_%H_%M_%S_%N')"
filename="${filename// /_}"
filename="${filename//\//_}"

if [ $DEPLOY_REPORT = "false" ]; then
  echo "Creating archive with logs..."
fi

# Remove MAC address from logs as sensitive data.
# Ignore "SC2046 (warning): Quote this to prevent word splitting" shellcheck
# warning:
# shellcheck disable=SC2046
MAC_ADDR=`cat /sys/class/net/$(ip route show default | head -1 | awk '/default/ {print $5}')/address`
grep -rl "${MAC_ADDR}" logs > /dev/null && grep -rl "${MAC_ADDR}" logs | xargs sed -i 's/'${MAC_ADDR}'/MAC ADDRESS REMOVED/g'
tar -zcf "$filename.tar.gz" logs/*
rm -rf logs

if [ $DEPLOY_REPORT = "false" ]; then
  echo "Done! Logs saved to: $(readlink -f $filename.tar.gz)"
fi

if [ "$SEND_LOGS" = "true" ]; then
  if [ $DEPLOY_REPORT = "false" ]; then
    echo "Sending logs to 3mdeb cloud..."
    CLOUDSEND_OPTS="-e"
  else
    CLOUDSEND_OPTS="-e -q"
  fi
  cloudsend.sh \
    ${CLOUDSEND_OPTS} \
    "$(readlink -f $filename.tar.gz)" \
    ${FULL_UPLOAD_URL}
  if [ "$?" -ne "0" ]; then
    echo "Failed to send logs to the cloud"
    if [ -a "${CMD_DASHARO_DEPLOY}" ]; then
      echo -e "Something may be wrong with credentials. Please use option 4 to change DPP keys
               \rand make sure that there is no typo."
    fi
    exit 1
  fi
  if [ $DEPLOY_REPORT = "false" ]; then
    echo "Thank you for supporting Dasharo!"
  fi
fi

echo -e \
"-----------------------------------------------------------------------------\r
Would you like to contribute to the \"Hardware for Linux\" project?\r
it is an open source project that that anonymously collects hardware details\r
of Linux-powered computers over the world and helps people to collaboratively\r
debug hardware related issues, check for Linux-compatibility and find drivers.\r
-----------------------------------------------------------------------------\r
You can find more about it here:\r
https://linux-hardware.org/\r
https://github.com/linuxhw/hw-probe\r
-----------------------------------------------------------------------------\r
Do you want to participate in this project?\r
(if you answer \"yes\", then command hw-probe --all --upload will be ran, in \r
order to participate)\r
"

read -p "[N/y] "
case ${REPLY} in
    yes|y|Y|Yes|YES)
    /usr/bin/hw-probe -all -upload
    if [ $? -eq 0 ]; then
        echo "Thank you for contributing to the \"Hardware for Linux\" project!"
    else
        echo "couldn't probe/upload. Check your internet connection..."
        exit 1
    fi
    ;;
    *)
    echo -e \
    "Please consider contributing to the \"Hardware for Linux\" project in the future.\r
    All you have to do is run this command:\r
    hw-probe --all --upload\r
    "
    ;;
esac
