#! /bin/bash
# Copyright 2020 Cumulus Networks, Inc.  All rights reserved.

# This command can change from release to release without
# any compatibility promises, and is intended for Cumulus Networks
# support use, and is deliberately not documented.

SUPPORT_PATH="/var/support/"
PRINT_HEADER="/tmp/core_snap_shot_header_needed"
CORED_PROCESS=""
SNAP_SHOT_ROOT_DIR_PATH=""

get_process_name () {
    CORED_PROCESS=$1
    if [[ $1 == sx*  ]]
    then
        CORED_PROCESS="sx_sdk"
    fi
}

# process single core info to list
list_core_file () {
    CORE_FILE_INFO="$2"
    print_header=0
    if test -f "$PRINT_HEADER"
    then
        print_header=1
    fi
    if test -z "$CORE_FILE_INFO"
    then
        SKIP=1
    else
        CORE_FILE=`echo $CORE_FILE_INFO |awk '{split($0,a," "); print a[6]}'`
        TEMP_PROCESS_NAME=`echo $CORE_FILE | awk '{split($0,a,"\/"); print a[3]}' | awk '{split($0,a,"\."); print a[1]}'`
        CORED_PROCESS=""
        get_process_name "$TEMP_PROCESS_NAME"
        if [ $print_header -ne 0 ]
        then
            printf "\n"
            header_process="Cored Process"
            header_cl_sup="Cl support file"
            printf '%-15s: %s\n' "$header_process" "$header_cl_sup"
            printf "=%.0s"  $(seq 1 63)
            printf "\n"
            rm -rf  ${PRINT_HEADER}
        fi
        printf '%-15s: %s\n' "$CORED_PROCESS" "$1"
        return 0
    fi
    return $2
}

# process all cores in a single cl_support to list
list_all_core_files_in_support () {
    tar -tvf "${1}"| grep -v gdb| awk '/\.core/{ print $0  }' | while read line
    do
        list_core_file $1 "$line"
    done
}
# function to list all core cl_support files
list_all_core_files () {
    touch ${PRINT_HEADER}
    for sup in "$SUPPORT_PATH"cl_supp*.txz
    do
        list_all_core_files_in_support "$sup"
    done
    if test -f "$PRINT_HEADER"
    then
        rm -rf  ${PRINT_HEADER}
    fi
}

#generate snap shot for a core
generate_core_snapshot() {
    CORE_FILE_INFO="${3}"
    if test -z "$CORE_FILE_INFO"
    then
        echo "Core File not found"
    else
        CORE_FILE=`echo $CORE_FILE_INFO |awk '{split($0,a," "); print a[6]}'`
        TEMP_PROCESS_NAME=`echo $CORE_FILE | awk '{split($0,a,"\/"); print a[3]}' | awk '{split($0,a,"\."); print a[1]}'`
        CORED_PROCESS=""
        get_process_name "$TEMP_PROCESS_NAME"
        TEMP=`echo $2 | awk '{split($0,a,"\."); print a[1]}'`
        SNAP_SHOT_ROOT_DIR="snap_shot_${TEMP}"
        SNAP_SHOT_ROOT_DIR_PATH="${SUPPORT_PATH}${SNAP_SHOT_ROOT_DIR}"
        if test -d "$SNAP_SHOT_ROOT_DIR_PATH"
        then
            snap_shot_core_dir_present=1
        else
            mkdir "$SNAP_SHOT_ROOT_DIR_PATH"
            if [ $? -ne 0 ]
            then
                echo "Not able to create snap shot directory"
                exit
            fi
            net show version > "${SNAP_SHOT_ROOT_DIR_PATH}"/net_show_version.txt
        fi

        SNAP_SHOT_DIR="/${CORED_PROCESS}"
        SNAP_SHOT_DIR_PATH="${SNAP_SHOT_ROOT_DIR_PATH}${SNAP_SHOT_DIR}"
        CORED_BIN_PATH=`ps -ef | grep $CORED_PROCESS | grep -v grep | awk '{split($0,a," "); print a[8]}'`

        mkdir "$SNAP_SHOT_DIR_PATH"
        echo "Copying core..."
        tar -xvf "${1}" -C "${SNAP_SHOT_DIR_PATH}" "$CORE_FILE"

        if test -z "$CORED_BIN_PATH"
        then
            printf '%-15s: %s , bin path not found\n' "${CORED_PROCESS}" "${CORE_FILE_INFO}" > "${SNAP_SHOT_DIR_PATH}"/binary_file.txt
        else
            echo "Copying libs..."
            ldd ${CORED_BIN_PATH} | cut -d' ' -f3 | xargs -I {} readlink -f {} | xargs -I{} cp -L --parents {} ${SNAP_SHOT_DIR_PATH}
            echo "Copying cored binary..."
            cp ${CORED_BIN_PATH}                ${SNAP_SHOT_DIR_PATH}/

            GDB_CHECK=`which -a gdb`

            if test -z "$GDB_CHECK"
            then
                echo "gdb is not installed"
                echo "gdb is not installed" > "${SNAP_SHOT_DIR_PATH}"/gdb_not_installed.txt
            else
                echo "getting trace back"
                gdb ${CORED_BIN_PATH} "${SNAP_SHOT_DIR_PATH}/${CORE_FILE}"  -ex 'set height 0' -ex 'set width 0' -ex 'thread apply all backtrace full' -ex quit > "${SNAP_SHOT_DIR_PATH}"/backtrace.log
            fi
        fi

    fi
}

#generate snapshot for all the cores in a single cl support and tar it
generate_all_cores_snapshot () {
    core_file_info="/tmp/core_file_info"
    tar -tvf "${1}"| awk '/\.core/{ print $0   }' > $core_file_info
    while IFS= read -r line
    do
        generate_core_snapshot "${1}" "${2}" "$line"
    done < $core_file_info

    if test -d "$SNAP_SHOT_ROOT_DIR_PATH"
    then
        archive_name="${SNAP_SHOT_ROOT_DIR}".txz
        XZ_OPT=-2q tar -J -c -b 128 -f $archive_name --warning=no-file-changed \
        --mode=+r  ${SNAP_SHOT_ROOT_DIR}
        rm -rf  ${SNAP_SHOT_ROOT_DIR}
        echo
        printf 'Snapshot Generated at %s\n' "${SUPPORT_PATH}${SNAP_SHOT_ROOT_DIR}.txz"
        
    fi
}


process_core_snapshot_req() {
    CL_FILE_NAME=`echo "${2}" | awk '{split($0,a,"\/"); print a[4]}'`
    if test -z "$CL_FILE_NAME"
    then
        CL_FILE_NAME="${2}"
    fi
    cl_sup_file_path="${1}${CL_FILE_NAME}"

    if test -f "$cl_sup_file_path"
    then
        generate_all_cores_snapshot $cl_sup_file_path $CL_FILE_NAME
    fi

}


display_help() {
    printf "\n"
    header_option="Option"
    header_desc="Description"
    echo "Options available"
    printf '%-10s: %s\n' "$header_option" "$header_desc"
    printf "=%.0s"  $(seq 1 63)
    printf "\n"
    printf '%-10s: %s\n' "-l" "Lists name of the processes cored and it's cl_support file"
    printf '%-10s: %s\n' "-s" "Saves snapshot of the process cored. cl_support file needed as an argument"

}




main()
{
    if [ `whoami` != 'root' ]
    then
        echo "Only super user can run this."
        exit
    fi
    local arch
    prog=${0##*/}
    export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/cumulus/bin

    cd $SUPPORT_PATH
    __LIST__=0
    __SNAP_SHOT__=0
    PARAMS=""

    if [ $# -eq 0  ]
    then
        display_help
    fi



    while (( "$#" )); do
    case "$1" in
        -l|--list-core-files)
            list_all_core_files
            __LIST__=1
        shift
            ;;
        -h|--help-)
            display_help
        shift
            ;;
        -s|--save-snapshot-for-specified-core)
        if [ -n "$2" ]
            then
                process_core_snapshot_req "$SUPPORT_PATH" $2
            else
                echo "Support file name needed"
                display_help
            fi
            shift
            ;;
        -*|--*=)
            echo "Error: Unsupported option $1" >&2
            display_help
            exit 1
            ;;
        *) # preserve positional arguments
            PARAMS="$PARAMS $1"
            shift
            ;;
        esac
            done
# set positional arguments in their proper place
    eval set -- "$PARAMS"
}



main "$@"
