#!/bin/sh

set -x

GetConfiguration()
{
    NAVICO_COREDUMP_FLAG=/tmp/navico_coredump_active

    TRY_TO_SAVE_ON_EXTERNAL_MEDIA=1
    TRY_TO_SAVE_ON_INTERNAL_PARTITION=0

    EXTERNAL_MEDIA_IGNORE=
    INTERNAL_STORAGE_LIST=
    # 20 MB
    MINIMUM_SPACE=20000
    FILE_GRAB_LIST=
    USERFEEDBACK=
    TEMPDIR=/tmp/navico-coredump
    SEQUENCE_FILE=/home/nos/sequence.ini
    MINIMUM_THRESHOLD=100000
    
    if [ -e /etc/navico-coredump.conf ]; then
        . /etc/navico-coredump.conf
    fi
}

GetCommandLineArguments()
{
  while [ $# -gt 0 ]; do
    case $1 in
      --exec=*)
      coredump_thread_name=${1#--exec=}
      ;;
      --pid=*)
      coredump_pid=${1#--pid=}
      ;;
      --signal=*)
      coredump_signal=${1#--signal=}
      ;;
      --time=*)
      coredump_time=${1#--time=}
      ;;
    esac
    shift
  done
}

DumpSysLog()
{
    echo Dump Sys Log  
}

DumpDmesg()
{
    /bin/dmesg > $TEMPDIR/dmesg.log
}

DumpNOSInfo()
{
  echo Dump NOS Info

  for grab in $FILE_GRAB_LIST; do
    cp -r $grab $TEMPDIR/
  done
}

SpaceAvailable()
{
    space_available=$(df -k $1 | awk '/\/dev\//{print $4}')
    echo $space_available
    if [ $space_available -gt $MINIMUM_SPACE ]; then
        return 1
    fi
    return 2
}

StartUserFeedback()
{
    if [ -x ${USERFEEDBACK} ]; then
        ${USERFEEDBACK} start ${coredump_exe_name}
    fi
}

EndUserFeedback()
{
    if [ -x ${USERFEEDBACK} ]; then
        ${USERFEEDBACK} stop ${coredump_exe_name}
    fi
}

#------------------------------------------------------------------------------

GetConfiguration
GetCommandLineArguments $*

if [ $coredump_thread_name = "" ]; then
    # called from command line
    exit
fi 

coredump_exe_name=$(basename $(readlink /proc/${coredump_pid}/exe))

touch $NAVICO_COREDUMP_FLAG

CORE_DUMP_ROOT_DIRECTORY=

# check sd cards first
if [ "${TRY_TO_SAVE_ON_EXTERNAL_MEDIA}" = "1" ]; then
    for SDPATH in /media/*; do
        echo $SDPATH
        IGNORE_PATH=0
        for IGNORE_MEDIA in ${EXTERNAL_MEDIA_IGNORE}; do
            if [ $SDPATH == $IGNORE_MEDIA ]; then
                IGNORE_PATH=1
                break
            fi
        done

        if [ "${IGNORE_PATH}" = "0" ]; then
            IGNORE_PATH=0
            if [ -d $SDPATH ]; then
                RWFLG=$(cat /proc/mounts | grep $SDPATH | cut -d " " -f 4 | cut -d "," -f 1)
                echo $RWFLG
                if [ "$RWFLG" = "rw" ]; then
                    SpaceAvailable $SDPATH
                    if [ "$?" = "1" ]; then
                        CORE_DUMP_ROOT_DIRECTORY=$SDPATH
                        break;
                    fi
                fi
            fi
        fi
    done
fi

if [ -z "${CORE_DUMP_ROOT_DIRECTORY}" ] && [ "${TRY_TO_SAVE_ON_INTERNAL_PARTITION}" = "1" ]; then
    for dir in ${INTERNAL_STORAGE_LIST}; do
        if [ "$(df ${dir} | awk '{ if (NR==2) print $2 }')" -gt "${MINIMUM_SPACE}" ]; then
            CORE_DUMP_ROOT_DIRECTORY=${dir}
            break
        fi
    done
fi

echo $CORE_DUMP_ROOT_DIRECTORY

# Does the requested directory actually exist? If not then bail
if [ -z "${CORE_DUMP_ROOT_DIRECTORY}" ]; then
    rm $NAVICO_COREDUMP_FLAG
    exit
fi

StartUserFeedback

rm -fR ${TEMPDIR}
mkdir ${TEMPDIR}

# If the requested directory is on a read-only file-system (common for map partitions) then
# remount this read-write. This is slightly dangerous !
MOUTPOINT=df ${CORE_DUMP_ROOT_DIRECTORY} | awk '{ if (NR==2) print $6 }'
if ! touch ${MOUTPOINT}/test_core_write >/dev/null 2>&1; then
    NEED_REMOUNT_RO=true
    mount -o rw,remount ${MOUTPOINT}
else
    rm ${MOUTPOINT}/test_core_write
fi

if [ -e $SEQUENCE_FILE ]; then
        . $SEQUENCE_FILE
else
        touch $SEQUENCE_FILE
        coredump_seq=1 
fi

CORE_DUMP_DIRECTORY=${CORE_DUMP_ROOT_DIRECTORY}/crashlog
CORE_FILE=$CORE_DUMP_DIRECTORY/_${coredump_seq}_${coredump_exe_name}_${coredump_thread_name}_${coredump_time}_${coredump_signal}_core.gz
EXTRAS_FILE=$CORE_DUMP_DIRECTORY/_${coredump_seq}_${coredump_exe_name}_${coredump_thread_name}_${coredump_time}_${coredump_signal}_extra.tar.gz

while [ "$(df ${CORE_DUMP_ROOT_DIRECTORY} | awk '{ if (NR==2) print $4 }')" -lt "${MINIMUM_THRESHOLD}" ]; do
   if ! ls ${CORE_DUMP_DIRECTORY}/*.gz; then
       break;
   fi

   minimum=$coredump_seq
   for corefile in $CORE_DUMP_DIRECTORY/*.gz
   do
       temp=$(echo ${corefile} | awk -F_ '{print $2}') 
       if [ $temp -lt $minimum ]; then
          minimum=$temp
       fi
   done

   for corefile in $CORE_DUMP_DIRECTORY/*.gz
   do
       temp=$(echo ${corefile} | awk -F_ '{print $2}') 
       if [ $temp -eq $minimum ]; then
          rm $corefile
       fi
   done
done

coredump_seq=$(expr $coredump_seq + 1)
echo "coredump_seq=$coredump_seq" > $SEQUENCE_FILE_"temp"
mv $SEQUENCE_FILE_"temp"  $SEQUENCE_FILE


# Make sure core-dump directory exists and is writeable by everyone
if [ ! -d $CORE_DUMP_DIRECTORY ]; then
    mkdir -p ${CORE_DUMP_DIRECTORY}
fi
chmod a+rwx ${CORE_DUMP_DIRECTORY}
chown $(stat -c %U:%G ${CORE_DUMP_ROOT_DIRECTORY}) ${CORE_DUMP_DIRECTORY}

echo ${CORE_DUMP_DIRECTORY}

# Disable panic (and then reboot) on out-of-memory
echo 0 > /proc/sys/vm/panic_on_oom

# Collect data before app is closed, in case we die during real core dump
DumpSysLog
DumpDmesg
DumpNOSInfo

# Agregate all the files into a single tar file
tar -C ${TEMPDIR} -czf ${EXTRAS_FILE} .
chown $(stat -c %U:%G ${INTERNAL_STORAGE_LIST}) ${EXTRAS_FILE}
chmod a+rw ${EXTRAS_FILE}
sync
rm -fr ${TEMPDIR}/*

# Disable hung-task checking during coredump
if [ -w /proc/sys/kernel/hung_task_timeout_secs ]; then
    echo 0 >/proc/sys/kernel/hung_task_timeout_secs
fi

# zip core dump
gzip -f > ${CORE_FILE}
sync

# Close stdin, to tell kernel we are done with dumping core
echo 0>&-

# Wait a bit, so any dmesg info from app exiting ends up in logs
sleep 1

# Collect data again after app has exited, to try to get app exit messages
DumpSysLog
DumpDmesg
DumpNOSInfo

# Agregate all the files into a single tar file
tar -C ${TEMPDIR} -czf ${EXTRAS_FILE}.new .
rm -fr ${TEMPDIR}/*
sync
mv ${EXTRAS_FILE}.new ${EXTRAS_FILE}

# Especially for the case where this ends up in the userdata files, make it possible for 
# someone to delete the crash logs through NOSApp gui
chown $(stat -c %U:%G ${CORE_DUMP_ROOT_DIRECTORY}) ${CORE_FILE}
chmod a+rw ${CORE_FILE}
chown $(stat -c %U:%G ${CORE_DUMP_ROOT_DIRECTORY}) ${EXTRAS_FILE}
chmod a+rw ${EXTRAS_FILE}
sync

if [ ! -z $NEED_REMOUNT_RO ]; then
    mount -o ro,remount ${MOUTPOINT}
fi

rm $NAVICO_COREDUMP_FLAG

EndUserFeedback
