#! /bin/sh
#
#  Copyright 2005 Red Hat, Inc.
#  Author:  Jeff Moyer <jmoyer@redhat.com>
#  Modifications for SUSE from Chris Mason <mason@suse.com>
#                              Takashi Iwai <tiwai@suse.de>
#
#  kdump
#
#  Description:  The kdump init script provides the support necessary for
#  		 loading a kdump kernel into memory at system bootup time,
#		 and for copying away a vmcore at system panic time.
#
#
# /etc/init.d/kexec
### BEGIN INIT INFO
# Provides:       kdump
# Required-Start: boot.localfs $remote_fs
# Should-Start:   
# Required-Stop:  
# Default-Start:  1 2 3 5
# Default-Stop:
# Description:    kdump core saving and boot configuration
### END INIT INFO

. /etc/sysconfig/kdump
. /etc/rc.status

KEXEC=/sbin/kexec

BOOTDIR="/boot"

# purge old dump directories if the number of directories
# exceeds $KDUMP_KEEP_OLD_DUMPS
purge_old_dumps()
{
    dirs=`ls -d $KDUMP_SAVEDIR/*-*-*-*:* 2>/dev/null | sort`
    numdirs=`echo $dirs | wc -w`
    for d in $dirs; do
	if [ $numdirs -le $KDUMP_KEEP_OLD_DUMPS ]; then
	    break;
	fi
	echo " Expiring old dump $d"
	rm -rf $d
	numdirs=`expr $numdirs - 1`
    done
}

# get the free disk space of the given directory in MB
parse_rest_size()
{
    test -d "$1" || mkdir -p "$1"
    hdread=""
    df -P "$1" | while read fs bl us av rest; do
	test -n "$hdread" && echo $av
	hdread="$fs"
    done
}

# get memory size in kB
get_mem_size()
{
    while read tag size kb; do
	if [ "$tag" = "MemTotal:" ]; then
	    echo "$size"
	    break
	fi
    done < /proc/meminfo
}

# The default dumper
#
# Clean up old stuff if necessary, check the free size
# and save the vmcore
save_core()
{
    if [ $KDUMP_KEEP_OLD_DUMPS -gt 0 ]; then
	purge_old_dumps
    fi

    if [ $KDUMP_FREE_DISK_SIZE -gt 0 ]; then
	restsize=`parse_rest_size "$KDUMP_SAVEDIR"`
	restsize=`expr $restsize / 1024`
	needsize=`get_mem_size`
	needsize=`expr $needsize / 1024 + $KDUMP_FREE_DISK_SIZE`
	if [ $restsize -lt $needsize ]; then
	    echo -n " No enough space left on dump device ($restsize MB)"
	    rc_status -s
	    rc_failed 6
	    return
	fi
    fi

    coredir="${KDUMP_SAVEDIR}/`date +"%Y-%m-%d-%H:%M"`"
    mkdir -p $coredir
    echo -n "Saving crash dump to $coredir"
    cp --sparse=always /proc/vmcore $coredir/vmcore
    rc_status -v
}

# Load the kdump kerel specified in /etc/sysconfig/kdump
# If none is specified, try to load a kdump kernel with the same version
# as the currently running kernel.
load_kdump()
{
    echo -n "Loading kdump "
    if [ -z "$KDUMP_KERNELVER" ]; then
	kdump_kver=`uname -r | sed 's/-smp//g'`
	kdump_kver="${kdump_kver}-kdump"
    else
	kdump_kver=$KDUMP_KERNELVER
    fi

    kdump_kernel="${BOOTDIR}/vmlinux-${kdump_kver}"
    kdump_initrd="${BOOTDIR}/initrd-${kdump_kver}"

    if [ ! -f $kdump_kernel ]; then
	echo -n ": No kdump kernel image found." 
	echo "Tried to locate ${kdump_kernel}"
	rc_status -s
	rc_failed 6
	rc_exit
    fi

    if [ ! -f $kdump_initrd ]; then
	echo -n ": No kdump initial ramdisk found."
	echo "Tried to locate ${kdump_initrd}"
	rc_status -s
	rc_failed 6
	rc_exit
    fi

    if [ -z "$KDUMP_COMMANDLINE" ]; then
	KDUMP_COMMANDLINE=`cat /proc/cmdline`
	KDUMP_COMMANDLINE=`echo $KDUMP_COMMANDLINE | sed -e 's/crashkernel=[0-9]\+[mM]\(@[0-9]\+[Mm]\)\?//g' `
	# Use deadline for saving the memory footprint
	KDUMP_COMMANDLINE="$KDUMP_COMMANDLINE elevator=deadline"
	case `uname -i` in
	i?86|x86_64)
	    KDUMP_COMMANDLINE="$KDUMP_COMMANDLINE irqpoll"
            ;;
	esac
    fi
    KDUMP_COMMANDLINE="sysrq=1 $KDUMP_COMMANDLINE"
    if [ -n "$KDUMP_RUNLEVEL" ]; then
	case "$KDUMP_RUNLEVEL" in
	[1-5s])
	    KDUMP_COMMANDLINE="$KDUMP_COMMANDLINE $KDUMP_RUNLEVEL"
	    ;;
	*)
	    echo " : Invalid KDUMP_RUNLEVEL=$KDUMP_RUNLEVEL, ignored"
	    ;;
	esac
    fi

    echo 1 > /proc/sys/kernel/panic_on_oops

    $KEXEC -p $kdump_kernel \
	--append="$KDUMP_COMMANDLINE" \
	--initrd=$kdump_initrd \
	$KEXEC_OPTIONS

    rc_status -v
}

case "$1" in
  start)
	if [ -f /proc/vmcore ]; then
	    if [ -n "$KDUMP_TRANSFER" ]; then
		$KDUMP_TRANSFER
	    else
		save_core
	    fi
	    if test "$KDUMP_IMMEDIATE_REBOOT" = "yes"; then
		/sbin/reboot
		# sleep to avoid the conflict with script "single"
		sleep 600
	    fi
        else
	    load_kdump
	fi
	;;
  stop)
	if [ ! -f /proc/vmcore ]; then
	    echo -n "Unloading kdump"
	    $KEXEC -u
	    rc_status -v
	fi
	;;
  status)
	echo "not implemented"
	;;
  restart|reload)
	$0 stop
	$0 start
	;;
  condrestart)
	;;
  *)
	echo $"Usage: $0 {start|stop|status|restart|reload}"
	exit 1
esac

exit $?
