#!/bin/sh
#
# ktune		ktune sysctls
#
# chkconfig: - 27 99
# description:	Applies and reverts ktune sysctl settings
#
# config: /etc/sysctl.ktune
# config: /etc/sysconfig/ktune
#

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

# Source ktune configureation.
if [ -f /etc/sysconfig/ktune ] ; then
    . /etc/sysconfig/ktune
else
    echo -n $"$0: /etc/sysconfig/ktune does not exist."; warning; echo
    exit 5
fi

VAR_SUBSYS_KTUNE=/var/lock/subsys/ktune
SAVE_FILE="/var/run/ktune.save"
SYSCTL_SET="/sbin/sysctl -q -w "
SYSCTL_GET="/sbin/sysctl -e"

KERNEL_ELEVATOR="cfq"
/bin/fgrep -q 'elevator=' /proc/cmdline
CMDLINE_ELEVATOR=$?
if [ -n "$ELEVATOR_TUNE_DEVS" ]; then
	SYS_BLOCK_SDX=
	for file in $(eval LANG=C /bin/ls -1d "${ELEVATOR_TUNE_DEVS}" 2>/dev/null); do
		if ! expr match $(readlink -f "$file") '^/sys/.*/queue/scheduler$' >/dev/null; then
			printf $"$0: '%s' is not a scheduler control file." "$file"
			warning; echo
		else
			SYS_BLOCK_SDX="$SYS_BLOCK_SDX $file"
		fi
	done
else
	SYS_BLOCK_SDX=
fi

declare -a KTUNE_FILES
if [ -r "$SYSCTL" ]; then
    KTUNE_FILES[0]="$SYSCTL"
fi
if [ "x$USE_KTUNE_D" = "xyes" ]; then
    while read file; do
	[ -r "$file" ] || continue
	KTUNE_FILES[${#KTUNE_FILES[*]}]="${file}"
    done <<EOF 
$(LANG=C /bin/ls -1 /etc/ktune.d/*.conf 2>/dev/null)
EOF
fi

function is_int
{
  [ ! -z "${1##*[^0-9]*}" ]
}

load_file() {
    local file=$1
    local save=$2
    local curr_value

    ret_s=0
    errors=
    # apply ktune settings
    while read line; do
	[ "${line:0:1}" == "#" -o "${line:0:1}" == ";" ] && continue
	[ -z "$line" ] && continue

	key=$(echo $line | awk '{ match($0,"[ \t]*=[ \t]*") && $0=substr($0,1,RSTART-1); print $0}')
	value=$(echo $line | awk '/=/ { match($0,"[ \t]*=[ \t]*"); $0=substr($0,RSTART+RLENGTH); print $0}')

	curr_value=""
	if [ "${value:0:1}" = '>' ]; then
	    value=${value:1}
	    curr_value=$($SYSCTL_GET -n "$key")
	fi

	if [ "${value:0:1}" = '$' ]; then
	    value=${value:1}
	    value=${!value}
	fi

	is_int "$curr_value" && is_int "$value" && [ "$value" -lt "$curr_value" ] && value="$curr_value"

	[ $save -ne 0 ] && save_value=$($SYSCTL_GET "$key")

	setting=$key
	if [ "$value" ]; then
	    [ -n "$value" ] && setting+="=${value}"

	    error="$($SYSCTL_SET "${setting}" 2>&1)"
	    ret=$?
	    if [ $save -ne 0 -a $ret -eq 0 ] && ! grep -q "^${key} =" $SAVE_FILE 2>/dev/null; then
	        echo "$save_value" >> "$SAVE_FILE"
	    fi
	    [ -n "$error" ] && errors+="${error}\n"

	    let ret_s+=$ret
	fi
    done < "$file"

    if [ $ret_s -eq 0 ]; then
	success; echo
    else
	failure; echo; ret=1
	echo -e "$errors" | while read line; do echo -e "  ${line}"; done
    fi
}

call_script() {
    local script=$1
    local option=$2

    if [ -x "$script" ]; then
	echo -n "Calling '$script $option': "
	("$script" "$option")
	ret=$?

	if [ $ret -eq 0 ]; then
	    success; echo
	else
	    failure; echo; ret=1
	fi
    fi
}

load_sysctl() {
    # Remove save file
    /bin/rm -f "$SAVE_FILE"

    if [ ${#KTUNE_FILES[@]} -gt 0 ]; then
        # Apply general sysctl settings beforehand
	for f in $SYSCTL_PRE; do
	    if [ -r "$f" ]; then
		echo $"Applying sysctl settings from $f"
		sysctl -e -p "$f" >/dev/null 2>&1
	    fi
	done

	echo $"Applying ktune sysctl settings:"

	# Apply ktune files.
	for file in "${KTUNE_FILES[@]}"; do
	    echo -n $"$file: "
	    load_file "$file" 1
	    call_script "${file%.conf}.sh" start
	done

        # Apply general sysctl settings afterwards
	for f in $SYSCTL_POST; do
	    if [ -r "$f" ]; then
		echo $"Applying sysctl settings from $f"
		sysctl -e -p "$f" >/dev/null 2>&1
	    fi
	done
    fi
}

revert_sysctl() {
    if [ -r "$SAVE_FILE" ]; then
	echo -n $"Reverting to saved sysctl settings: "
	load_file "$SAVE_FILE" 0
	/bin/rm -f "$SAVE_FILE"
    fi

    if [ ${#KTUNE_FILES[@]} -gt 0 ]; then
	for file in "${KTUNE_FILES[@]}"; do
	    call_script "${file%.conf}.sh" stop
	done
    fi
}

start() {
    [ "$EUID" != "0" ] && exit 4
    ret=0

    # if no elevator on command line, apply the ktune elevator
    if [ -n "$ELEVATOR" -a -n "$SYS_BLOCK_SDX" -a $CMDLINE_ELEVATOR -ne 0 ]; then
	ret_e=0
	echo -n $"Applying ${ELEVATOR} elevator: "
	for i in $SYS_BLOCK_SDX; do
	    dev="${i%%/queue*}"; echo -n "${dev##*/} "
	    echo "$ELEVATOR" > "$i" 2>/dev/null;
	    let ret_e+=$?
	done
	if [ $ret_e -eq 0 ]; then
	    success; echo
	else
	    failure; echo; ret=1
	fi
    fi

    load_sysctl

    /bin/touch $VAR_SUBSYS_KTUNE
    return $ret
}

reload() {
    [ "$EUID" != "0" ] && exit 4
    revert_sysctl
    load_sysctl
}

stop() {
    [ "$EUID" != "0" ] && exit 4
    ret=0

    revert_sysctl

    # if no elevator on command line, apply the default elevator
    if [ -n "$ELEVATOR" -a -n "$SYS_BLOCK_SDX" -a $CMDLINE_ELEVATOR -ne 0 ]; then
	ret_e=0
	echo -n $"Reverting to ${KERNEL_ELEVATOR} elevator: "
	for i in $SYS_BLOCK_SDX; do
	    dev="${i%%/queue*}"; echo -n "${dev##*/} "
	    echo "$KERNEL_ELEVATOR" > "$i" 2>/dev/null;
	    let ret_e+=$?
	done
	if [ $ret_e -eq 0 ]; then
	    success; echo
	else
	    failure; echo; ret=1
	fi
    fi

    /bin/rm -f $VAR_SUBSYS_KTUNE
    return $ret
}

status() {
    [ "$EUID" != "0" ] && exit 4

    if [ ! -f "$VAR_SUBSYS_KTUNE" ]; then
	echo $"ktune settings are not applied."
	return 3
    fi

    echo $"Current ktune sysctl settings:"
    if [ -e $SAVE_FILE ]; then
        keys=$(awk '/^[#;]/ { next } /=/ { match($1,"=") && $1=substr($1,1,RSTART-1); print $1 }' "$SAVE_FILE")
        for key in $keys; do
	    $SYSCTL_GET $key
        done
    else
        echo $"None"
    fi

    if [ -n "$ELEVATOR" -a -n "$SYS_BLOCK_SDX" -a $CMDLINE_ELEVATOR -ne 0 ]; then
	echo
	echo $"Current elevator settings:"
	for i in $SYS_BLOCK_SDX; do
	    echo -n "${i}: "; cat "$i"
	done
    fi

    return 0
}

case "$1" in
    start)
	[ -f "$VAR_SUBSYS_KTUNE" ] && exit 0
	start
	RETVAL=$?
	;;
    stop)
	[ -f "$VAR_SUBSYS_KTUNE" ] || exit 0
	stop
	RETVAL=$?
	;;
    reload)
	[ -f "$VAR_SUBSYS_KTUNE" ] && reload
	RETVAL=$?
	;;
    restart|force-reload)
	[ -f "$VAR_SUBSYS_KTUNE" ] && stop
	start
	RETVAL=$?
	;;
    condrestart|try-restart)
	[ -f "$VAR_SUBSYS_KTUNE" ] || exit 0
	stop
	start
	RETVAL=$?
	;;
    status)
	status
	RETVAL=$?
	;;
    *)
	echo $"Usage: $0 {start|stop|restart|condrestart|status}"
	RETVAL=2
	;;
esac

exit $RETVAL
