#!/bin/sh
#------------------------------------------------------------------
#
# S04mvcorecheck - Check for previous system failure
#
# Feb 2016 Joel Aller - Move/ported from S10boot
#
# Copyright (c) 2016 by cisco Systems, Inc.
# All rights reserved.
#------------------------------------------------------------------
#set -x


system_reboot() {
    board_type="`cat /MERAKI_BOARD`"
    echo "Rebooting system."
    if [ "$board_type" == "axel-qca" -o "$board_type" == "axel-bcm" ]; then
        mkdir -p /part2 && mount /dev/ubivol/part2 /part2 && cd / && ln -s /part2/storage
    fi
    RELOAD_REASON="kernel_core_dump"
    /sbin/reboot -r "$RELOAD_REASON"
}

enable_usb_in_normal_mode () {
    # Try for 10 seconds for enable file system
    count=0
    while [ ! -f /sys/class/nolan/usb.0/enable ]; do
        sleep 1
        count=`expr $count + 1`
        if [ $count -gt 10 ]; then
            break;
        fi
    done
    if [ -f /sys/class/nolan/usb.0/enable ]; then
        echo 1 > /sys/class/nolan/usb.0/enable
    else
        logger -p user.notice -s "Cisco-Kexec cannot find usb enable files"
    fi
    # Try for 10 seconds for authorized file system
    count=0
    while [ ! -f /sys/bus/usb/devices/1-1/authorized -a  \
            ! -f /sys/bus/usb/devices/3-1/authorized ]; do
        sleep 1
        count=`expr $count + 1`
        if [ $count -gt 10 ]; then
            break;
        fi
    done
    if [ -f /sys/bus/usb/devices/1-1/authorized -o  \
         -f /sys/bus/usb/devices/3-1/authorized ]; then
        { echo 1 > /sys/bus/usb/devices/1-1/authorized ; } > /dev/null 2>&1
        { echo 1 > /sys/bus/usb/devices/3-1/authorized ; } > /dev/null 2>&1
    else
        logger -p user.notice -s "Cisco-Kexec cannot find usb authorized files"
    fi
}
enable_usb_in_crash_mode () {
    # Try for 10 seconds for authorized file system
    count=0
    while [ ! -f /sys/bus/usb/devices/1-1/authorized -a  \
            ! -f /sys/bus/usb/devices/3-1/authorized ]; do
        sleep 1
        count=`expr $count + 1`
        if [ $count -gt 10 ]; then
            break;
        fi
    done
    if [ -f /sys/bus/usb/devices/1-1/authorized -o  \
         -f /sys/bus/usb/devices/3-1/authorized ]; then
        { echo 1 > /sys/bus/usb/devices/1-1/authorized ; } > /dev/null 2>&1
        { echo 1 > /sys/bus/usb/devices/3-1/authorized ; } > /dev/null 2>&1
    else
        echo "Cisco-Kexec cannot find authorized files"
    fi
}

mount_usb() {
    # Check if external USB storage exists, if it does, copy core there
    USBSTORAGEDRV=/lib/modules/usb-storage.ko
    if [ -e $USBSTORAGEDRV ]; then
        insmod $USBSTORAGEDRV
    fi
    #sleep 10 # Wait for USB enumeration
    count=0
    while [ ! -e /dev/sda ]; do
        sleep 1
        count=`expr $count + 1`
        if [ $count -gt 10 ]; then
            break;
        fi
    done
    # Try for 5 more seconds for partition node to show up
    count=0
    while [ ! -e /dev/sda1 ]; do
        sleep 1
        count=`expr $count + 1`
        if [ $count -gt 5 ]; then
            break;
        fi
    done
    mkdir -p /mnt/usb
    usbdev=""
    #Assume USB storage has partiton. Try to mount partition
    for dev in `ls /dev | grep "^sd[a-z][1-9]$"`; do
        mount /dev/$dev /mnt/usb/ > /dev/null 2>&1
        if [[ "$?" -eq "0" ]]; then
            usbdev="/dev/$dev"
            break;
        fi
    done
    if [[ -z "$usbdev" ]]; then
        #Assume USB storage does not have partition and try non-partition mount
        for dev in `ls /dev | grep "^sd[a-z]$"`; do
            mount /dev/$dev /mnt/usb/ > /dev/null 2>&1
            if [[ "$?" -eq "0" ]]; then
                usbdev="/dev/$dev"
                break;
            fi
        done
    fi
    if [[ -z "$usbdev" ]]; then
        logger -p user.notice -s "Cisco-Kexec cannot find usb storage device node"
    fi
    echo "$usbdev"
}

if [ -s /proc/vmcore ]; then
    # Start watchdog petting in background for 3 minutes
    # When program pethwdog exits, the hw watchdog is running
    # Nocode will pet Hw watchdog and it will reboot the system
    # for hang cases
    /usr/bin/pethwdog &

    echo "----------------------" > /dev/console
    echo "Starting kernel dump from previous failure." > /dev/console
    echo "Expected completion time is about 5 minutes." > /dev/console
    echo "System will automatically reboot soon." > /dev/console
    echo "----------------------" > /dev/console
    echo
    sleep 1

    # --------------------------------------
    # compress and copy the core
    # --------------------------------------
    COREDIR=/storage/kcore
    USBDEV=""
    corename="ABC"
    if $(cat /proc/cmdline | grep -q corename); then
        corename=$(cat /proc/cmdline | sed 's/^.*corename=//' | cut -d" " -f1)
    fi
    enable_usb_in_crash_mode 
    USBDEV=$(mount_usb)
    if [[ -n "$USBDEV" ]]; then
        echo "External USB storage found! Dumping core on /dev/$dev"
        COREDIR=/mnt/usb
    else
        echo "External storage not found"
        echo "Skipping core dump creation"
        # Reboot here, skip creating core on /storage
        system_reboot
    fi
    mkdir -p ${COREDIR}
    KCORE_TS=$(date +%Y%m%d_%H%M%S)
    CORENAME=${COREDIR}/${corename}
    echo "kdump core filename: " ${CORENAME}
    START_KCORE=$(date +%s)
    makedumpfile -c --message-level 31 -d 31 /proc/vmcore ${CORENAME}.TEMP_IN_PROGRESS
    #cat /proc/vmcore | gzip - > ${CORENAME}.TEMP_IN_PROGRESS
    if [ "$?" -ne "0" ]; then
        echo "Kdump failed to finish the core dump, please check if out of space " > /dev/console
        df $USBDEV > /dev/console
        ls -l $CORENAME > /dev/console
        echo "Deleting the incomplete core file" > /dev/console
        rm -f $CORENAME.TEMP_IN_PROGRESS
    else
        END_KCORE=$(date +%s)
        corefile_name=${CORENAME}.TEMP_IN_PROGRESS
        mv ${CORENAME}.TEMP_IN_PROGRESS ${CORENAME}
        echo "kdump core finished:took $(( ${END_KCORE} - ${START_KCORE} )) seconds"
    fi
    sync
    # Unmount USB storage before rebooting
    if [[ -n "$USBDEV" ]]; then
        umount $USBDEV
    fi
    system_reboot
else
    if grep -l 'Crash' /proc/iomem > /dev/null; then
        ARCH=`uname -m`
        if [ "$ARCH" == "aarch64" ]; then
            IMG_NAME=Image.lzma
            #IGONORE_OPT=-i
        else
            # Kernel image size. Find this size from System.map (_end - _text)
            # This can be extracted at run time
            # "cat /proc/iomem" Kernel data-end - Kernel code-start
            # Kernel code
            #  08008000-0899701b : Kernel code
            #  089ee000-08fc7137 : Kernel data
            #  size = 0x08fc7137 - 08008000
            IMAGESIZE=0x1000000
            if [ -f  /proc/atags ]; then
                ATAGS="--atags"
                IMAGESIZE=0x1000000
            fi
            IMAGESIZE_CMD=--image-size=${IMAGESIZE}
            IMG_NAME=zImage
        fi
        if [ -f  /storage/BOOT_COUNT ]; then
            bootcnt=-`cat /storage/BOOT_COUNT`-

        fi
        VER=`uname -r`
        ap_name=`cat /proc/sys/kernel/hostname`
        if [ "$ap_name" == "localhost" ]; then
            CAPWAP_CONFIG_FILE=/storage/base_capwap_cfg_info
            ap_name=`cat $CAPWAP_CONFIG_FILE | grep node_name | cut -d" " -f2`
            [ -z "$ap_name" ] && ap_name=`uname -n`
            ap_name=`echo $ap_name | sed 's/[:|;|?|!|\||\\|\/]//g'` # remove illegal symbols
        fi
        capwap_version=`cat /CAPWAP_VERSION`
        KDUMP_NAME="corename=${ap_name}${bootcnt}kernel-core-`date -I`-`date +"%H-%M-%S"`"
        KDUMP_COMMANDLINE_APPEND="irqpoll maxcpus=1 cgroup_disable=memory reset_devices root=/dev/ram incrashk"
        KDUMP_COMMANDLINE=`cat /proc/cmdline`
        KDUMP_COMMANDLINE=`echo $KDUMP_COMMANDLINE | sed -e 's/crashkernel=[^ ]*//'`
        KDUMP_COMMANDLINE=`echo $KDUMP_COMMANDLINE | sed -e 's/activepart=[^ ]*//'`
        KDUMP_COMMANDLINE=`echo $KDUMP_COMMANDLINE | sed -e 's/activeboot=[^ ]*//'`
        KDUMP_COMMANDLINE=`echo $KDUMP_COMMANDLINE | sed -e 's/ckernel=[^ ]*//'`
        #KDUMP_COMMANDLINE=`echo $KDUMP_COMMANDLINE | \
        #                     sed -e 's/usbcore.authorized_default=0/usbcore.authorized_default=1/'`
        KDUMP_COMMANDLINE="${KDUMP_COMMANDLINE} ${KDUMP_COMMANDLINE_APPEND} ${KDUMP_NAME}"
        #echo "kexec -d -p /kexec/zImage --initrd=/kexec/kexec.cpio.lzma \
        #    --command-line="$KDUMP_COMMANDLINE" ${IMAGESIZE_CMD} ${ATAGS}"
        kexec ${IGONORE_OPT} -p /kexec/${IMG_NAME} --initrd=/kexec/kexec.cpio.lzma \
            --command-line="$KDUMP_COMMANDLINE" ${IMAGESIZE_CMD} ${ATAGS}

        #Tell nolan module not to disable the USB even if controller has requested disabled
        if [ -f /usr/cisco/bin/sys_condition_func.sh ]; then
            . /usr/cisco/bin/sys_condition_func.sh
        fi
        set_usb_health_str "Crash kernel enabled"
        mkdir -p /var/sys_condition
        touch /var/sys_condition/usb_enable_ckernel

        #Mount USB for show flash
        enable_usb_in_normal_mode
        USBDEV=$(mount_usb)
    fi
    rm -f /kexec/zImage /kexec/kexec.cpio.lzma /kexec/Image /usr/sbin/makedumpfile /kexec/Image.lzma
fi

exit 0
