#! /sbin/sh
#  @(#) $Revision: 1.4.98.3 $
#  truncate_sys
#
#  (c) Copyright Hewlett-Packard Company, 1994
#######
#
# This is a script to remove any non "core" drivers and subsystems
# from a given system file. It must only be called during the 
# initial installation process or when upgrading to a new major
# release. (9.X -> 10.X, or 10.X to 11.X)
#
# NOTE: This script assumes that it is called from within the SD
#       framework, thus all messages go to stdout, and have the
#       standard SD log message indentation.
#
# USAGE: $0 -P -m <master> -s <system>
#    
# Where -P 	    Means preserve original system file in /stand/save.sys.$$
#                   Default: erase original on success.
#       -m <master> Means use <master> as the master sub-file to extract
#                   a list of valid drivers from. Default:
#		    /usr/conf/master.d/core-hpux
#       -s <system> Means use <system> as the system file to truncate.
#		    Default: /stand/system.
#######

########################################################################
# FUNCTIONS
########################################################################
Usage_exit ()
# Function to print a Usage message to standard out, then exit.
# The message should never be seen on a customer's system.
{
    print "ERROR:   Usage: $CMD [-P] [-m <master sub-file>] [-s <system file>]"
    exit $FAILURE
}

########################### rebuild_sysfile ##############################
#								       #
# rebuild_sysfile() -- rebuild the 'sysfile' after an update.	       #
#								       #
########################################################################
function rebuild_sysfile
{
    # 
    # Set variables to be passed into awk via the command line
    #

    master=$1
    old_sysfile=$2
    new_sysfile=$3

    # Set error log location

    errlog=/tmp/rbld.err.$$

    #-------------------------
    # Begin monster awk script
    #-------------------------

    awk '
	#
	# NEW_NAME_MAP --
	#    string of pairs of kernel driver name in the format
	#    "old1|new1 old2|new2 ...".  This list MUST be maintained
	#    each release, as names might be changed in the new
	#    /etc/master
	#
	# Note: The strings below are put together using awk string
	#       concatenation so on each lines the SPACE BEFORE THE
	#       QUOTE IS NECESSARY!
	#

    BEGIN {
	#
	# Initialization
	#
	current_table="";
	NEW_NAME_MAP="parallel|CentIf scsi|sdisk scsitape|stape s2tape|stape autoch|ssrfc autox|schgr pcfloppy|pflop pcfdc|fdc";

	#
	# Build associative array of kernel driver names that need
	# to be "updated" called "new_name_map". This will be used
	# to determine if a driver name has been changed, as well
	# as what the new name is.
	# (e.g.,  new_name_map[old_name] == new_name)
	#
	stringsize = split(NEW_NAME_MAP, stringtemp, " ")
	for (i = 1; i <= stringsize; i++)
	{
	    split(stringtemp[i], name_pair, "|");
	    new_name_map[name_pair[1]] = name_pair[2];
	}
    }

    FILENAME==master {
	#
	# Each section of /etc/master begins with a "$<table name>" 
	# and is terminated by "$$$".  The  valid "driver" names are 
	# all those in the tables "DRIVER_INSTALL" and "CDIO". The older
	# drivers are in the table "DEVICE" and the alternative driver
	# names (aliases) are in the table "$ALIAS".  If the entries
	# are in the core master sub-file, then they are valid core
	# "driver specifications". 

	if (NF == 1 && substr($1, 1, 1) == "$")
	{
		current_table=$1
		next;
	}

	#
	# If this is an older core driver, add it to our table of
	# valid driver names.
	#
	if (current_table == "$DEVICE" && NF == 6 && substr($1, 1, 1) != "*" && substr($1, 1, 1) != "$")
	{
		valid_kernel_drivers[$1] = 1;
		next;
	}

	# If this is a CDIO, add it to our table of
	# valid driver names.
	#
	if (current_table == "$CDIO" && NF == 2 && substr($1, 1, 1) != "*" && substr($1, 1, 1) != "$")
	{
		valid_kernel_drivers[$1] = 1;
		next;
	}

	# If this is a converged driver, add it to our table of
	# valid driver names.
	#
	if (current_table == "$DRIVER_INSTALL" && ( NF == 3 || NF == 4 ) && substr($1, 1, 1) != "*" && substr($1, 1, 1) != "$")
	{
		valid_kernel_drivers[$1] = 1;
		next;
	}

	# If this is a core driver alias, add it to our table of
	# valid driver names.
	#
	if (current_table == "$ALIAS" && NF == 2 && substr($1, 1, 1) != "*" && substr($1, 1, 1) != "$")
	{
		valid_kernel_drivers[$1] = 1;
		next;
	}
    }

    FILENAME==sysfile {
	#
	# Pass through all comments and tunables.
	#

				# Covers all tunables and most comments
	if (NF != 1 && substr($2, 1, 1) != "*" && $1 != "driver" )	
	{
		print $0;
		next;
	}

	if (substr($1, 1, 1) == "*")		# Covers the rest of the comments
	{
		print $0;
		next;
	}

	#
	# Scan input (a sysfile) for valid kernel driver names.
	# Parse the input knowing that:
	#
	#    1) a driver entry is one word per line
	#    2) a driver to hardware specification has the keyword "driver" 
	#       (with H/W addr & driver name)
	#    3) anything starting with "*" is a comment
	#
	# An entry is a valid kernel "driver" name if the entry is 
	# in valid_kernel_drivers[]. (All aliases and subsystems have
	# been added to this valid_kernel_drivers table.)
	#
	# A valid kernel driver name may have been changed for
	# the new release, and must be mapped into the "new" name.
	# Aliases are treated like drivers - old alias names are
	# replaced either by the new aliases or by the actual new
	# driver names.
	#
	# All "driver to hardware path specifications" statements are 
	# passed through.  At "config" time, any for drivers not 
	# specified are ignored.

	if ( (NF == 1 && substr($1, 1, 1) != "*") || 
	     (NF > 1 && substr($1, 1, 1) != "*" && substr($2, 1, 1) == "*") )
	{
	    if (valid_kernel_drivers[$1])
		print $0;
	    else if (new_name_map[$1] != "")
		print new_name_map[$1];
	    next;
	}

	if ( NF >= 3 && $1 == "driver" && substr($2, 1, 1) != "*" && 
		substr($3, 1, 1) != "*" )
	{
	    if (valid_kernel_drivers[$3])
		print $0;
	    else if (new_name_map[$3] != "")
		print $1,$2,new_name_map[$3];
	    else if ($3 != "psi0")
			# now we allow unknown driverto hardware specs
			# in system file, except for SNA driver psi0
		print $0;
	    next;
	}


    }' master=$master sysfile=$old_sysfile $master $old_sysfile > $new_sysfile 2>$errlog

    #-------------------------
    # End monster awk script
    #-------------------------

    if [[ $? -ne 0 ]]
    then
	print "ERROR:   $CMD unable to truncate system file. Awk output follows:"
	sed -e 's/^/         /' $errlog
        return_code=$FAILURE
    else
	return_code=$SUCCESS
    fi

    rm -f $errlog
    return $return_code

}		# end of rebuild_sysfile()

########################
########################
## MAIN LINE CODE
########################
########################

#
# Preset defaults
#

CMD="${0##*/}"
master=/usr/conf/master.d/core-hpux
system=/stand/system
preserve=""

PATH=/usr/lbin/sw/bin:/usr/bin:/sbin

SUCCESS=0
FAILURE=1
WARNING=2

#
# Parse and test command line arguments
#

while getopts Pm:s: flag
do
	case $flag in
	*P)	preserve="Y"
		;;
	*m) 	master=$OPTARG
		;;
	*s)	system=$OPTARG
		;;
	*)	Usage_exit
		;;
	esac
done

if [[ $# -gt $OPTIND ]]	# getopts is ignoring something on the command line
then			# Get out quick!
	Usage_exit
fi

if [[ ! -f "$master" || ! -r "$master" ]]
then
	print "ERROR:   $CMD - \"$master\" is not a readable ordinary file."
	Usage_exit
fi

if [[ ! -f "$system" || ! -r "$system" ]]
then
	print "ERROR:   $CMD - \"$system\" is not a readable ordinary file."
	Usage_exit
else
    if [[ ${system%/*} = ${system} ]]	# posix-sh equivalent of dirname()
    then
	sys_directory="."
    else
	sys_directory=${system%/*}
    fi
    old_sys=$sys_directory/save.sys.$$
fi

#
# Move original system file aside and create new, truncated version.
#

mv $system $old_sys

rebuild_sysfile $master $old_sys $system
if [[ $? -ne $SUCCESS ]]
then
    mv -f $old_sys $system
    exit $FAILURE
elif [[ -z "$preserve" ]]
then
    rm -f $old_sys
else
    print "         $CMD: Original system file saved to \"$old_sys\"."
fi

exit $SUCCESS
	
