#!/sbin/sh
#ident	"@(#)ktool:common/ktool/idtools/idtune	1.20.1.7"
#ident	"$Header:"

# idtune  [ -f | -m ]  [ -c ]	name  value
#
# Attempt to set the value of tunable parameter 'name' to 'value'.
# If a value is already given to this parameter (via stune or autotune), 
# the user will
# be asked to confirm the change unless the -f option is used.
# If the -m option is used, we silently accept existing values greater than
# the new value.
#
# -or-
#
# idtune  -g  [ -c ] name
#
# This form reports the current settings for tunable parameter 'name'.
# A line is output to stdout with four whitespace-separated fields:
#
#	current_value  original_default_value  minimum_value  maximum_value
#
# -or-
#
# idtune  -d  [ -c ]	name
#
# This form restores the tunable parameter 'name' to its default value,
# as given in the mtune file.
#
#
# -or-
#
# idtune -B 
#
# which does the refresh of mtune before a build; normally only called 
# from other idtools, particularly idbuild.  
#
# In any form, if the tunable parameter is not defined (in an mtune file),
# idtune will exit with a non-zero status.
#
#
# In any form, if the -c option is used, the work will done on stune.current
# in addition to stune. stune.current will be used to preconfig all the new
# loadable modules, so these changes will become effective on those loadable modules
# immediately instead of at the next reboot. The -c option should be used with
# caution, because it may cause inconsistent between the static kernel and
# loadable modules.

umask 022

LABEL=UX:idtune
CATALOG=uxidtools
	
usage()
{
	pfmt -l $LABEL -s error -g $CATALOG:210 "Usage: idtune [ -f | -m ] [ -c ] name value\n  -or- idtune -g [ -c ] name\n  -or- idtune -d [ -c ] name\n"
	exit 99
}

del_stune()
{
	name=$1

	if [ ! "$force" ]
	then
		pfmt -l $LABEL -s info -g $CATALOG:211 "Tunable Parameter %s is currently set to %s.\n" "$name" "$cur_value"

		if [ "$isauto" ]
		then
			pfmt -s nostd -g $CATALOG:212 "\tIs it OK to return it to autotuning? (y/n) "
		else
			pfmt -s nostd -g $CATALOG:213 "\tIs it OK to change it to %s? (y/n) " "$new_value"
		fi
		read ans
		case $ans in
			y*|Y*)	;;
			*)	pfmt -s nostd -g $CATALOG:214 "%s left at %s.\n" "$name" "$cur_value"
				exit 0;;
		esac
	fi

	egrep -v "^$name[ 	]" $STUNE > $STUNE.tmp
	mv $STUNE.tmp $STUNE
}

# If parameter already in stune, see if we're allowed to change it.
# Otherwise, append the new value to the end.

ed_stune()
{
	if [ "$sline" ]
	then
		if [ "$dflt" ]
		then
			del_stune $name
			return 0
		fi
		if [ "$cur_value" = "$new_value" ]
		then
			return 0
		fi
		if [ "$min" -a "$numeric" ]
		then
			$IDVAL -g "$cur_value" "$new_value"  >/dev/null
			if [ "$?" -eq "1" ]
			then
				return 0
			fi
		fi
		if [ ! "$force" ]
		then
			pfmt -l $LABEL -s info -g $CATALOG:215 "Tunable Parameter %s is currently set to %s.\n" "$name" "$cur_value"

			pfmt -s nostd -g $CATALOG:216 "\tIs it OK to change it to %s? (y/n) " "$new_value"
			read ans
			case $ans in
				y*|Y*)	;;
				*)	pfmt -s nostd -g $CATALOG:217 "%s left at %s.\n" "$name" "$cur_value"
					exit 0;;
			esac
			echo
		fi
		ed - $STUNE >/dev/null 2>&1 <<-!
			/^$name[ 	]/c
			$name	$new_value
			.
			w
		!
		return $?
	fi
	if [ "$isauto" ]
	then
		if [ ! "$force" ]
		then
			pfmt -l $LABEL -s info -g $CATALOG:218 "Tunable Parameter %s is currently autotuned\n." "$name"
			pfmt -s nostd -g $CATALOG:219 "\tIs it OK to change it to %s? (y/n) " "$new_value"
			read ans
			case $ans in
				y*|Y*)	;;
				*)	pfmt -l $LABEL -s info -g $CATALOG:220 "%s left autotuning.\n" "$name"
					exit 0;;
			esac
			echo
		fi
		echo "$name\t$new_value" >>$STUNE
		return $?
	else
		echo "$name\t$new_value" >>$STUNE
		return $?
	fi
}

new_mtune()
{
	(echo "* Lines ending in \"%%INS%%\" are from mtune.d/*\t%%INS%%"
	echo "* and constructed automatically.\t\t\t%%INS%%"
	echo "* DO NOT edit manually.\t\t\t\t%%INS%%"
	sed '/./s/$/	%%INS%%/' $CONF/mtune.d/*
	if [ -f $MTUNE ]
	then
		egrep -v '^$|%%INS%%$|%%AUTO%%$' $MTUNE
	fi) > $NMTUNE
	mv $NMTUNE $MTUNE
	if [ "$ROOT" = "/" -a -x /sbin/chlvl ]
	then
		chlvl SYS_PRIVATE $MTUNE 2>/dev/null
	fi

	if [ ! -d $CONF/autotune.d ]
	then
		return
	fi

	cd $CONF/cf.d

	if [ ! "$recursive" ]
	then 
		est_mem

		cd $CONF/autotune.d

		echo "* Autotune parameters ------------------- %%AUTO%%" >> $MTUNE
		cat $ROOT/etc/conf/autotune.d/* | egrep -v "^#|^\*|^[ 	]*$" > $ATUNE
		$IDREADAUTO -r $ROOT -t $tunemem >> $MTUNE
	fi
	
	return 
	
}

est_mem()
{
		if [ ! "$MEMSIZE" ]
		then
			tunemem=0
			return
		fi
		
		maxpmem=`$IDTUNE -g -r MAXPMEM | awk '{print $1}'`

		if [ $? -eq 0 ]
		then
			if [ $maxpmem -ne 0 ]
			then
				if [ $maxpmem -lt $MEMSIZE ]
				then
					MEMSIZE=$maxpmem
				fi
			fi
		fi
		
		tunemem=$MEMSIZE
}

auto_calc_curve()
{
	name=$1

	grep "^$name[ 	]" $ROOT/etc/conf/autotune.d/$MODNAME | sort +3n > $ATUNE

	if [ -f $NSTUNE ]
	then
		SPECIFIED=`grep "^$name[ 	]" $NSTUNE`
	fi

	if [ "$SPECIFIED" ]
	then
		echo $SPECIFIED | $IDREADAUTO -s >> $CONF/pack.d/$MODNAME/tune.c
	else
		cat $ATUNE | $IDREADAUTO -c >> $CONF/pack.d/$MODNAME/tune.c
	fi

}


autotune() {

	new_mtune 

	if [ ! -d $CONF/autotune.d ]
	then
		return
	fi

	cd $CONF/autotune.d

	for MODNAME in *
	do
		echo "#include <sys/autotune.h>" > $CONF/pack.d/$MODNAME/tune.c

		A=`cat $MODNAME | egrep -v "^#|^\*" | awk '{print $1}' | sort -u`
		for NAME in $A
		do
			auto_calc_curve $NAME $MODNAME
		done
	done

	rm $ATUNE

	$IDMKDTUNE -r $ROOT/etc/conf
}

if ps -z > /dev/null 2>&1
then
	pfmt -l $LABEL -s error -g $CATALOG:221 "Cannot tune the system while running in enhanced security mode.\nPlease reboot mUNIX and try it again.\n"
fi

_PFX=`basename $0 | sed -n 's/idtune$//p'`
_PFX=${_PFX:-$PFX}

if [ "${ROOT:=/}" != "/" ]
then
	ROOT=${ROOT}${MACH:+"/$MACH"}
fi

CONF=$ROOT/etc/conf
NSTUNE=$CONF/cf.d/stune
CSTUNE=$CONF/cf.d/stune.current
MTUNE=$CONF/cf.d/mtune
NMTUNE=$CONF/cf.d/mtune.new
ATUNE=$CONF/cf.d/autotune

P_IDTUNE=/etc/conf/bin/idtune
IDTUNE=$ROOT/$P_IDTUNE
[ -x $IDTUNE -o ! -x $TOOLS/$P_IDTUNE ] || IDTUNE=$TOOLS/$P_IDTUNE

P_IDVAL=/etc/conf/bin/${_PFX}idval
IDVAL=$ROOT/$P_IDVAL
[ -x $IDVAL -o ! -x $TOOLS/$P_IDVAL ] || IDVAL=$TOOLS/$P_IDVAL

P_IDREADAUTO=/etc/conf/bin/${PFX}idreadauto
IDREADAUTO=$ROOT/$P_IDREADAUTO
[ -x $IDREADAUTO -o ! -x $TOOLS/$P_IDREADAUTO ] || IDREADAUTO=$TOOLS/$P_IDREADAUTO

P_IDMKDTUNE=/etc/conf/bin/${_PFX}idmkdtune
IDMKDTUNE=$ROOT/$P_IDMKDTUNE
[ -x $IDMKDTUNE -o ! -x $TOOLS/$P_IDMKDTUNE ] || IDMKDTUNE=$TOOLS/$P_IDMKDTUNE

force=
min=
get=
dflt=
cflag=
debug=
numeric=
recursive=
isauto=

while getopts Bfmgdcr# op
do
	case "$op" in
	B)
		autotune
		exit 0
		;;
	f)
		force=y;;
	m)
		min=y;;
	g)
		get=y;;
	d)
		dflt=y;;
	c)
		cflag=y;;
	r)
		recursive=y;;
	'#')
		debug=y;;
	\?)
		usage;;
	esac
done
shift `expr $OPTIND - 1`

STUNE=$NSTUNE

if [ "$force" -o "$dflt" ]
then
	if [ "$min" ]
	then
		usage
	fi
fi

if [ "$get" ]
then
	if [ "$force" -o "$min" -o "$dflt" ]
	then
		usage
	fi
fi

if [ "$get" -o "$dflt" ]
then
	if [ $# -ne 1 ]
	then
		usage
	fi
else
	if [ $# -ne 2 ]
	then
		usage
	fi
fi

new_mtune

if [ "$debug" ]
then
	echo "Root for this process is ${ROOT}"
	echo "The stune file used:"
	echo "\t$STUNE"
	if [ "$cflag" ]
	then
		echo "and\t$CSTUNE"
	fi
	echo "\nThe mtune file used:"
	echo "\t$MTUNE"
fi

if [ ! -f $STUNE ]
then
	> $STUNE
	if [ "$ROOT" = "/" -a -x /sbin/chlvl ]
	then
		chlvl SYS_PRIVATE $STUNE 2>/dev/null
	fi
fi
if [ ! -f $CSTUNE ]
then
	> $CSTUNE
	if [ "$ROOT" = "/" -a -x /sbin/chlvl ]
	then
		chlvl SYS_PRIVATE $CSTUNE 2>/dev/null
	fi
fi

name=$1

if [ ! "$dflt" ]
then
	new_value=${2:-'""'}
fi

if [ ! -f $MTUNE ]
then
	pfmt -l $LABEL -s error -g $CATALOG:222 "The mtune file %s does not exist.\n" "$MTUNE"
	exit 1
fi

if mline=`grep "^$name[ 	]" $MTUNE 2>/dev/null`
then
	set -- $mline
	def_value=$2
	if [ $# -ge 4 ]
	then
		lbound=$3
		ubound=$4
		if [ "$5" ] 
		then
			if [ $5 = %%AUTO%% ]
			then
				isauto=y
			fi
		fi
		numeric=y
	fi
else
	pfmt -l $LABEL -s error -g $CATALOG:223 "The Tunable Parameter %s does not exist.\n" "$name"
	exit 1
fi

if [ "$cflag" ]
then
	STUNE=$CSTUNE
fi

if sline=`grep "^$name[ 	]" $STUNE 2>/dev/null`
then
	set -- $sline
	cur_value=$2
else
	cur_value=$def_value
fi

if [ "$get" ]
then
	if [ "$numeric" ]
	then
		echo "$cur_value\t$def_value\t$lbound\t$ubound"
	else
		echo "$cur_value\t$def_value"
	fi
	exit 0
fi

if [ "$dflt" ]
then
	new_value=$def_value
fi

# Check for upper and lower bound in mtune if -f not given.

if [ ! "$force" ]
then
    if [ "$numeric" ]
    then
	$IDVAL -g "$new_value" "$ubound"  > /dev/null
	if [ "$?" -eq "1" ]
	then
		pfmt -l $LABEL -s error -g $CATALOG:224 "The requested value for Tunable Parameter %s, %s,\nis higher than the upper limit in mtune, %s.\n%s left unchanged.\n" "$name" "$new_value" "$ubound" "$name"
		exit 1
	fi
	$IDVAL -l "$new_value" "$lbound"  > /dev/null
	if [ "$?" -eq "1" ]
	then
		pfmt -l $LABEL -s error -g $CATALOG:225 "The requested value for Tunable Parameter %s, %s,\nis lower than the lower limit in mtune, %s.\n%s left unchanged.\n" "$name" "$new_value" "$name"
		exit 1
	fi
    fi
fi

if ed_stune
then
	:
else
	pfmt -s nostd -g $CATALOG:226 "%s left at %s.\n" "$name" "$cur_value"
	exit 1
fi

if [ "$cflag" ]
then
	STUNE=$NSTUNE
	if sline=`grep "^$name[ 	]" $STUNE 2>/dev/null`
	then
		set -- $sline
		cur_value=$2
	else
		cur_value=$def_value
	fi
	force=y
	ed_stune
fi
