#!/bin/sh # mkkernel # v1.6 This is good ... always name the version. Ideally also supply a date. # Tunes the kernel parameters listed in the file "./settings" This is also good. Describe what the script # This file must have the format PARAMETER VALUE does, and what input it expects. # eg : # MAXUP 2000 # shell, softscreen, etc. # Updates /etc/conf/mtune.d/* and /etc/conf/cf.d/mtune files if maximum # allowable values require updating; keeps default, min values as before echo " Kernel Tuning Utility" Optional banner stuff. For something like echo " Intel DRS/NX, Intel UnixWare, SPARC MPlus" this, which just runs but can come across echo multiple error states, it is worth keeping the echo " === S G Parker and D A Dallas ===" user informed as to what is happening. If you have echo ever used such a script, you will realise how useful it can be to scroll back, see when the script was kicked off, and see the result. USAGE="Usage : mkkernel [-f ] [-e] [-l] [-y] [-v]" Setting some global variables before the start. This stuff should all really be in a function, but EXACT="NO" it seems that I didn't know about shell script VERBOSE="NO" functions back then. LIST="NO" REBUILD="NO" SETTINGSFILE=settings while getopts 'eylf:?' c Getopts is a very handy utility. Use it. do case $c in e) EXACT="YES" ;; f) SETTINGSFILE=$OPTARG;; y) REBUILD="YES" ;; v) VERBOSE="YES" ;; l) LIST="YES" ;; \?) echo $USAGE echo "Where contains desired values, -e tunes exactly to that value" Again, a function could be done to do the Usage echo " default is to tune to at least the given value ie, never tune down" option better, than echoing a standard line plus this extra monologue. exit 2;; Exit 2 should normally be used for usage errors. esac done trap 'echo "`basename $0` : Interrupted" ; exit 1' 1 2 15 Trap is also useful when you need to do some cleaning up when hit by a KILL -9, ^C, etc. if [ "$LOGNAME" -ne "root" ] then echo "You must be super-user to run this script." exit 1 fi echo "Checking $SETTINGSFILE ..." if [ ! -r $SETTINGSFILE ] then echo "ERROR: Cannot read settings file $SETTINGSFILE" exit 1 fi rm /tmp/settings > /dev/null 2>&1 Serious bug here: What if \ while i=`line` # Remove comments and $SETTINGSFILE=/tmp/settings ? It'd be erased! do # blank lines, convert j=`echo $i|awk '{ print $1 }' | cut -c1` # all to upper case Again, this should be a function. More important, if [ "$j" != "#" ] && [ "$j" != "" ] this does not get rid of " #xxx" lines. then echo $i | tr '[a-z]' '[A-Z]' >> /tmp/settings fi done < $SETTINGSFILE SETTINGSFILE=/tmp/settings echo "Checking `uname -n` architecture ..." Again, best as a function. Another dirty hack, BASE='/etc/conf' # Default to Intel but works for this particular scenario. Not ARCH="INTEL" recommended for general use. if [ "`uname -p`" = "sparc" ] then case "`uname -v`" in ?MPlus.*) ARCH="MPLUS" ;; *) BASE='/etc/master.d' # SPARC non-MPlus ARCH="SPARC" # settings. ;; esac fi if [ "$ARCH" = "SPARC" ] By using functions more, it would have been then possible to make a single script which would echo "This script is for SPARC MPlus and Intel machines only" have coped with different architectures. echo "`uname -n` architecture is $ARCH" With the monolithic style, different scripts exit 1 were needed, which caused needless editing for fi updates, such as the lockfile stuff above. echo "`uname -n` architecture is $ARCH" # Confirm to user This is good... keep the user informed. If nothing else, you know where it got to if it crashes later. if [ "$LIST" = "YES" ] This, yet again, should be a function. then It is a specialised feature of the script, and echo "`uname -n`: Current kernel parameters" should be seperated out as such. ls -l /stand/`kernel` while i=`line` do PARAM=`echo $i | awk '{ print $1 }'` VALUE=`echo $i | awk '{ print $2 }'` echo "$PARAM: " > /tmp/param.out /etc/conf/bin/idtune -g $PARAM >> /tmp/param.out 2>&1 # Skip if parameter cat /tmp/param.out|tr '\012' ' ' > /tmp/out.param if [ $? -ne "0" ] # does not exist then echo "`basename $0`: Skipping nonexistant parameter '$PARAM'" else PRESENT=`cat /tmp/out.param|awk '{ print $2 }'` if [ "$VALUE" -gt "$PRESENT" ] then echo " (> to $VALUE)" >> /tmp/out.param elif [ "$VALUE" -lt "$PRESENT" ] then echo " (< to $VALUE)" >> /tmp/out.param else echo " (= `basename $SETTINGSFILE`)" >> /tmp/out.param fi cat /tmp/out.param fi done < $SETTINGSFILE exit 0 fi ls -l /tmp/mkkernel.lock > /dev/null 2>&1 Check if someone else is already running this if [ "$?" -eq "0" ] script. You might think that retuning a kernel then would not require these checks, but we found that echo "ERROR : Another copy of mkkernel is running on `uname -n`" because two of us worked on this, we ended up ps -fp `cat /tmp/mkkernel.lock` with file corruption. It's best to check! if [ "$?" -ne "0" ] then # ps failed to find it echo "Failed to find process `cat /tmp/mkkernel.lock`" echo "This process may have terminated abnormally" echo "Please remove /tmp/mkkernel.lock if you are sure" echo "that there is no competing process" exit 2 fi else echo $$ > /tmp/mkkernel.lock echo "Process lock granted. Continuing ..." fi echo "Creating backups of kernel files ..." Again, a subroutine. mkdir /tmp/sgp > /dev/null 2>&1 # Create backups mkdir /tmp/sgp/mtune.d > /dev/null 2>&1 mkdir /tmp/sgp/cf.d > /dev/null 2>&1 cp -r $BASE/mtune.d/* /tmp/sgp/mtune.d cp -r $BASE/cf.d/mtune /tmp/sgp/cf.d/mtune while i=`line` This is where we do the real stuff..... do It is too huge for me to be bothered commenting PARAM=`echo $i | awk '{ print $1 }'` and critiquing it in detail. This fact in itself VALUE=`echo $i | awk '{ print $2 }'` speaks volumes; and I wrote it in the first place! /etc/conf/bin/idtune -g $PARAM > /dev/null 2>&1 # Skip if parameter if [ $? -ne "0" ] # does not exist How could anyone else get it if I can't be then bothered going through it?!! echo "`basename $0`: Skipping nonexistant parameter '$PARAM'" else # this is a big "else" ... ... And the tabs are wrong... it should be current_max=`/etc/conf/bin/idtune -g $PARAM | cut -f4` indented. if [ "$current_max" -lt "$VALUE" ] then # fix the file if [ "$VERBOSE" = "YES" ] Okay, this is good, but a better feature would then be a verbose() function to check the variable echo "Fixing file $filename : max was $current_max" and, if appropriate, echo the message. This makes fi it less hassle to add verbose messages. filename=`grep "^$PARAM" $BASE/mtune.d/*|cut -d: -f1` if [ $? -ne "0" ] then echo "ERROR: Cannot find $PARAM in $BASE/mtune.d/" exit 1 fi linenumber=`grep -n "^$PARAM" $filename | cut -d: -f1|head -1` Could use sed here quite usefully, since there thisline=`expr $linenumber - 1` # all lines before PARAM should be a unique instance of the PARAM name.... nextline=`expr $linenumber + 1` # all lines after PARAM head -$thisline $filename > /tmp/steve.tunefile if [ $? -ne "0" ] I've no idea why this is in here; writing to then /tmp is normally taken for granted. echo "ERROR: Cannot write to /tmp directory" exit 1 fi current_values=`grep "^$PARAM" $filename|head -1` This use of `head` ensures against multiple current_default=`echo $current_values|awk '{ print $2 }'` instances of the PARAM name. current_min=`echo $current_values|awk '{ print $3 }'` echo "$PARAM $current_default $current_min $VALUE" >> /tmp/steve.tunefile tail +$nextline $filename >> /tmp/steve.tunefile mv /tmp/steve.tunefile $filename # Place the edited file if [ $? -ne "0" ] # in the right place. then echo "ERROR: Cannot move /tmp/steve.tunefile to $filename" exit 1 fi filename='/etc/conf/cf.d/mtune' # this also needs editing linenumber=`grep -n "^$PARAM" $filename | cut -d: -f1` if [ $? -ne "0" ] then echo "ERROR: Cannot find $PARAM in $filename" exit 1 fi thisline=`expr $linenumber - 1` # see above nextline=`expr $linenumber + 1` head -$thisline $filename > /tmp/steve.tunefile if [ $? -ne "0" ] then echo "ERROR: Cannot write to /tmp" exit 1 fi echo "$PARAM $VALUE 0 $VALUE %%INS%%" >> /tmp/steve.tunefile tail +$nextline $filename >> /tmp/steve.tunefile mv /tmp/steve.tunefile $filename # move edited file to position if [ $? -ne "0" ] then echo "ERROR: Cannot move /tmp/steve.tunefile to $filename" exit 1 fi /etc/conf/bin/idtune -f $PARAM $VALUE if [ "$?" -ne "0" ] then echo "Still cannot tune $PARAM to $VALUE." fi fi # fix the file current_value=`/etc/conf/bin/idtune -g $PARAM|cut -f1` if [ $current_value -lt $VALUE ] then TUNEME="YES" else TUNEME="NO" fi if [ "$EXACT" = "YES" ] then TUNEME="YES" fi if [ "$TUNEME" = "YES" ] then echo Tuning $PARAM from $current_value to $VALUE /etc/conf/bin/idtune -f $PARAM $VALUE else echo $PARAM is already tuned to $current_value : will not tune to $VALUE fi fi # the "else" part of whether the parameter exists done < $SETTINGSFILE rm -f /tmp/mkkernel.lock # remove process lock if [ "$REBUILD" = "NO" ] then echo "Rebuild and copy new kernel? (y/n) \c" read RESPONSE case "$RESPONSE" in "y"|"Y"|"Yes"|"yes") REBUILD="YES" ;; *) REBUILD="NO" ;; esac else echo "Called with the -y option; will rebuild and copy new kernel" fi if [ "$REBUILD" = "YES" ] then /etc/conf/bin/idbuild -K && /etc/conf/bin/idcpunix echo "The kernel has been tuned and rebuilt. Please reboot the machine" echo " to start using this new kernel." echo echo "/tmp/sgp/* contains backups of the previous kernel files." echo "Please note : /tmp/* will be deleted on a system reboot." fi rm /tmp/files.edited > /dev/null 2>&1