#!/bin/sh
#      Copyright (C) 2008-2013 Team XBMC
#      http://xbmc.org
#
#  This Program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2, or (at your option)
#  any later version.
#
#  This Program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details.

. /etc/profile

trap cleanup TERM

KODI_ROOT=$HOME/.kodi

SAVED_ARGS="$@"
CRASHLOG_DIR=$KODI_ROOT/temp

BOOT_STATUS=$HOME/.config/boot.status
NOSAFE_MODE=$HOME/.config/safemode.disable
CRASH_HIST=/run/libreelec/crashes.dat
KODI_MAX_RESTARTS=@KODI_MAX_RESTARTS@
KODI_MAX_SECONDS=@KODI_MAX_SECONDS@

cleanup() {
  # make systemd happy by not exiting immediately but
  # wait for kodi to exit
  while killall -0 kodi.bin &>/dev/null; do
    sleep 0.5
  done
}

command_exists()
{
  command -v $1 &>/dev/null
}

single_stacktrace()
{
  # core filename is "core.*kodi.bin.*"
  find "$1" -name 'core.*kodi.bin.*' | while read core; do
    echo "=====>  Core file: "$core"" >> $FILE
    echo "        =========================================" >> $FILE
    if [ -f /storage/.config/debug.enhanced ]; then
      gdb /usr/lib/kodi/kodi.bin --core="$core" --batch -ex "thread apply all bt full" -ex "info registers" -ex "set print asm-demangle on" -ex "disassemble" 2>/dev/null >> $FILE
    else
      gdb /usr/lib/kodi/kodi.bin --core="$core" --batch -ex "thread apply all bt" 2>/dev/null >> $FILE
    fi
    rm -f "$core"
  done
}

detect_crash_loop()
{
  # use monotonic time (in case date/time changes after booting)
  NOW_TIME=$(awk '/^now/ {print int($3 / 1000000000)}' /proc/timer_list)
  echo "$NOW_TIME" >> $CRASH_HIST

  NUM_RESTARTS=$(wc -l $CRASH_HIST | cut -d' ' -f1)
  FIRST_RESTART_TIME=$(tail -n $KODI_MAX_RESTARTS $CRASH_HIST | head -n 1)

  # kodi restart loop detected? fail this kodi install
  if [ $NUM_RESTARTS -ge $KODI_MAX_RESTARTS -a $KODI_MAX_SECONDS -ge $((NOW_TIME - FIRST_RESTART_TIME)) ]; then
    return 0
  else
    return 1
  fi
}

activate_safe_mode()
{
  [ -f $NOSAFE_MODE ] && return 0

  BOOT_STATE="$(cat $BOOT_STATUS 2>/dev/null)"

  if [ "${BOOT_STATE:-OK}" = "OK" ]; then
    # generate logfiles zip for the failed kodi
    /usr/bin/createlog
    lastlog=$(ls -1 /storage/logfiles/*.zip | tail -n 1)
    mv $lastlog /storage/logfiles/log-$(date -u +%Y-%m-%d-%H.%M.%S)-FAILED.zip

    echo "SAFE" > $BOOT_STATUS
  fi

  return 0
}

print_crash_report()
{
  mkdir -p $CRASHLOG_DIR

  DATE=`date +%Y%m%d%H%M%S`
  FILE="$CRASHLOG_DIR/.kodi_crashlog.log"
  echo "############## kodi CRASH LOG ###############" > $FILE
  echo >> $FILE
  echo "################ SYSTEM INFO ################" >> $FILE
  echo -n " Date: " >> $FILE
  date >> $FILE
  echo " kodi Options: $SAVED_ARGS" >> $FILE
  echo -n " Arch: " >> $FILE
  uname -m >> $FILE
  echo -n " Kernel: " >> $FILE
  uname -rvs >> $FILE
  echo -n " Release: " >> $FILE
  . /etc/os-release
  echo $NAME $VERSION >> $FILE
  echo "############## END SYSTEM INFO ##############" >> $FILE
  echo >> $FILE
  echo "############### STACK TRACE #################" >> $FILE
  if command_exists gdb; then
    single_stacktrace /storage/.cache/cores
  else
    echo "gdb not installed, can't get stack trace." >> $FILE
  fi
  echo "############# END STACK TRACE ###############" >> $FILE
  echo >> $FILE
  echo "################# LOG FILE ##################" >> $FILE
  echo >> $FILE
  cat $KODI_ROOT/temp/kodi.log >> $FILE
  echo >> $FILE
  echo "############### END LOG FILE ################" >> $FILE
  echo >> $FILE
  echo "############ END kodi CRASH LOG #############" >> $FILE
  OFILE="$FILE"
  FILE="$CRASHLOG_DIR/kodi_crashlog_$DATE.log"
  mv "$OFILE" "$FILE"
  ln -sf "$(basename $FILE)" "$CRASHLOG_DIR/kodi_crash.log"
  echo "Crash report available at $FILE"
}

if command_exists gdb; then
  ulimit -c unlimited
fi

# clean up any stale cores. just in case
find /storage/.cache/cores -type f -delete

# clean zero-byte database files that prevent migration/startup
for file in $KODI_ROOT/userdata/Database/*.db; do
  if [ -e "$file" ]; then
    [ -s $file ] || rm -f $file
  fi
done

/usr/lib/kodi/kodi.bin $SAVED_ARGS
RET=$?

if [ $(( ($RET >= 131 && $RET <= 136) || $RET == 139 )) = "1" ] ; then
  # Crashed with core dump
  print_crash_report

  # Cleanup. Keep only youngest 10 reports but current in any case
  rm -f $(ls -1t $CRASHLOG_DIR/kodi_crashlog_*.log | grep -v "$FILE" | tail -n +10)

  # Enable safe mode if a crash loop is detected
  detect_crash_loop && activate_safe_mode
fi

# Filter Kodi powerdown/restartapp/reboot codes to satisfy systemd
[ "$RET" -ge 64 -a "$RET" -le 66 ] && RET=0

exit $RET
