#!/bin/sh

set -x

exec 2>/tmp/navico-coredump.log >&2

GetConfiguration()
{
    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-${coredump_pid}
    SEQUENCE_FILE=/home/nos/sequence.ini
    MINIMUM_THRESHOLD=100000
    NAVICO_COREDUMP_FLAG=/tmp/navico_coredump_active

    if [ -e /etc/navico-coredump.conf ]; then
        . /etc/navico-coredump.conf
    fi
    
    NAVICO_COREDUMP_FLAG="${NAVICO_COREDUMP_FLAG}-${coredump_pid}"
}

GetCommandLineArguments()
{
  while [ $# -gt 0 ]; do
    case $1 in
      --exec=*)
      coredump_thread_name=${1#--exec=}
      coredump_thread_name=${coredump_thread_name//:/_}
      ;;
      --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
}

DumpBootVer()
{
  strings -n7 </dev/mtd0ro | sed -ne 's/.*\(U-Boot [^)]*)\).*/\1/p' | sort | uniq > $TEMPDIR/uboot
}

DumpProcfs()
{
    local dest="$TEMPDIR/proc"
    mkdir -p "$dest"

    cp -a /proc/cpuinfo /proc/navico_platform "$dest"

    dest="$dest/app"
    mkdir -p "$dest"
    
    # Store open file list
    ls -la --color=never /proc/${coredump_pid}/fd > "$dest/fd"

    # Files and links in /proc/PID/
    find "/proc/${coredump_pid}" -maxdepth 1 -type f -o -type l | while read; do
	local file="$REPLY" f_base=$(basename "$REPLY")
      
	if [ -L "$file" ]; then
	    # Symlinks - just store what theyre pointing to
	    readlink "$file" > "$dest/$f_base"
	    
	elif [ -r "$file" ]; then
	    # Readable files (some are write-only)
	    case "$f_base" in
		mem|clear_refs)
		    : # Files to ignore
		    ;;
		pagemap)
		    gzip -c "$file" > "$dest/${f_base}.gz"
		    ;;
		cmdline|environ)
		    strings "$file" > "$dest/$f_base"
		    ;;
		*)
		    # TODO The -r test doesnt appear to work with busybox
		    # Until that bug is fixed, add "|| true" to cover non-readable files
		    cp -a "$file" "$dest/" || true
		    ;;
	    esac
	fi
    done
}

SpaceAvailable()
{
    space_available=$(df -kP $1 | grep $1 | awk '{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
}

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

GetCommandLineArguments $*
GetConfiguration

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
    # The SD card may be remote NFS-mounted in the case of Hatchetfish CPU B.
    for SDPATH in /media/* /mnt/*; 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 [ -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

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

# Collect data before app is closed, in case we die during real core dump
DumpBootVer
DumpProcfs
# Save the data that cant (or wont) be re-captured after application has exited
cp -al ${TEMPDIR} ${TEMPDIR%%/}.saved
DumpSysLog
DumpDmesg

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

# Restore non-changing (or now unavailable) data captured while app was still running
rm -fr ${TEMPDIR}
mv ${TEMPDIR%%/}.saved ${TEMPDIR}

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

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

# Re-collect any data that may have changed after application has exited.
DumpSysLog
DumpDmesg

# Agregate all the files into a single tar file
tar -C ${TEMPDIR} -czf ${EXTRAS_FILE}.new . ${FILE_GRAB_LIST}
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

rm $NAVICO_COREDUMP_FLAG

EndUserFeedback
