#!/bin/sh

# @(#)install_patch.sh 1.19 95/05/09 SMI; Trusted Solaris 1.X
#
#	Name:		install_patch.sh
#
#	Description:	Script to install an ALASKA patch.  This script
#		installs a patch for the native architecture of the
#		running system and for any diskless clients.
#
PATH="/usr/bin:/usr/ucb:/usr/etc"
export PATH

ARCH_INFO="/etc/install/arch_info"
ARCH_LIST="sun4 sun4c sun4m"
CL_LIST="/etc/install/client_list"
CL_ROOT="/export/root"
DYNAMIC_LOG=etc/tfm/home/dynamic.log
LOAD_MARKER=".patch_loaded"
README="README"
STATIC_LOG=etc/tfm/home/static.log


#
#	Main driver for this program
#
main_driver() {
	this_rev=`what "$README" | get_rev`

	if [ -f "$LOAD_MARKER" ]; then
		prev_rev=`what "$LOAD_MARKER" | get_rev`

		echo \
	  "Revision $prev_rev of the patch has already been loaded." > /dev/tty
		if [ "$prev_rev" = "$this_rev" ]; then
			question="Do you want to reload it? (y/n) "
		else
	   question="Do you want to replace it with revision $this_rev? (y/n) "
		fi

		ans=""
		while [ -z "$ans" ]; do
			echo -n "$question" > /dev/tty
			read ans < /dev/tty

			case "$ans" in
			[Nn]*)	ans=no
				;;

			[Yy]*)	ans=yes
				;;

			*)	ans=""
				;;
			esac
		done

		case "$ans" in
		no)	echo "Aborting load of revision $this_rev of patch."
			exit 1
			;;
		esac
	fi

	mach_arch=`arch -k`
	echo "Installing revision $this_rev of patch for $mach_arch"

	echo "Mounting file systems"
	mount -at cfs

	if [ -d /etc/tfm/nis ]; then
		mach_config=nis_master
	else
		mach_config=nis_client
	fi

	work_done=false

	#
	#	Only do native machine's work if there is a patch (nis_master or
	#	nis client).
	#
	machine_patch=`ls $mach_config.* 2> /dev/null`
	if [ -n "$machine_patch" ]; then
		do_machine
	fi

	#
	#	Only check to what other software architectures are loaded if
	#	there is a nis_client patch.
	#
	client_patch=`ls nis_client.* 2> /dev/null`
	if [ -n "$client_patch" ]; then
		#
		#	Check to what other software architectures are loaded.
		#
		sed -e 's/^[^.][^.]*\.\([^.][^.]*\).*/\1/' "$ARCH_INFO" \
		| while read arch; do
			case "$arch" in
			$mach_arch)
				continue
				;;
			esac

			do_kvm "$arch"
		done
	fi


	#
	#	Only do the diskless work if there is a diskless patch.
	#
	diskless_patch=`ls diskless.* 2> /dev/null`
	if [ -n "$diskless_patch" ]; then
		client_file_list=`ls $CL_LIST.* 2> /dev/null`
		for client_file in $client_file_list; do
			do_diskless
		done
	fi

	if [ "$work_done" = false ]; then
		echo \
		  "This patch is not applicable to this machine configuration."
		exit 0
	fi

	rm -f "$LOAD_MARKER"
	cp "$README" "$LOAD_MARKER"
	exit 0
}


#
#	Function to do the diskless work
#
do_diskless() {
	dl_arch=`expr "$client_file" : "$CL_LIST.sun4.\(.*\).trusted.*"`
	#
	#	If the patch is not supported on this architecture
	#	then we are done early.
	#
	if [ ! -f "diskless.$dl_arch.tar.Z" ]; then
		return
	fi

	echo "Installing revision $this_rev of patch for $dl_arch clients"
	dl_list=`zcat "diskless.$dl_arch.tar.Z" | tar tf -`
	abs_dl_list=`zcat "diskless.$dl_arch.tar.Z" | tar tf - \
		| sed -e 's#^#/#'`

	while read client; do
		work_done=true

		for f_path in $dl_list; do
			cl_f_path="$CL_ROOT/$client/$f_path"
			if [ ! -f "$cl_f_path" ]; then
				continue
			fi
			if [ ! -f "$cl_f_path.orig" ]; then
				echo "Saving $cl_f_path"
				mv "$cl_f_path" "$cl_f_path.orig"
			else
				echo \
			       "$cl_f_path.orig already exists - skipping save"
			fi
		done
		usrbin="$CL_ROOT/$client/usr/bin"
		if [ ! -d "$usrbin" ]; then
			mkdir "$usrbin"
			/usr/etc/setlow "$usrbin"
			chown root "$usrbin"
			chmod 755 "$usrbin"
		fi
		(cd "$CL_ROOT/$client";
		 zcat "$here/diskless.$dl_arch.tar.Z" | tar xsvf -)

		echo \
"Updating dynamic TCB database. Saving log in $CL_ROOT/$client/$DYNAMIC_LOG"
		sync_ctab /etc/security/tcb_dynamic -c "$client" -o $abs_dl_list \
		| sed -e '/^$/d' >> "$CL_ROOT/$client/$DYNAMIC_LOG" 2>&1

		echo \
"Updating static TCB database. Saving log in $CL_ROOT/$client/$STATIC_LOG"
		sync_ctab /etc/security/tcb_static -c "$client" -o $abs_dl_list \
		| sed -e '/^$/d' >> "$CL_ROOT/$client/$STATIC_LOG" 2>&1
	done < "$client_file"
}


#
#	Function to do the work for other kernel software architectures.
#
do_kvm() {
	arch="$1"
	#
	#	If the patch is not supported on this architecture
	#	then we are done early.
	#
	if [ ! -f "nis_client.$arch.tar.Z" ]; then
		return
	fi

	work_done=true

	mach_list=`zcat "nis_client.$arch.tar.Z" \
		| tar tf - "export/exec/kvm/$arch"`
	abs_mach_list=`zcat "nis_client.$arch.tar.Z" \
		| tar tf - "export/exec/kvm/$arch" \
		| sed -e 's#^#/#'`

	echo "All files modified by this script are saved as 'filename.orig'"
	echo "unless 'filename.orig' already exists.  For example, '/etc/rc.local'"
	echo "is saved as '/etc/rc.local.orig'."

	for f_path in $mach_list; do
		if [ ! -f "/$f_path" ]; then
			continue
		fi
		if [ ! -f "/$f_path.orig" ]; then
			echo "Saving /$f_path"
			mv "/$f_path" "/$f_path.orig"
		else
			echo "/$f_path.orig already exists - skipping save"
		fi
	done

	here=`pwd`
	(cd /; zcat "$here/nis_client.$arch.tar.Z" \
	 | tar xsvf - "export/exec/kvm/$arch")

	echo "Updating dynamic TCB database. Saving log in /$DYNAMIC_LOG"
	sync_ctab /etc/security/tcb_dynamic -o $abs_mach_list \
	| sed -e '/^$/d' >> "/$DYNAMIC_LOG" 2>&1

	echo "Updating static TCB database. Saving log in /$STATIC_LOG"
	sync_ctab /etc/security/tcb_static -o $abs_mach_list \
	| sed -e '/^$/d' >> "/$STATIC_LOG" 2>&1
}


#
#	Function to do the native machine's work (nis_client or nis_master)
#
do_machine() {
	#
	#	If the patch is not supported on this architecture
	#	then we are done early.
	#
	if [ ! -f "$mach_config.$mach_arch.tar.Z" ]; then
		return
	fi

	work_done=true

	mach_list=`zcat "$mach_config.$mach_arch.tar.Z" | tar tf -`
	abs_mach_list=`zcat "$mach_config.$mach_arch.tar.Z" | tar tf - \
		| sed -e 's#^#/#' -e "s#/export/exec/kvm/$mach_arch#/usr/kvm#" \
		      -e 's#/export/exec/[^/][^/]*#/usr#'`

	echo "All files modified by this script are saved as 'filename.orig'"
	echo "unless 'filename.orig' already exists.  For example, '/etc/rc.local'"
	echo "is saved as '/etc/rc.local.orig'."

	for f_path in $mach_list; do
		if [ ! -f "/$f_path" ]; then
			continue
		fi
		if [ ! -f "/$f_path.orig" ]; then
			echo "Saving /$f_path"
			mv "/$f_path" "/$f_path.orig"
		else
			echo "/$f_path.orig already exists - skipping save"
		fi
	done

	here=`pwd`
	(cd /; zcat "$here/$mach_config.$mach_arch.tar.Z" | tar xsvf -)

	echo "Updating dynamic TCB database. Saving log in /$DYNAMIC_LOG"
	sync_ctab /etc/security/tcb_dynamic -o $abs_mach_list \
	| sed -e '/^$/d' >> "/$DYNAMIC_LOG" 2>&1

	echo "Updating static TCB database. Saving log in /$STATIC_LOG"
	sync_ctab /etc/security/tcb_static -o $abs_mach_list \
	| sed -e '/^$/d' >> "/$STATIC_LOG" 2>&1
}


#
#	Function to get the revision of the patch.
#
get_rev() {
	sed -n \
		-e '1d' \
		-e 's/^[ 	]*//' \
		-e 's/^[^ 	][^ 	]*[ 	][ 	]*//' \
		-e 's/[ 	].*//' \
		-e 'p'
}

main_driver
