#!/bin/bash

# kernel must be adjusted
# echo '|<path to script> %e %E %p %s %t' > /proc/sys/kernel/core_pattern
# parameters with example
# $1 - %e  executable filename (without path prefix)
# $2 - %E  pathname of executable, !usr!bin!vnlk
# $3 - %p  PID of dumped process, 3791
# $4 - %s  number of signal causing dump, 11
# $5 - %t  time of dump, expressed as seconds since the Epoch, 1538560002
# http://man7.org/linux/man-pages/man5/core.5.html

# filtered list seperated by space of executable names for dumps
FILTER="vnlk"
COREPATH='/var/vnlk/cores'

log () {
  logger -p local0.notice -t crash-handler "$1"
}

FILENAME=$1
if [ "$2" = "!usr!bin!vnlk" ]; then
    FILENAME=vnlk
fi

TIMESTAMP=$(date --date=@$5 --rfc-3339=seconds)
SIG_NUM=$4

log "$FILENAME crashed at time $TIMESTAMP with signal $SIG_NUM"

# save dumps only for specific executable names
if [ -z "$(grep -w $FILENAME <<< $FILTER)" ]; then
    log "Executable $FILENAME not in the filter, exiting"
    exit 0
fi

if df|grep /var/log > /dev/null; then
    COREPATH=/var/log/vnlk/cores
fi

[ -d $COREPATH ] || mkdir -p $COREPATH

# check free space on the target device
LIMIT=1000 # MB
TARGET=$(findmnt -n -T $COREPATH | awk '{print $1}')
FREE=$(df --block-size=1048576 --out=target --output=avail | grep "$TARGET " | awk '{print $2}')
log "Free space on target device $TARGET: $FREE MB"

if ((FREE < LIMIT)); then
    log "${FREE}MB left on device ${TARGET}, limit is ${LIMIT}MB, exiting"
    exit 0
fi

ARCHIVE="${COREPATH}/${FILENAME}.zip"

if [ -f $ARCHIVE ]; then
    NOW=`date "+%s"`
    LAST=`date -r $ARCHIVE "+%s"`
    if [[ 'LAST + 1800' -gt NOW ]]; then
        log "$FILENAME crashes too frequently, exiting"
        exit 0
    fi
fi

# Storing extra info
cd /tmp
mkdir extra.$3
top -H -p $3 -b -n 1 > extra.$3/top.log
top -b -n 1 > extra.$3/topall.log
cp /etc/vnlk/vnlk.conf     extra.$3/
cp /var/vnlk/log/vnlk.stat extra.$3/
date > extra.$3/date
vnlk -h|grep -m1 "" > extra.$3/version
ps aux > extra.$3/psaux.log
dmesg > extra.$3/dmesg
cat /proc/cpuinfo > extra.$3/cpuinfo
df -H > extra.$3/df
[ -f /var/log/dpkg.log ] && cp /var/log/dpkg.log extra.$3/
journalctl --no-pager --since "10 min ago" > extra.$3/system.log
who > extra.$3/who
echo $SIG_NUM > extra.$3/signal

rm -f $ARCHIVE
cat /dev/stdin | zip -q -4 $ARCHIVE -
if [ $? -ne 0 ]; then
    rm -f $COREPATH/*
    touch $ARCHIVE
    log "Creating dump for $FILENAME failed, exiting"
    rm -rf extra.$3
    exit 0
fi

echo -ne "@ -\n@=core\n" | zipnote -w $ARCHIVE

zip -grqm -1 $ARCHIVE extra.$3

chmod -R a+rw $COREPATH

log "Core dump archive $ARCHIVE created"
