#!/bin/bash
#
# chkconfig: - 70 08
# description: Loads and unloads the drbd module
#
# Copyright 2001-2010 LINBIT
#
# Philipp Reisner, Lars Ellenberg
#
### BEGIN INIT INFO
# Provides: drbd
# Required-Start: $local_fs $network $syslog
# Required-Stop:  $local_fs $network $syslog
# Should-Start:   sshd multipathd
# Should-Stop:    sshd multipathd
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# X-Start-Before: heartbeat corosync
# X-Stop-After:   heartbeat corosync
# Short-Description:    Control drbd resources.
### END INIT INFO

DEFAULTFILE="/etc/default/drbd"
DRBDADM="/sbin/drbdadm"
DRBDSETUP="/sbin/drbdsetup"
PROC_DRBD="/proc/drbd"
MODPROBE="/sbin/modprobe"
RMMOD="/sbin/rmmod"
UDEV_TIMEOUT=10
ADD_MOD_PARAM=""

if [ -f $DEFAULTFILE ]; then
  . $DEFAULTFILE
fi

test -f $DRBDADM || exit 5

# we only use these two functions, define fallback versions of them ...
log_daemon_msg() { echo -n "${1:-}: ${2:-}"; }
log_end_msg() { echo "."; }
# ... and let the lsb override them, if it thinks it knows better.
if [ -f /lib/lsb/init-functions ]; then
    . /lib/lsb/init-functions
fi

function assure_module_is_loaded
{
    [ -e "$PROC_DRBD" ] && return

    $MODPROBE -s drbd `$DRBDADM sh-mod-parms` $ADD_MOD_PARAM || {
	echo "Can not load the drbd module."$'\n'; exit 20
    }
    # tell klogd to reload module symbol information ...
    [ -e /var/run/klogd.pid ] && [ -x /sbin/klogd ] && /sbin/klogd -i
}

function adjust_with_progress
{
    IFS_O=$IFS
    NEWLINE='
'
    IFS=$NEWLINE
    local res out

    COMMANDS=`$DRBDADM -d -n res adjust all` || exit 20
    echo -n "[ "

    for CMD in $COMMANDS; do
	case "$CMD" in
		res=*)		eval "$CMD";;
		*\ disk\ *)
			# Check for offline resize. If using internal meta data,
			# we may need to move it first to its expected location.
				out=$($DRBDADM check-resize "$res" 2>&1)
				[[ -z $out ]] ||
				printf "\n%s\n%s\n" "$res" "$out"
				echo -n "d($res) " ;;
		*\ syncer\ *)	echo -n "s($res) " ;;
		*\ net\ *)	echo -n "n($res) " ;;
		*)		echo ".. " ;;
	esac
	if ! eval "$CMD"; then
	    echo -e "\n[$res] cmd $CMD failed - continuing!\n "
	fi
    done
    echo -n "]"

    IFS=$IFS_O
}

drbd_pretty_status()
{
	local proc_drbd=$1
	# add resource names
	if ! type column &> /dev/null ||
	   ! type paste &> /dev/null ||
	   ! type join &> /dev/null ||
	   ! type sed &> /dev/null ||
	   ! type tr &> /dev/null
	then
		cat "$proc_drbd"
		return
	fi
	sed -e '2q' < "$proc_drbd"
	sed_script=$(
		i=0;
		_sh_status_process() {
			let i++ ;
			stacked=${_stacked_on:+"^^${_stacked_on_minor:-${_stacked_on//[!a-zA-Z0-9_ -]/_}}"}
			printf "s|^ *%u:|%6u\t&%s%s|\n" \
				$_minor $i \
				"${_res_name//[!a-zA-Z0-9_ -]/_}" "$stacked"
		};
		eval "$(drbdadm sh-status)" )

	p() {
		sed -e "1,2d" \
		      -e "$sed_script" \
		      -e '/^ *[0-9]\+: cs:Unconfigured/d;' \
		      -e 's/^\(.* cs:.*[^ ]\)   \([rs]...\)$/\1 - \2/g' \
		      -e 's/^\(.* \)cs:\([^ ]* \)st:\([^ ]* \)ds:\([^ ]*\)/\1\2\3\4/' \
		      -e 's/^\(.* \)cs:\([^ ]* \)ro:\([^ ]* \)ds:\([^ ]*\)/\1\2\3\4/' \
		      -e 's/^\(.* \)cs:\([^ ]*\)$/\1\2/' \
		      -e 's/^ *[0-9]\+:/ x &??not-found??/;' \
		      -e '/^$/d;/ns:.*nr:.*dw:/d;/resync:/d;/act_log:/d;' \
		      -e 's/^\(.\[.*\)\(sync.ed:\)/... ... \2/;/^.finish:/d;' \
		      -e 's/^\(.[0-9 %]*oos:\)/... ... \1/' \
		      < "$proc_drbd" | tr -s '\t ' '  ' 
	}
	m() {
		join -1 2 -2 1 -o 1.1,2.2,2.3 \
			<( ( drbdadm sh-dev all ; drbdadm -S sh-dev all ) | cat -n | sort -k2,2) \
			<(sort < /proc/mounts ) |
			sort -n | tr -s '\t ' '  ' | sed -e 's/^ *//'
	}
	# echo "=== p ==="
	# p
	# echo "=== m ==="
	# m
	# echo "========="
	# join -a1 <(p|sort) <(m|sort)
	# echo "========="
	(
	echo m:res cs ro ds p mounted fstype
	join -a1 <(p|sort) <(m|sort) | cut -d' ' -f2-6,8- | sort -k1,1n -k2,2
	) | column -t
}

# Try to settle regardless of udev version or presence,
# so "/etc/init.d/drbd stop" is able to rmmod, without interfering
# temporary module references caused by udev scanning the devices.
# But don't wait too long.
_udev_settle()
{
	if udevadm version ; then
		# ok, we have udevadm, use it.
		udevadm settle --timeout=5
	else
		# if udevsettle is not there,
		# no matter.
		udevsettle --timeout=5
	fi
}

case "$1" in
    start)
	# Just in case drbdadm want to display any errors in the configuration
	# file, or we need to ask the user about registering this installation
	# at http://usage.drbd.org, we call drbdadm here without any IO
	# redirection.
	$DRBDADM sh-nop
	log_daemon_msg "Starting DRBD resources"
	assure_module_is_loaded
	adjust_with_progress

	# make sure udev has time to create the device files
	for RESOURCE in `$DRBDADM sh-resources`; do
	    for DEVICE in `$DRBDADM sh-dev $RESOURCE`; do
		UDEV_TIMEOUT_LOCAL=$UDEV_TIMEOUT
		while [ ! -e $DEVICE ] && [ $UDEV_TIMEOUT_LOCAL -gt 0 ] ; do
		    sleep 1
		UDEV_TIMEOUT_LOCAL=$(( $UDEV_TIMEOUT_LOCAL-1 ))
		done
	    done
	done

	[ -d /var/lock/subsys ] && touch /var/lock/subsys/drbd	# for RedHat
	$DRBDADM wait-con-int # User interruptible version of wait-connect all

	$DRBDADM sh-b-pri all # Become primary if configured
	log_end_msg 0
	;;
    stop)
	$DRBDADM sh-nop
	log_daemon_msg "Stopping all DRBD resources"
	if [ -e $PROC_DRBD ] ; then
		# bypass drbdadm and drbd config file and everything,
		# to avoid leaving devices around that are not referenced by
		# the current config file, or in case the current config file
		# does not parse for some reason.
		for d in /dev/drbd* ; do
			[ -L "$d" ] && continue
			[ -b "$d" ] || continue
			M=$(umount "$d" 2>&1)
			case $M in
			*" not mounted") :;;
			*) echo "$M" >&2 ;;
			esac
			$DRBDSETUP "$d" down
		done
		_udev_settle &> /dev/null
		$RMMOD drbd
	fi
	[ -f /var/lock/subsys/drbd ] && rm /var/lock/subsys/drbd
	log_end_msg 0
	;;
    status)
	# NEEDS to be heartbeat friendly...
	# so: put some "OK" in the output.
	if [ -e $PROC_DRBD ]; then
	    echo "drbd driver loaded OK; device status:"
	    drbd_pretty_status $PROC_DRBD 2>/dev/null
	    exit 0
	else
	    echo >&2 "drbd not loaded"
	    exit 3
	fi
	;;
    reload)
	$DRBDADM sh-nop
	log_daemon_msg  "Reloading DRBD configuration"
	$DRBDADM adjust all
	log_end_msg 0
	;;
    restart|force-reload)
	( . $0 stop )
	( . $0 start )
	;;
    *)
	echo "Usage: /etc/init.d/drbd {start|stop|status|reload|restart|force-reload}"
	exit 1
	;;
esac

exit 0
