#!/bin/sh
#
# (c) Bernhard Walle <bwalle@suse.de>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; You may only use version 2 of the License, you have no option to
# use any other version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 675 Mass
# Ave, Cambridge, MA 02139, USA.
#
# --------------------------------------------------------------------------------
#
# Copies the whole kernel including debuginfo to the specified
# directory. That script is meant to be used with kdump so that
# the directory which contains the core file is 'self-contained',
# i.e. contains all files necessary to debug the crash.


KDUMP_SHARED=/usr/share/kdump/kdump-shared_functions
copy_modules=1
verbose=0
kernel_version=$(uname -r)

###############################################################################
# Checks if the files exists we need afterwards
function check_files()
{

    if [ ! -r "$kernelimage" ] ; then
        echo "The kernel image $kernelimage doesn't exist"
        return 1
    fi

    if ! contains_debuginfo ; then
        if [ ! -r "/usr/lib/debug/$kernelimage.debug" ] ; then
            echo "The debug kernel doesn't exist at /usr/lib/debug/$kernelimage.debug"
            echo "Please install the kernel-*-debuginfo package!"
            return 1
        fi
    fi
}

###############################################################################
# Sets arch-specific global variables
function set_arch_specific()
{
    case $(uname -i) in 
        i386|x86_64)
            kernelimage=/boot/vmlinux-$kernel_version.gz
            ;;
        ia64)
            kernelimage=/boot/vmlinuz-$kernel_version
            ;;
    esac
}

###############################################################################
# Sets arch-specific global variables
function copy_kernel()
{
    TARGET=$1

    # look for an uncompressed image first
    if [ -r "/boot/vmlinux-$kernel_version" ] ; then
        cp /boot/vmlinux-$kernel_version $TARGET
        return 0
    fi

    # now look for .gz as common in SUSE packages for i386/x86_64
    if [ -r "/boot/vmlinux-$kernel_version.gz" ] ; then
        zcat "/boot/vmlinux-$kernel_version.gz" > $TARGET/vmlinux-$kernel_version
        return 0
    fi

    # and finally IA64 ...
    if [ $(uname -i) == "ia64" -a "/boot/vmlinuz-$kernel_version" ] ; then
        zcat "/boot/vmlinuz-$kernel_version" > $TARGET/vmlinux-$kernel_version
        return 0
    fi

    return 1
}

###############################################################################
# Copy debug information if necessary
function copy_debuginfo()
{
    local debugfile=
    TARGET=$1

    # look if we really need to copy the debuginfo
    if contains_debuginfo $TARGET/vmlinux-$kernel_version ; then
        return 0
    fi

    debugfile=$(read-debuglink $TARGET/vmlinux-$kernel_version 2>/dev/null)
    if [ -z "$debugfile" ] ; then
        echo "There's no debug information for the kernel"
        echo "doesn't exist. Please install -debuginfo package."
        return 1
    fi

    cp $debugfile $TARGET
}

###############################################################################
# Copies kernel modules
function copy_modules()
{
    TARGET=$1

    # check if we need to copy modules
    if [ $copy_modules -ne 1 ] ; then
        return 0
    fi

    if [ ! -d /lib/modules/$kernel_version/kernel ] ; then
        echo "Modules for kernel $kernel_version don't exist"
        return 1
    fi

    mkdir $TARGET/modules
    cp -r /lib/modules/$kernel_version/kernel $TARGET/modules
}

###############################################################################
# Copies kernel modules with debuginfo
function copy_modules_debuginfo()
{
    TARGET=$1

    # check if we need to copy modules
    if [ $copy_modules -ne 1 ] ; then
        return 0
    fi

    # check if we need debug information
    if contains_debuginfo $1/vmlinux-$kernel_version ; then
        return 0
    fi

    cp -r /usr/lib/debug/lib/modules/$kernel_version/kernel \
        $TARGET/modules
}

###############################################################################
# Outputs a text if verbosity was enabled
function output_verbose()
{
    if [ "$verbose" -eq 1 ] ; then
        echo $1
    fi
}

###############################################################################
# Main

if [ ! -r "$KDUMP_SHARED" ] ; then
    echo "$KDUMP_SHARED missing"
    exit 1
fi
source $KDUMP_SHARED

# parse the command line arguments
while getopts nhr:v name ; do
    case $name in
        n)
            copy_modules=0
            ;;
        r)
            kernel_version="$OPTARG"
            ;;
        v)
            verbose=1
            ;;
        ?)
            echo "Usage:    copy-kernel-kdump [-n] [-r release] targetdir"
            echo
            echo "Options"
            echo "   -n:  don't copy modules, only the kernel image"
            echo "   -r:  use the specified release number instead of the"
            echo "        running kernel version"
            echo "   -v:  be verbose"
            exit 1
    esac
done
shift $(($OPTIND -1))


TARGET=$1
if [ -z "$TARGET" ] ; then
    echo "You have to specify a target directory as first argument"
    exit 1
fi

# check if target directory exists and create it if necessary
if [ ! -d "$TARGET" ] ; then
    if ! mkdir -p "$TARGET" ; then
        echo "The target directory $TARGET doesn't exist and cannot be created"
        return 1
    fi
fi

output_verbose "Copying kernel ..."
if ! copy_kernel $TARGET ; then
    echo "No kernel to copy, aborting"
    exit 1
fi

output_verbose "Copying kernel debuginfo ..."
if ! copy_debuginfo $TARGET ; then
    echo "Cound't copy the debug info of the kernel, aborting"
    exit 1
fi

output_verbose "Copying kernel modules ..."
if ! copy_modules $TARGET ; then
    echo "Cound't copy the kernel modules, aborting"
    exit 1
fi

output_verbose "Copying kernel modules debuginfo ..."
if ! copy_modules_debuginfo $TARGET ; then
    echo "Cound't copy the kernel modules debuginfo, aborting"
    exit 1
fi

exit 0

# vim: set sw=4 ts=4 et:
