#!/sbin/sh
#############################
# Product: DesktopConfig
# Fileset: LITECONFIG
# lite_config
# @(#) $Revision: 1.4.98.1 $
#############################
#
# (c) Copyright Hewlett-Packard Company, 1993
#
################################################################################
#
# Name: Lite_config (Series 700 only)
#
# Description:
#	Lite_config installs the Series 700 "Lite" HP-UX Configuration.
#	This is the default configuration for Desktop HP-UX.
#	It is a special lightweight configuration of HP-UX which
#	conserves system memory by scaling down kernel resources and
#	disabling several optional subsystems.
#
#	The indicated system file is made "lite" as follows:
# 		o Removal of several optional drivers 
# 		o Reduction of the default values of several tunable parameters 
#
#	Optional subsystems are made "lite" by simply disabling the startup of 
#	their corresponding daemons.  This is typically accomplished by setting 
#	the appropriate control variable in the /etc/rc.config.d/<subsystem> 
#	file to "0".
#
# NOTE: Lite_config is called from the following sources:
#		o DesktopConfig.LITECONFIG SD control scripts 
#		  (postinstall, configure, unconfigure, and preremove).
#		o SAM utility. 
#		  Lite_config is called (-l/-u -r options ONLY) whenever the 
#		  user selects the "Apply Lite HP-UX Configuration" button
#		  from the Actions pull-down menu of the Drivers, Subsystems, 
#		  or Configurable Parameters menus (from within SAM's Kernel
#		  Configuration screen). 
#
# Runstring:
#	lite_config -l|-u [-c] -r|-s<systemfile> [-R<systemroot>]
#
#	Options:
#	-l	"Lite"    mode of operation (minimize kernel/system size)
#	-u	"Un-lite" mode of operation (revert back to original size)
#	-c	Cold-install environment 
#	-r	Process /etc/rc.config.d subsystems
#	-s	Process the system file specified by <systemfile>
#	-R	Specify the system root (default is "/")
#
################################################################################


#==============================================================================
# Printusage()
#
# Parameters: 	
#	None
#
# Description: 	
#	Print usage run-string.
#
# Return value:	
#	None
#==============================================================================
function printusage 
{ 
	print ""
	print "NOTE: $ME installs the Series 700 \"Lite HP-UX Configuration\"."
	print "This is the default configuration for Desktop HP-UX."
	print "It is a special lightweight configuration of HP-UX which"
	print "conserves system memory by scaling down kernel resources and"
	print "disabling several optional subsystems."
	print ""
	print "CAUTION: This configuration is specifically tuned for the"
	print "single-user commercial HP-UX customer using a desktop"
	print "workstation with limited disk space and/or RAM."
	print "$ME should not be run on multi-user systems, servers, etc."  
	print ""
 	print "Usage:\t$ME: -l|-u [-c] -r|-s<systemfile> [-R<systemroot>]"
	print ""
	print "\t-l\t\t \"Lite\"    mode of operation"
	print "\t-u\t\t \"Un-lite\" mode of operation"
	print "\t-c\t\t Cold-install environment"
	print "\t-r\t\t Process /etc/rc.config.d subsystems"
	print "\t-s <systemfile>  Process <systemfile> (e.g. /stand/system)"
	print "\t-R <systemroot>  Specify <systemroot> (default is \"/\")"
	print ""
}


#===============================================================================
# Scan_devices() 
#
# Parameters: 
#	$1	Name of driver corresponding to device (as displayed by ioscan)
#	$2	Hardware type of device (as displayed by ioscan)
#
# Description: 	
#	Scan_devices() invokes the ioscan(1M) utility in order to scan for
#	the indicated device.  A device is considered present if ioscan's 
#	output contains an entry for the driver ($1), the software state is 
#	"CLAIMED", and the hardware type displayed matches the indicated 
#	hardware type ($2).
#
#	Scan_devices() will immediately return failure is this is a pre-10.0
#	system.  The main benefit of scan_devices() is the optimization of 
#	"older" dfiles that have been upgraded from 9.X to 10.0.  These older 
#	dfiles traditionally had extra drivers included even though the 
#	corresponding devices were not always present on the system.
#
#	In order to improve performance, the i/o scan is only done *once*
#	and the filtered results are cached.
#
# Return value:
#	0	Device found
#	1	Device not found
#	2	Fatal error (e.g., pre-10.0 system)
#===============================================================================
function scan_devices 
{
	#
	# Return immediately (with failure) if OS is pre-10.0 
	# -or- if ioscan isn't accessible.
	#
	typeset release=`uname -r`		# Get release  (e.g., A.09.00)
	release=${release%.*}			# Truncate rhs (e.g., A.09)
	[[ ${release#*.} -le 9 ]] && return 2
	[[ ! -x $IOSCAN ]] && return 2

	#
	# Run ioscan only once and cache filtered results.
	# After the ioscan, we filter the output for only CLAIMED entries
	# since these represent existing, functioning devices.
	#
	if [[ $ioscanned_already -eq 0 ]]; then
		$IOSCAN -F > $IOSCAN_OUT || return 2
		awk -F: '
		{
			driver		= $15
			sw_status	= $16
			hardware_type	= $17
			if (sw_status == "CLAIMED") {
				printf( ":%s:%s:\n", driver, hardware_type )
			}
		}' < $IOSCAN_OUT > $IOSCAN_FILTERED_OUT 
		[[ $? -ne 0 ]] && return 2
		ioscanned_already=1
	fi

	#
	# Look for driver and hardware type in ioscan filtered output.
	#
	grep -q ":$1:$2:" $IOSCAN_FILTERED_OUT 
	return $?
}


#===============================================================================
# Eisa_present()
#
# Parameters: 
#	None
#
# Description: 	
#	Eisa_present() determines if an EISA system board (adapter) is
#	present in the system.  
#
# Return value:
#	0	Returned if EISA system board present
#	1	Returned if EISA system board not present
#	2	Fatal error
#===============================================================================
function eisa_present 
{
	#
	# Gecko (712) systems don't support EISA.
	# Return "1" immediately (this saves us an i/o scan).
	#
	typeset model=`uname -m`		# Get model    (e.g., 9000/750)
	model=${model#*/}			# Truncate lhs (e.g., 750)
	if [[ "$model" = "712" ]]; then
		return 1
	fi

	#
	# Look for the EISA system board.
	# Note that the EISA system board can be reliably scanned for
	# since it cannot be powered down (unlike a peripheral device).
	#
	scan_devices "eisa" "BUS_NEXUS" 
	return $?
}


#===============================================================================
# Tune_drivers() 
#
# Parameters: 
#	None
#
# Description (called from postinstall & configure scripts): 	
#	Tune_drivers() removes optional drivers from the system file.
#	The drivers are categorized into several different removal classes.
#	All of the driver sizes shown are static (text+data+bss) only.
#
#	For the 10.0 release, the diagnostics drivers are *not removed* unless
#	lite_config is being run manually (i.e., not on behalf of swinstall).
#	This means that the DesktopConfig.LITECONFIG fileset will not remove
#	these drivers when it is installed.  The only supported way a user
#	can remove these is to invoke SAM's "Lite HP-UX Configuration" option.
#
#	dmem		Memory diagnostics pseudo-driver      (~ 4.5 KB)
#	diag1		I/O diagnostics pseudo-driver         (~ 6.3 KB)
#	diag2		Generic error logging pseudo-driver   (~ 5.9 KB)
#	                (diag2 also allocates a 12 KB logging buffer)
#
#
#	The following drivers are removed during a *cold-install only*.
#	These drivers are considered to be infrequently used in the single-user
#	commercial client desktop environment and can be safely removed. 
#	These drivers are not removed for normal updates because it is 
#   	difficult (if not impossible) to determine if their corresponding
#	devices are attached to the system (i.e., device could be powered down).
#	Note: all Instantly Ignited systems are cold-installed at the factory.
#
#	CharDrv		Parallel device driver                (~ 1.3 KB)
#	CentIf		Parallel interface driver 	      (~ 3.4 KB)
#	parallel	CentIf pre-10.0 alias     
#
#
#	The following drivers are removed only if an EISA system board is not 
#	found during an I/O scan:
#
#	eisa		EISA system board driver 	      (~19.6 KB)
#	eeprom		EISA EEPROM driver      	      (~ 7.3 KB)
#	hshpib		EISA high-speed HPIB interface driver (~18.8 KB)
#	cs80		CS/80 (disk/tape) HPIB device driver  (~20.0 KB)
#	hpib		printers/plotters HPIB device driver  (~17.7 KB)
#
#
# Return value:
#	0	Success
#	1	Failure
#	2	Warning
#===============================================================================
function tune_drivers 
{
	# Declare local variables.
	typeset -i exitstat=$SUCCESS
	typeset driver 
	typeset -i remove

	#
	# Create "removed drivers" log file (if not already present).
	#
	if [[ -d $LOGDIR && ! -f $REMOVED_DRVS_LOG ]]; then 
		cat > $REMOVED_DRVS_LOG <<End-Of-Drivers-Header
#
# CAUTION: Do not remove this file !
#
# This file contains a list of all the optional drivers that have been removed 
# from the system file as a result of swinstall'ing the SD product 
# DesktopConfig.  Note that DesktopConfig is automatically installed whenever 
# the SD bundle for Desktop HP-UX is installed.
#
End-Of-Drivers-Header

		# Make read-only (note: super-user can still write to this).
		chmod 444 $REMOVED_DRVS_LOG
	fi

	#
	# Update the IPD if we've been invoked from an SD session.
	# Note: we need to *always* do this because re-installs of 
	# DesktopConfig will wipe-out any previous additions to the IPD.
	#
	# Note: IPD_addfile is currently commented out because it cannot handle
	# "volatile" files (however, swmodify can using "-a is_volatile=true").
	# This eliminates errors produced by an swverify of DesktopConfig.
	#
	# [[ -n "$SD_INITIATED" ]] && IPD_addfile $REMOVED_DRVS_LOG 

	#
	# Extract all drivers from system file.
	#
	awk '
	{
		# Skip over blank lines and whole-line comments
		if (NF == 0) { next }	
		if ((c = index( $0, "*" )) == 1) { next }	

		# Process comment free lines
		if (c == 0) {
			# Print driver name
			if (NF == 1) { print $1 }
			# Otherwise exit (tunable parameter)
			else { exit 0 }
		}

		#
		# Process embedded comments (a bit messy).
		# Split-up the non-commented portion (around white-spaces).
		# If the number of fields > 1 then exit (tunable parameter),
		# otherwise print the driver name.
		#
		else {
			entry = substr( $0, 1, c-1 )		
			if (split( entry, a ) > 1) { exit 0 }
			else { print a[1] }
		}
	}' < $SYSTEM > $SYSTEM_DRIVERS 
	if [[ $? -ne 0 ]]; then
		print "WARNING: Cannot remove any optional drivers from"
		print "         \"$SYSTEM\"."	
		return $WARNING
	fi				

	#
	# Process each driver in the system file.
	# If we can remove it, go ahead.
	#
	while read driver
	do
		#
		# Process each driver.
		# Only consider removing the driver if it hasn't been
		# previously removed by lite_config (i.e., if it's not present 
		# in the "removed drivers" log file).
		# Otherwise, the user has probably added it back to the
		# system file -- honor this.
		#
		grep -q "^$driver " $REMOVED_DRVS_LOG && continue
		remove=0
		case "$driver" in
			#
			# Remove diagnostics pseudo-drivers
			# (only for non-SD session !).
			#	dmem	Memory diagnostics pseudo-driver
			#	diag1	I/O diagnostics pseudo-driver
			#	diag2	Generic I/O error logging pseudo-driver
			#
			# Note: diag0 is not removed since it is exclusively
			#       an S800-style driver.
			#
			"dmem" | "diag1" | "diag2") 	
				[[ -z "$SD_INITIATED" ]] && remove=1 ;;

			#
			# Remove parallel port drivers (cold-install only).
			#	CharDrv		Parallel device driver	
			#	CentIf		Parallel interface driver
			#	parallel	Pre-10.0 alias for CentIf
			#
			"CharDrv" | "CentIf" | "parallel")
				[[ -n "$COLD_INSTALL" ]] && remove=1 ;;

			#
			# Remove EISA system board driver.
			# EISA driver is removed if the EISA system board
			# is not present (see eisa_present() function).
			#
			"eisa" | "eeprom")
				eisa_present
				[[ $? -eq 1 ]] && remove=1 ;;

			#
			# Remove HPIB drivers (only if EISA not present).
			#	hshpib	EISA high-speed HPIB interface driver
			#	cs80	CS/80 (disk/tape) HPIB device driver
			#	hpib	printers/plotters HPIB device driver
			#
			"hshpib" | "cs80" | "hpib")
				eisa_present
				[[ $? -eq 1 ]] && remove=1 ;;

			#
			# Default-- don't remove 
			#
			*) 	;;
		esac	

		#
		# Continue on to next driver if we can't remove this one.
		# Otherwise, remove driver from system file.
		#
		[[ $remove -eq 0 ]] && continue
		mod_systemfile $SYSTEM -d "$driver" 
		if [[ $? -ne 0 ]]; then
			print "WARNING: Cannot remove \"$driver\" driver from"
			print "         \"$SYSTEM\"."	
			[[ $exitstat -ne $FAILURE ]] && exitstat=$WARNING
			continue
		fi

		#
		# Echo/log driver removal.
		#
		print "NOTE:    Removed \"$driver\" driver from \"$SYSTEM\"." 
		print "$driver " >> $REMOVED_DRVS_LOG 
	done < $SYSTEM_DRIVERS

	# Return 
	return $exitstat
}


#===============================================================================
# Untune_drivers()
#
# Parameters: 
#	None
#
# Description (called from preremove script): 	
#	Untune_drivers() adds back any optional drivers to the system file that 
#	were previously removed by lite_config.  A list of drivers previously
#	removed is kept in the "removed drivers" log file.  
#
#	Note that because swremove does *not* support any modifications to the
#	kernel for release 10.0, untune_drivers() does not (cannot) add back 
#	the driver(s) to the system file if invoked from an SD session.  
# 	In this case, it merely logs each driver's name to the swagent.log file 
#	so that the user can subsequently add back the driver(s) by hand.
#
# Return value:
#	0	Success
#	1	Failure
#	2	Warning
#===============================================================================
function untune_drivers 
{ 
	#
	# Declare local variables.
	# Immediately return if no "removed drivers" log file exists.
	#
	typeset -i exitstat=$SUCCESS
	typeset driver junk
	[[ ! -f $REMOVED_DRVS_LOG ]] && return $exitstat

	#
	# Add back in drivers to system file (that were originally deleted).
	# Use the $REMOVED_DRVS_LOG file for guidance.
	#
	while read driver junk
	do
		# Skip over leading comments.
		[[ "$driver" = "#" ]] && continue

		#
		# If we've been invoked from an SD session (i.e., swremove), 
		# just echo the driver's name to the swagent.log file.
		#
		if [[ -n "$SD_INITIATED" ]]; then
			print "         Add: $driver"
			continue
		fi

		#
		# Otherwise, add driver back to system file.
		#
		mod_systemfile $SYSTEM -a "$driver" 
		if [[ $? -ne 0 ]]; then
			print "WARNING: Cannot add \"$driver\" driver back to"	
			print "         \"$SYSTEM\"."	
			[[ $exitstat -ne $FAILURE ]] && exitstat=$WARNING
			continue
		fi

		# Echo driver addition.
		print "NOTE:    Added \"$driver\" driver back to \"$SYSTEM\"." 
	done < $REMOVED_DRVS_LOG 

	#
	# Delete "removed drivers" log file.
	# Also update IPD (delete file) if we've been invoked by SD.
	# Note: we remove this log file here rather than letting swremove
	# delete it.  This is done in order to be consistent with 
	# untune_subsystems() removal of the "saved rc.config.d" log file,
	# and also so that a manual invocation of lite_config will work.
	#
	rm -f $REMOVED_DRVS_LOG 
	# Note: IPD_delfile currently commented out (see IPD_addfile comments).
	# [[ $? -eq 0 && -n "$SD_INITIATED" ]] && IPD_delfile $REMOVED_DRVS_LOG
	return $exitstat
}


#===============================================================================
# Get_lite_tunables()
#
# Parameters: 
#	None
#
# Description: 	
#	Get_lite_tunables() prints (to stdout) a list of kernel tunable 
#	parameters and their corresponding "lite" values.  This list of kernel 
#	tunables reflects the resource requirements expected in a single-user 
#	commercial HP-UX desktop workstation environment.
#
#	The following table shows each kernel parameter, its default value, 
#	its tuned or "lite" value, and the estimated RAM size savings obtained 
#	by reducing the parameter.
#
#                                  ~RAM
#	Parameter  Default/Tuned   Savings  Description
#       ----------------------------------------------------------------
#       dbc_max_pct     50/25      N/A      Dynamic buffer cache maximum (25%).
#       dbc_min_pct      5/2       >500 KB  Dynamic buffer cache minimum (2%).
#                                           The RAM savings here reduces the
#                                           dynamic memory usage of the system 
#                                           during VM stress conditions.
#
#       nproc          276/120     78.0 KB  Max number of active processes.
#       ninode         476/250     78.5 KB  Max number of open inodes in memory.
#       nfile          671/400      8.5 KB  Max number of open files.
#       nflocks        200/50      19.4 KB  Max number of file/record locks.
#
#       npty            60/30      14.5 KB  Max number of pseudo terminals.
#                                           This limits the maximum number 
#                                           of windows / network-sessions.
#
#       msgmni          50/20       3.0 KB  Max number of message queues.
#       semmni          64/20       3.8 KB  Max number of semaphore identifiers.
#       shmmni         200/50      15.2 KB  Max number of shared mem segments.
#       shmseg         120/50        --     Max number of shmem segs / process.
#                                           These values for the System V IPC 
#                                           tunables appear to be adequate 
#                                           for most single-user environments.
#
#       scroll_lines   100/70       7.5 KB  Graphics ITE maximum scroll lines.
#                                           This only impacts the scroll limit
#                                           before VUE/X is started.
#
#       maxusers        32/8       12.0 KB  Indirectly limits kernel resources.
#                                           This does NOT limit the actual 
#                                           number of users.
#
# Return value:
#	None
#===============================================================================
function get_lite_tunables
{
	#
	# Print "lite" kernel tunable parameters.
	#
	print "nproc 		120"
	print "ninode 		250"
	print "nfile 		400"
	print "nflocks		50"
	print "npty 		30"
	print "msgmni 		20"
	print "semmni 		20"
	print "shmmni 		50"
	print "shmseg 		50"
	print "dbc_max_pct	25"
	print "dbc_min_pct	2"
	print "scroll_lines	70"
	print "maxusers		8"
}


#===============================================================================
# Tune_parameters()
#
# Parameters: 
#	None
#
# Description (called from postinstall & configure scripts): 	
#	Tune_parameters() reduces the default value of each tunable parameter
#	returned by get_lite_tunables().  In general, the parameter is 
#	*only* reduced if it has not been explicitly set in the system file.
#	Note that the algorithms below also allow for corrections/updates to 
#	existing sets of "lite" tunable parameters shipped with previous
#	versions of DesktopConfig.
#
# Return value:
#	0	Success
#	1	Failure
#	2	Warning
#===============================================================================
function tune_parameters 
{ 
	# Declare local variables.
	typeset -i exitstat=$SUCCESS
	typeset param val curval oldval junk

	#
	# Create "reduced tunables" log file (if not already present).
	#
	if [[ -d $LOGDIR && ! -f $LITE_TUNABLES_LOG ]]; then
		cat > $LITE_TUNABLES_LOG <<End-Of-Tunables-Header
#
# CAUTION: Do not remove this file !
#
# This file contains a list of all the kernel tunable parameters that have been 
# reduced in the system file as a result of swinstall'ing the SD product 
# DesktopConfig.  Note that DesktopConfig is automatically installed whenever 
# the SD bundle for Desktop HP-UX is installed.
#
# Each entry is of the form: 
# <parameter> <lite_value>
#
End-Of-Tunables-Header

		# Make read-only (note: super-user can still write to this).
		chmod 444 $LITE_TUNABLES_LOG
	fi

	#
	# Update the IPD if we've been invoked from an SD session.
	# Note: we need to *always* do this because re-installs of 
	# DesktopConfig will wipe-out any previous additions to the IPD.
	#
	# Note: IPD_addfile is currently commented out because it cannot handle
	# "volatile" files (however, swmodify can using "-a is_volatile=true").
	# This eliminates errors produced by an swverify of DesktopConfig.
	#
	# [[ -n "$SD_INITIATED" ]] && IPD_addfile $LITE_TUNABLES_LOG 

	#
	# Tune down (if possible) each parameter returned by get_lite_tunables()
	#
	get_lite_tunables |
	while read param val junk
	do
		#
		# Query system file for parameter value.
		#
		curval=`query_systemfile $SYSTEM $param`
		if [[ $? -ne 0 ]]; then
		    print "WARNING: Query of \"$SYSTEM\" for \"$param\" failed."
		    print "         Cannot update \"$SYSTEM\" to reduce"
		    print "         \"$param\" tunable to \"$val\"."
		    [[ $exitstat -ne $FAILURE ]] && exitstat=$WARNING
		    continue  	
		fi

		#
		# If the parameter itself was found in the system file,
		# then only tune it (again) if already "lite"; see below.
		#
		# This mechanism allows for parameter bug fixes and/or 
		# enhancements to be made to a system already installed
		# with the Lite HP-UX Configuration.
		#
		if [[ -n "$curval" ]]; then
			#
			# If the parameter isn't present in the log file,
			# then if the parameter's value matches the lite value,
			# we'll log it to the tunables log file (since it
			# appears to have been previously tuned).
			# This would be the case if the system file had 
			# already been lite'ned by SAM, or if the user
			# had previously removed this log file after 
			# lite'ning the system via swinstall.
			#
			oldval=`grep "^$param " $LITE_TUNABLES_LOG | \
				awk '{print $2}'`
			if [[ -z "$oldval" ]]; then
				[[ $curval -eq $val ]] && \
				print "$param $val" >> $LITE_TUNABLES_LOG 
				continue

			#
			# The parameter is present in the tunables log file 
			# indicating it has been previously tuned.
			# Only change the parameter if the new lite value ($val)
			# has changed from the old lite value ($oldval) --and--
			# if the user hasn't changed the original value.
			#
			else
				[[ $val -eq $oldval ]] && continue 
				[[ $curval -ne $oldval ]] && continue 

				#
				# OK to change parameter again; 
				# remove old logged entries first.
				#
				sed -e "/^$param /d" $LITE_TUNABLES_LOG > $TEMPF
				mv $TEMPF $LITE_TUNABLES_LOG
				chmod 444 $LITE_TUNABLES_LOG
			fi
		# End 'if [[ -n "$curval" ]]; then'

		#
		# Parameter was not found in the system file. 
		# The following prevents lite_config from re-tuning a parameter
		# that the user has intentionally deleted from the system file.
		# This also allows for the later addition of more tunable 
		# parameters to the Lite HP-UX Configuration.
		#
		else	
			grep -q "^$param " $LITE_TUNABLES_LOG && continue
		fi

		#
		# All systems green-- tune down parameter !
		#
		mod_systemfile $SYSTEM -t "$param" "$val"
		if [[ $? -ne 0 ]]; then
		    print "WARNING: Cannot update \"$SYSTEM\" to reduce"
		    print "         \"$param\" tunable to \"$val\"."
		    [[ $exitstat -ne $FAILURE ]] && exitstat=$WARNING
		    continue
		fi

		#
		# Echo/log tunable parameter reduction.
		#
		print "NOTE:    Reduced \"$param\" tunable to \"$val\" in \"$SYSTEM\"."
		print "$param $val" >> $LITE_TUNABLES_LOG 
	done 

	# Return
	return $exitstat
}


#===============================================================================
# Untune_parameters()
#
# Parameters: 
#	None
#
# Description (called from preremove script): 	
#	Untune_parameters() restores the default values (i.e., increases the 
#	values) of any tunable parameters that were previously "lite'ned".
#	Get_lite_tunables() is called in order to retrieve the current list of 
#	"lite" tunables.
#
#	Note that because swremove does *not* support any modifications to the
#	kernel for release 10.0, untune_parameters() does not (cannot) restore 
#	the tunables' default values if invoked from an SD session.  
#	In this case, it merely logs each tunable's name and lite value to the 
#	swagent.log file so that the user can subsequently restore the tunables
#	by hand.
#
# Return value:
#	0	Success
#	1	Failure
#	2	Warning
#===============================================================================
function untune_parameters 
{
	# Declare local variables.
	typeset -i exitstat=$SUCCESS
	typeset param val curval junk

	#
	# Restore (if possible) the default value of each parameter
	# returned by get_lite_tunables().
	#
	get_lite_tunables |
	while read param val junk
	do
		#
		# Query system file for parameter.
		#
		curval=`query_systemfile $SYSTEM $param`
		if [[ $? -ne 0 ]]; then
		    print "WARNING: Query of \"$SYSTEM\" for \"$param\" failed."
		    [[ $exitstat -ne $FAILURE ]] && exitstat=$WARNING
		    continue 
		fi

		#
		# If the parameter isn't in the system file, 
		# or if the parameter's value != its current "lite" value, 
		# don't do anything (retain its value).
		#
		[[ -z "$curval" ]] && continue
        	[[ $curval -ne $val ]] && continue

		#
		# If we've been invoked from an SD session (i.e., swremove), 
		# just echo the tunable's name and lite value to the log file. 
		#
		if [[ -n "$SD_INITIATED" ]]; then
			print "         Delete: $param $val"
			continue
		fi

		#
		# Restore parameter's default value (delete entry).
		#
		mod_systemfile $SYSTEM -d "$param"
		if [[ $? -ne 0 ]]; then
		    print "WARNING: Cannot update \"$SYSTEM\" to restore the"
		    print "         default value of the \"$param\" tunable."
		    [[ $exitstat -ne $FAILURE ]] && exitstat=$WARNING
		    continue
		fi

		# Echo tunable parameter default value restoration.
		print "NOTE:    Restored \"$param\" tunable default value in \"$SYSTEM\"."
	done 

	#
	# Delete "reduced tunables" log file.
	# Also update IPD (delete file) if we've been invoked by SD.
	# Note: we remove this log file here rather than letting swremove
	# delete it.  This is done in order to be consistent with 
	# untune_subsystems() removal of the "saved rc.config.d" log file,
	# and also so that a manual invocation of lite_config will work.
	#
	[[ ! -f $LITE_TUNABLES_LOG ]] && return $exitstat
	rm -f $LITE_TUNABLES_LOG
	# Note: IPD_delfile currently commented out (see IPD_addfile comments).
	# [[ $? -eq 0 && -n "$SD_INITIATED" ]] && IPD_delfile $LITE_TUNABLES_LOG
	return $exitstat
}


#===============================================================================
# Change_rc_conf()
#
# Parameters:
#	$1	Configuration file containing control variable
#	$2	Control variable name
#	$3	Default value of control variable 
#	$4	New (desired) value of control variable
#
# Description: 	
#	Change_rc_conf() does a one-time only change of the indicated control 
#	variable to the new value in the indicated /etc/rc.config.d 
#	configuration file.  It also logs a "change" entry for the control
#	variable to the "saved rc.config.d" log file so that a subsequent
#	"lite_config -u -r" (un-lite'n subsystems) command can work properly,
#	and also to communicate the "lite" (disabled) state to the 
#	corresponding subsystem's fileset.
#
# NOTE: The default value passed in from tune_subsystems() for each control 
#	variable must always *match* the corresponding fileset's default value.
#	This should be verified for each major/minor HP-UX release.
#
# Return value:
#	0	Successfully changed
#	1    	Failure
#	2	No change required
#===============================================================================
function change_rc_conf 
{
	# Declare local variables & pickup parameters.
	typeset configfile=${1##*/}	# Strip off leading directories
	typeset rccfg=${CONFDIR}/${configfile}
	typeset var=$2
	typeset defval=$3
	typeset newval=$4
	typeset curval
	typeset -i status=2		# Assume no change		

	#
	# If we've already changed this control variable,
	# don't change it again (honor user's subsequent modifications).
	#
	grep -q "$configfile $var " $SAVED_RC_LOG && return $status

	#
	# If the corresponding configuration file doesn't exist 
	# (e.g., due to a cold-install and the fact that SD doesn't guarantee
	# any particular install-time ordering of filesets), 
	# then just log a "change" entry to the $SAVED_RC_LOG log file.
	# When the fileset corresponding to this subsystem is 
	# subsequently loaded, it will query this log file looking for 
	# an entry for its control variable.  If found, the fileset's 
	# configure script will disable the subsystem.
	#
	if [[ ! -f $rccfg ]]; then
		print "$configfile $var $defval $newval" >> $SAVED_RC_LOG
		return $status
	fi

	#
	# Change control variable to new value (if needed).
	# Use the ch_rc(1m) utility to get/set the control variable.
	#
	curval=`ch_rc -l -p $var $rccfg`
	[[ $? -ne 0 || -z "$curval" ]] && return $status	
	if [[ $curval -ne $newval ]]; then
	    ch_rc -a -p ${var}=${newval} $rccfg
	    if [[ $? -ne 0 ]]; then
		print "WARNING: Cannot change \"$var\" from \"$curval\""
		print "         to \"$newval\" in \"$rccfg\"."
		return 1
	    fi

	    # Echo message indicating we've changed the control variable.
	    status=0
	    print "NOTE:    Changed \"$var\" from \"$curval\" to \"$newval\" in"
	    print "         \"$rccfg\"." 
	fi			

	#
	# Log a "change" entry.
	# This is done even if the control variable wasn't changed
	# in order to communicate to the subsystem's fileset that the
	# initial installed state of this variable should be "lite" (disabled).
	# Note: we don't get here if the control variable couldn't be changed.
	#
	print "$configfile $var $curval $newval" >> $SAVED_RC_LOG
	return $status
}


#===============================================================================
# Tune_subsystems()
#
# Parameters: 
#	None
#
# Description (called from configure script and from SAM): 	
#	Tune_subsystems() disables several optional subsystems by forcing
#	their control variable(s) in the /etc/rc.config.d/<subsystem> 
#	configuration files to "0".  
#
#	A list of the disabled subsystems is given below along with the 
#	estimated RAM savings (daemon RAM sizes were measured immediately 
#	after system boot and tend to be worst-case since any inactive 
#	pages haven't been pushed out to disk).  
#
#	Disabled Subsystems			~RAM	
#	(Daemons)				Savings	
#       -----------------------------------------------------
#	On-line Diagnostics			1736 KB	
#	(DIAGMON, DEMLOG, MEMLOGP)
#
#	Network Tracing and Logging		668 KB
#	(netfmt, nktl_daemon, ntl_reader)
#
#	uucp(1), vt(1), shl(1)			200 KB
#	(ptydaemon, vtdaemon(1m))
#
#
#	Note that when each subsystem is disabled, a "change" entry is logged 
#	to a special file called the "saved rc.config.d" log file.  
#	This log file is created by tune_subsystems() and is used for the 
#	following purposes:
#		1. To log the original (un-lite'ned) states of the
#		   control variables so that a "lite_config -u -r"
#		   (un-lite'n subsystems) invocation can restore these 
#		   variables.  Lite_config is invoked with the -u -r options
#		   by an swremove (or swconfig -u) of DesktopConfig,
#		   or by selecting SAM's "Lite HP-UX Configuration" button.
#		2. To provide a communications mechanism between DesktopConfig
#	 	   and the associated subsystem's fileset (configure script)
#		   indicating the subsystem should be disabled when it is 
#		   *first* loaded.  See change_rc_conf() for details.
#		3. To prevent multiple invocations of "lite_config -l -r"
#		   from re-lite'ning (disabling) subsystems already disabled.
#
# Return value:
#	0	Success
#	1	Failure
#	2	Warning
#===============================================================================
function tune_subsystems 
{
	# Declare local variables.
	typeset -i exitstat=$SUCCESS
	typeset -i status

	#
	# Create "saved rc.config.d" log file (if not already present).
	#
	if [[ -d $LOGDIR && ! -f $SAVED_RC_LOG ]]; then
		cat > $SAVED_RC_LOG <<End-Of-RcConfig-Header
#
# CAUTION: Do not remove this file !
#
# This file contains a list of those subsystems (or daemons) that have been 
# disabled by the "lite_config" script.  The lite_config script is invoked
# in one of the following two ways:
#
#	1. Swinstall'ing the SD product DesktopConfig.
#	   Note that DesktopConfig is automatically installed whenever the 
#	   SD bundle for Desktop HP-UX is installed.
#	2. Running SAM and selecting the "Apply Lite HP-UX Configuration" 
#	   Action from within any of SAM's Kernel Configuration screens.
#
# Each entry is of the form: 
# <configfile> <control_variable> <previous_value> <lite_value>
#
End-Of-RcConfig-Header

		# Make read-only (note: super-user can still write to this).
		chmod 444 $SAVED_RC_LOG 
	fi

	#
	# Update the IPD if we've been invoked from an SD session.
	# Note: we need to *always* do this because re-installs of 
	# DesktopConfig will wipe-out any previous additions to the IPD.
	#
	# Note: IPD_addfile is currently commented out because it cannot handle
	# "volatile" files (however, swmodify can using "-a is_volatile=true").
	# This eliminates errors produced by an swverify of DesktopConfig.
	#
	# [[ -n "$SD_INITIATED" ]] && IPD_addfile $SAVED_RC_LOG 

	#
	# Disable On-line Diagnostics.
	# No diagnostic error logging, memory page de-allocation, etc. will
	# be available on the system.
	#
	# Note: On-line Diagnostics are *only* disabled via SAM or from a
	#	manual invocation of lite_config.  This is because On-line
	#	Diagnostics are *not* included with the Desktop HP-UX bundle,
	#	and must be explicitly loaded by the user from the support/DART
	#	tape if they are needed.  The Diagnostic filesets *always*
	#	default the subsystem to ON (enabled), and intentionally 
	#	ignore the "saved rc.config.d" log file entry for their 
	#	diagnostics control variable.
	#
	if [[ -z "$SD_INITIATED" ]]; then
		change_rc_conf diagnostic DIAGNOSTICS 1 0 
		status=$?
		[[ $status -eq 1 && $exitstat -ne $FAILURE ]] && \
			exitstat=$WARNING
	fi

	#
	# Disable Network Tracing and Logging; nettl(1m).
	# No network diagnostic error logging will be available on the system. 
	#
	change_rc_conf nettl NETTL 1 0 
	status=$?
	[[ $status -eq 1 && $exitstat -ne $FAILURE ]] && exitstat=$WARNING
	if [[ $status -eq 0 && -n "$SD_INITIATED" ]]; then
	print "         This will disable the Network Tracing and Logging"
	print "         nettl(1m) subsystem, thereby freeing up approximately"
	print "         500K bytes of system memory.  Nettl(1m) is a network"
	print "         based error reporting/troubleshooting facility used by"
	print "         many HP networking products.  If you choose to keep"
	print "         nettl(1m) disabled, then any networking errors that"
	print "         occur during the operation of the system will not be"
	print "         captured and logged.  For more details, run swinstall"
	print "         interactively and look at the \"Readme\" description"
	print "         file for the \"$PRODUCT\" product."
	fi

	#
	# Disable vtdaemon(1m).
	# Vtdaemon is used by vt(1), and by uucp(1) when configured over LAN 
	# with vt(1).
	#
	change_rc_conf vt VTDAEMON_START 1 0 
	status=$?
	[[ $status -eq 1 && $exitstat -ne $FAILURE ]] && exitstat=$WARNING
	if [[ $status -eq 0 && -n "$SD_INITIATED" ]]; then
	print "         This will disable the vtdaemon(1m) daemon process,"
	print "         thereby freeing up approximately 100K bytes of system"
	print "         memory.  Vtdaemon(1m) is used by the vt(1) virtual"
	print "         terminal service, and by uucp(1) when configured to"
	print "         run over a LAN with vt(1).  For more details, refer"
	print "         to the \"Remote Access: User's Guide\" manual."
	fi

	#
	# Disable ptydaemon.
	# Ptydaemon is used by vtdaemon(1m), uucp(1) when configured over LAN 
	# with vt(1), shl(1), etc.
	# We only disable ptydaemon if vtdaemon(1m) was successfully disabled.
	#
	if [[ $status -ne 1 ]]; then
		change_rc_conf ptydaemon PTYDAEMON_START 1 0 
		status=$?
		[[ $status -eq 1 && $exitstat -ne $FAILURE ]] && \
			exitstat=$WARNING
		if [[ $status -eq 0 && -n "$SD_INITIATED" ]]; then
	print "         This will disable the ptydaemon daemon process,"
	print "         thereby freeing up approximately 100K bytes of system"
	print "         memory.  Ptydaemon handles the allocation of pty's"
	print "         (pseudo-terminals) for the following network processes:"
	print "         vtdaemon(1m), shl(1), and uucp(1) when configured to"
	print "         run over a LAN with vt(1).  Most systems will not need"
	print "         to utilize the above processes and can keep the"
	print "         ptydaemon disabled.  For more details, refer to the"
	print "         \"Remote Access: User's Guide\" manual."
		fi
	fi

	# Return
	return $exitstat
}


#===============================================================================
# Untune_subsystems()
#
# Parameters: 
#	None
#
# Description (called from unconfigure script and from SAM): 	
#	Untune_subsystems() re-enables several optional subsystems previously
#	disabled by lite_config.  Subsystems are re-enabled by restoring the 
#	corresponding control variables in the /etc/rc.config.d/<subsystem> 
#	files to their original "un-lite'ned" states.  These original states
#	are kept in the "saved rc.config.d" log file.
#
# Return value:
#	0	Success
#	1	Failure
#	2	Warning
#===============================================================================
function untune_subsystems 
{
	#
	# Declare local variables.
	# Immediately return if no "saved rc.config.d" log file exists.
	#
	typeset -i exitstat=$SUCCESS
	typeset configfile var prevval tunedval rccfg curval junk
	[[ ! -f $SAVED_RC_LOG ]] && return $exitstat

	#
	# Restore control variables to their original "un-lite" values.  
	#
	while read configfile var prevval tunedval junk
	do
		# Skip over leading comments.
		[[ "$configfile" = "#" ]] && continue

		# If configuration file doesn't exist- skip to next one
		rccfg=${CONFDIR}/${configfile##*/}
		[[ ! -f $rccfg ]] && continue

		#
		# Retrieve current value of control variable-- use ch_rc(1m).
		# If current value in configuration file != tuned value
		# (i.e., the value that lite_config last set it to), 
		# then don't do anything -- honor user's latest configuration.
		# Also, if current value = previous value don't do anything.
		#
		curval=`ch_rc -l -p $var $rccfg`
		[[ $? -ne 0 || -z "$curval" ]] && continue
		[[ $curval -ne $tunedval ]] && continue
		[[ $curval -eq $prevval ]] && continue

		#
		# Change the control variable back to its original value.
		#
		ch_rc -a -p ${var}=${prevval} $rccfg
		if [[ $? -ne 0 ]]; then
			print "WARNING: Cannot change \"$var\" from \"$curval\""
			print "         to \"$prevval\" in \"$rccfg\"."
			[[ $exitstat -ne $FAILURE ]] && exitstat=$WARNING
			continue
		fi

		# Echo control variable restoration.
		print "NOTE:    Changed \"$var\" from \"$curval\" to \"$prevval\" in"
		print "         \"$rccfg\"." 
	done < $SAVED_RC_LOG

	#
	# Delete "saved rc.config.d" log file.
	# Also update IPD (delete file) if we've been invoked by SD.
	# Note: we need to remove this log file since we're not guaranteed
	# that SD will remove it (e.g., in the case of a swconfig -u ... ).
	#
	rm -f $SAVED_RC_LOG 
	# Note: IPD_delfile currently commented out (see IPD_addfile comments).
	# [[ $? -eq 0 && -n "$SD_INITIATED" ]] && IPD_delfile $SAVED_RC_LOG
	return $exitstat
}


#===============================================================================
# Set_exitval()
#
# Parameters: 
#	$1	Error status
#
# Description: 	
#	Set the $exitval global to $1 (if not already set to $FAILURE). 
#
# Return value:
#	None
#===============================================================================
function set_exitval 
{
	if [[ $exitval -ne $FAILURE ]]; then
		exitval=$1
	fi
}


#===============================================================================
# Cleanup()
#
# Parameters: 
#	None
#
# Description: 	
#	Cleanup all temporary files.
#
# Return value:
#	None
#===============================================================================
function cleanup 
{
	rm -f $SYSTEM_DRIVERS 
	rm -f $TEMPF
	rm -f $IOSCAN_OUT
	rm -f $IOSCAN_FILTERED_OUT
}


#===============================================================================
#
# MAIN.   
#
#===============================================================================

#
# Do some initial setup.
#
ME="${0##*/}"
SUCCESS=0                       
FAILURE=1
WARNING=2
LITE_MODE=""
COLD_INSTALL=""
SUBSYSTEMS=""
SYSTEM=""
SD_INITIATED=""
exitval=$SUCCESS			
exec 2>/dev/null	# Globally redirect all errors

#
# Determine if we've been invoked by SD initiated processes.
#
[[ -n "${SW_ROOT_DIRECTORY}" ]] && SD_INITIATED="y"


#===============================================================================
#
# Process command line options.
#
#===============================================================================

#
# Make sure we have at least one option.
#
if [[ $# -eq 0 ]]; then
	printusage
	exit $FAILURE
fi

#
# Parse options.
#
while getopts ":lucrs:R:" option
do 
	case $option in

	# "Lite" mode.
	l)	if [[ "$LITE_MODE" = "n" ]]; then
	  		print "ERROR:   -l and -u are mutually exclusive."
			printusage
			exit $FAILURE
		fi
	  	LITE_MODE="y"
		;;

	# "Un-lite" mode.
	u)	if [[ "$LITE_MODE" = "y" ]]; then
	  		print "ERROR:   -l and -u are mutually exclusive."
			printusage
			exit $FAILURE
		fi
	  	LITE_MODE="n"
		;;

	# Cold install environment.
	c)	COLD_INSTALL="y"
		;;

	# Process /etc/rc.config.d subsystems.
	r)	SUBSYSTEMS="y"
		;;

	# Process system file.
	s)	SYSTEM="$OPTARG"
		;;

	# Process system root.
	# Only set $SW_ROOT_DIRECTORY if we're not running within an SD session.
	R) 	[[ -z "$SD_INITIATED" ]] && SW_ROOT_DIRECTORY="$OPTARG"
		;;

	# Invalid option.
	?)	print "ERROR:   Invalid option \"$OPTARG\"."
		printusage
		exit $FAILURE
		;;

	# Missing arguement to either -s or -R options.
	:)	print "ERROR:   Missing arguement for \"$OPTARG\" option."
		printusage
		exit $FAILURE
		;;
	esac
done

#
# Make sure -l or -u has been specified.
#
if [[ -z "$LITE_MODE" ]]; then
	print "ERROR:   You must specify either -l or -u options."
	printusage
	exit $FAILURE
fi

#
# Make sure -r or -s <systemfile> has been specified.
#
if [[ -z "$SUBSYSTEMS" && -z "$SYSTEM" ]]; then
	print "ERROR:   You must specify either -r or -s <systemfile> or both."
	printusage
	exit $FAILURE
fi

#
# Is $SYSTEM readable ?
#
if [[ -n "$SYSTEM" && ! -r "$SYSTEM" ]]; then
	print "ERROR:   \"$SYSTEM\" is not readable."
	exit $FAILURE
fi

#
# Is $SYSTEM writeable ?
#
if [[ -n "$SYSTEM" && ! -w "$SYSTEM" ]]; then
	print "ERROR:   \"$SYSTEM\" is not writable."
	exit $FAILURE
fi

#
# Setup critial SD environment variables (if not already setup by SD).
# Because the sourcing of control_utils *resets* $PATH to $SW_PATH:... ,
# $SW_PATH needs to be properly set-up here.
#
[[ -z "${SW_ROOT_DIRECTORY}" ]] && SW_ROOT_DIRECTORY="/"
[[ -z "${SW_PATH}" ]] && SW_PATH="/usr/lbin/sw/bin:/usr/bin:/usr/ccs/bin"

#
# Setup remaining variables.
#
SYSTEM_DRIVERS="${SW_ROOT_DIRECTORY}tmp/systemdrv$$"
TEMPF="${SW_ROOT_DIRECTORY}tmp/tempfile$$"
IOSCAN="/sbin/ioscan"
IOSCAN_OUT="${SW_ROOT_DIRECTORY}tmp/ioscanout$$"
IOSCAN_FILTERED_OUT="${SW_ROOT_DIRECTORY}tmp/ioscanfil$$"
ioscanned_already=0
CONFDIR="${SW_ROOT_DIRECTORY}etc/rc.config.d"
LOGDIR="${SW_ROOT_DIRECTORY}var/adm/liteconfig"
REMOVED_DRVS_LOG="${LOGDIR}/RemovedDrivers"
LITE_TUNABLES_LOG="${LOGDIR}/ReducedTunable"
SAVED_RC_LOG="${LOGDIR}/SavedRcConf"

#
# Source $UTILS library.
#
UTILS="/usr/lbin/sw/control_utils"
if [[ ! -f $UTILS ]]; then
	print "ERROR:   Cannot find $UTILS"
	exit $FAILURE
fi
. $UTILS

#
# Make sure we cleanup if abnormally terminated.
#
trap "cleanup" HUP INT QUIT TERM ABRT EXIT


#===============================================================================
#
# Execute "lite" mode operations (if selected).
#
#===============================================================================

if [[ "$LITE_MODE" = "y" ]]; then

	#
	# Create logging directory if needed.
	# This is used by lite_config to save away changes made to
	# the system file and/or the /etc/rc.config.d configuration files.
	# This prevents multiple invocations of lite_config from re-"lite'ning"
	# the same portions of the system file, etc.  
	# See the tune_* functions for details.
	#
	if [[ ! -d $LOGDIR ]]; then
		mkdir -p $LOGDIR 
		if [[ $? -ne 0 ]]; then
		    print "ERROR:   Cannot create \"$LOGDIR\" log directory."
		    print "         All \"lite\" changes made to the system"
		    print "         cannot be saved away-- exiting."
		    exit $FAILURE
		fi
		# Make r-x only (note: super-user can still write to this)
		chmod 555 $LOGDIR 
	fi

	#
	# Lite'n system file (if selected):
	#	o "Tune" drivers (remove optional drivers)
	#	o "Tune" parameters (reduce kernel tunable parameters)
	#
	if [[ -n "$SYSTEM" ]]; then
		tune_drivers || set_exitval $?
		tune_parameters || set_exitval $?
	fi

	#
	# Lite'n /etc/rc.config.d subsystems (if selected):
	#	o "Tune" subsystems (disable optional subsystems/daemons)
	#
	if [[ -n "$SUBSYSTEMS" ]]; then
		tune_subsystems || set_exitval $?
	fi
# End 'if [[ "$LITE_MODE" = "y" ]]; then'


#===============================================================================
#
# Execute "un-lite" mode operations (if selected).
#
#===============================================================================

else
	#
	# Un-lite'n system file (if selected):
	#	o "Un-tune" drivers (restore optional drivers)
	#	o "Un-tune" parameters (restore kernel tunable parameters)
	#
	if [[ -n "$SYSTEM" ]]; then
		#
		# If we've been invoked from an SD session (i.e., swremove),
		# issue the following warning message.
		#
		if [[ -n "$SD_INITIATED" ]]; then
		print "WARNING: swremove does not support kernel rebuilding."
		print "         Cannot restore the \"$SW_KERNEL_PATH\" kernel"
		print "         to its original \"un-lite'ned\" state.  If you"
		print "         wish to do so, you must edit \"$SYSTEM\" as"
		print "         indicated below, and rebuild the kernel using"
		print "         \"mk_kernel\" (or alternatively run SAM):"
		print "         * Add the driver(s) listed below (if any)"
		print "         * Delete the tunable parameter settings listed"
		print "           below (if any):"
		set_exitval $WARNING
		fi
		untune_drivers || set_exitval $?
		untune_parameters || set_exitval $?
	fi

	#
	# Un-lite'n /etc/rc.config.d subsystems (if selected):
	#	o "Un-tune" subsystems (restore optional subsystems/daemons)
	#
	if [[ -n "$SUBSYSTEMS" ]]; then
		untune_subsystems || set_exitval $?
	fi

	#
	# Remove logging directory (only if all log files have been removed).
	#
	if [[ ! -f $REMOVED_DRVS_LOG && \
	      ! -f $LITE_TUNABLES_LOG && \
	      ! -f $SAVED_RC_LOG ]]; then
		rmdir -f $LOGDIR 
	fi
fi


#===============================================================================
#
# Cleanup and exit.
#
#===============================================================================

cleanup
exit $exitval
