#!/bin/bash
#
# diskdump	This starts, stops, and reloads the diskdump
#		and crashdump facility
#
# chkconfig: - 04 94
# description: Save dump file if previous system crashed and initialize diskdump module.
# config: /etc/sysconfig/diskdump
#
# $Id: diskdump.sh,v 1.53 2005/02/28 21:30:23 akira Exp $

# Source function library.
. /etc/rc.d/init.d/functions

# VERSION is given when "make install" is executed.
VERSION="1.0.1"
SERVICE_NAME=$(basename $0 .sh)
CONF_DISKDUMP="/etc/sysconfig/diskdump"
DISKDUMPFMT="/usr/sbin/diskdumpfmt"
SAVECORE="/usr/sbin/savecore"
DISKDUMPCTL="/usr/sbin/diskdumpctl"
PROC_DISKDUMP="/proc/diskdump"
MODINFO="/sbin/modinfo"
MODPROBE="/sbin/modprobe"
RMMOD="/sbin/rmmod"
SYSFSROOT=$(grep -w sysfs /etc/mtab | cut -d\  -f 2)
KERNEL=$(uname -r | awk '{print substr($0,1,3);}')

# Source Dump Device
if [ -f $CONF_DISKDUMP ]; then
	. $CONF_DISKDUMP
fi

[ -z $DEVICE ] && {
	echo "Device not specified in $CONF_DISKDUMP" >&2
	exit 1
}

RETVAL=0

start_device() {
	local dev=$1

	initlog -c "$DISKDUMPCTL $dev"
	ret=$?
	if [ $ret != 0 ]; then
		return
	fi
}

show_result() {
	local string=$1
	local good=$2
	local bad=$3

	if [ $bad -eq 0 ]; then
		success $string
	elif [ $good -eq 0 ]; then
		failure $string
	else
		warning $string
	fi
	echo
}

start() {
	local dev
	local good_devices
	local bad_devices
	local savecore_devices
	local reformat_devices
	declare -i local good_count=0
	declare -i local bad_count=0

	# Check if diskdump is already running
	status 2> /dev/null
	if [ $? -eq 0 ]; then
		echo "$SERVICE_NAME is already running" >&2
		return
	fi

	initlog -c "$MODPROBE scsi_dump"
#	initlog -c "$MODPROBE ide-dump"

	for dev in $(echo $DEVICE | tr ':' ' '); do
		$DISKDUMPFMT -c $dev
		ret=$?
		case $ret in
		0) good_devices="$good_devices $dev";;
		1) savecore_devices="$savecore_devices $dev";;
		3) reformat_devices="$reformat_devices $dev";;
		*) bad_devices="$bad_devices $dev";;
					# delay error message later
		esac
	done

	if [ ! -z "$savecore_devices" ]; then
		echo "Saving panic dump: " >&2

		for dev in $savecore_devices; do
			initlog -c "$SAVECORE -p $dev"
			if [ $? -eq 0 ]; then
				good_count=good_count+1
				reformat_devices="$reformat_devices $dev"
			else
				bad_count=bad_count+1
				if [ -z $PRESERVEDUMP ]; then
					reformat_devices="$reformat_devices $dev"
				fi
			fi
		done

		show_result "saving" $good_count $bad_count
	fi

	good_count=0; bad_count=0

	if [ ! -z "$reformat_devices" ]; then
		echo "Formatting dump device: " >&2

		$MODPROBE diskdump
		for dev in $reformat_devices; do
			initlog -c "$DISKDUMPFMT -p $dev"
			if [ $? -eq 0 ]; then
				good_devices="$good_devices $dev"
				good_count=good_count+1
			else
				bad_count=bad_count+1
			fi
		done

		show_result "formatting" $good_count $bad_count
	fi

	good_count=0

	echo -n $"Starting diskdump: "
	for dev in $bad_devices; do
		initlog -n "diskdump" -s $"$dev is not a dump device"
		bad_count=bad_count+1
	done
	for dev in $good_devices; do
		start_device $dev
		if [ $ret -eq 0 ]; then
			good_count=good_count+1
		else
			bad_count=bad_count+1
		fi
	done

	show_result "activating" $good_count $bad_count

	if [ $good_count -eq 0 ]; then
		RETVAL=-1
	else
		RETVAL=0
	fi
}

stop_device() {
	local dev=$1

	initlog -c "$DISKDUMPCTL -u $dev"
}

unload_module() {
	if grep ^scsi_dump\  /proc/modules > /dev/null; then
		$RMMOD scsi_dump
	fi
	if grep ^ide-dump\  /proc/modules > /dev/null; then
		$RMMOD ide-dump
	fi
	if grep ^diskdump\  /proc/modules > /dev/null; then
		$RMMOD diskdump
	fi
}

stop() {
	case "$KERNEL" in
	"2.4")
		if [ -f $PROC_DISKDUMP ]; then
			grep -v '^#' $PROC_DISKDUMP | while read dev sector; do
				stop_device $dev
			done
		fi
		;;
	"2.6")
		find $SYSFSROOT -name dump | while read f; do
			exec 3<&0 <$f
			while read dev; do
				stop_device "/dev/$dev"
			done
			exec 0<&3 3<&-
		done
		;;
	*)
		echo "kernel version '$KERNEL' incorrect" >&2
		exit 1
	esac
	unload_module
}

format() {
	opts=$1
	ret=1
	RM_MOD=0

	if [ ! -f $PROC_DISKDUMP ]; then
		$MODPROBE diskdump
		RM_MOD=1
	fi

	for dev in $(echo $DEVICE | tr ':' ' '); do
		$DISKDUMPFMT $opts $dev
		if [ $? -eq 0 ]; then
			ret=0
		fi
	done

	if [ $RM_MOD -eq 1 ]; then
		$RMMOD diskdump
	fi

	if [ $ret -ne 0 ]; then
		echo $opts | grep c > /dev/null
		if [ $? -eq 0 ]; then
			echo "Each device has not been formatted" >&2
		else
			echo "Each format processing failed" >&2
		fi
	fi

	RETVAL=$ret
}

status() {
	if test -f $PROC_DISKDUMP && grep ^[^#] $PROC_DISKDUMP >/dev/null; then
		echo "$SERVICE_NAME enabled" >&2
		RETVAL=0
	else
		echo "$SERVICE_NAME not enabled" >&2
		RETVAL=3
	fi
	return $RETVAL
}

restart() {
	stop
	start
}

version() {
	echo "$SERVICE_NAME version $VERSION" >&2

	exit 0
}

case "$1" in
	start)		start ;;
	stop)		stop ;;
	format)		format -p ;;
	initialformat)	format -fp ;;
	regularformat)	format -ap ;;
	devicestatus)	format -cv ;;
	status)		status ;;
	restart|reload)	restart ;;
	version)	version ;;
	*)
	    echo "Usage: service $SERVICE_NAME {subcommand}
Subcommands:
	start		start $SERVICE_NAME
	stop		stop $SERVICE_NAME
	format		do quick format all dump devices
	initialformat	do initial format all dump devices
	regularformat	do full format all dump devices
	status		show if $SERVICE_NAME is activated
	restart/reload	stop and start $SERVICE_NAME
	devicestatus	show status of all dump devices
	version		show $SERVICE_NAME version information" >&2
	    exit 1
esac

exit $RETVAL
