#!/bin/sh
#
# Make diskless client copy of prototype root directory
#
# Usage:
#	clone_root_proto [-r kvm_report_file] [-s server] [-h home_dir]
#	[-d domain] [-n os_release_name] client_name machine_arch
#
# where <client_name> is the name of the diskless client to be created,
# <machine_arch> is one of 'sun3', 'sun4', 'sun4c', 'Series4', 'Series5',
# 'Series6', or 'S4000', depending on the machine type.
# The optional <-d domain> specifies start up yellow pages
# on the diskless client using the domainname given.
# The optional <-h home_dir> specifies the client's home directory
# The optional <-n os_release_name> specifies the machine & OS release
# level name to use for directories, instead of the default machine_arch.
# The optional <-r kvm_report_file> requests that the name of the client's
# kvm directory be reported in kvm_report_file.
#
# The server directories/information must have already
# been setup.
#
# Copyright (c) 1989 Solbourne Computer, Inc.


#
# Global variables
#

Myname=`basename "$0"`
Usage="[-x] [-r kvm_report_file] [-s server] [-d domain] [-h home_dir] [-n os_release_level] client machine_arch"

#
# Filesystem specific pathnames
#

EXPORT_DIR=${EXPORT_DIR-/export}
EXPORT_ROOT=${EXPORT_ROOT-${EXPORT_DIR}/root}
EXPORT_USR=${EXPORT_USR-${EXPORT_DIR}/exec}
EXPORT_FILE=${EXPORT_FILE-/etc/exports}
LOG=${LOG-/var/log/diskless_log}
MYPATH=${MYPATH-/usr/etc/setup}
SERVER_HOME=${SERVER_HOME-/home}
SERVER_HOSTS=${SERVER_HOSTS-/etc/hosts}
TMP_ERR=/tmp/ins_err$$
KVM_REPORT=

#
# Set up default path
#

PATH=/bin:/usr/bin:/usr/ucb:${MYPATH}
export PATH

#
# Main function - test arguments and verify valid call
#
main()
{

	# Get optional arguments

	while getopts "xd:h:n:s:r:" arg
	do
		case "$arg" in
		d)	DOMAIN="$OPTARG";;
		h)	CLIENT_HOME="$OPTARG";;
		x)	set -x;;
		n)	CLIENT_MACH_NAME="$OPTARG";;
		s)	SERVER="$OPTARG";;
		r)	KVM_REPORT="$OPTARG";;
		*)	usage ;;
		esac
	done

	shift `expr $OPTIND - 1`

	# Test for proper remaining arguments

	if [ $# -ne 2 ]
	then
		usage
	fi

	CLIENT=${1-unknown}
	MACH=${2-unknown}
	MACH_NAME=${CLIENT_MACH_NAME-$MACH}
	DOMAIN=${DOMAIN-"noname"}
	CLIENT_ROOT=${EXPORT_ROOT}/${CLIENT}
	CLIENT_USR=${EXPORT_USR}/${MACH_NAME}
	CLIENT_HOME=${CLIENT_HOME-${CLIENT_ROOT}/home}
	if [ "${MACH_NAME}" = "${MACH}" ]
	then
		ROOT_PROTO=${EXPORT_ROOT}/proto.${MACH_NAME}
	else
		ROOT_PROTO=${EXPORT_ROOT}/${MACH_NAME}
	fi

	# Verify machine architecture

	case "${MACH}" in
	sun2 | sun3 | sun4 | sun4c | sun386 | Series4 | Series5 | Series6 | S4000 ) ;;
	*)
		error "Invalid machine architecture \"${MACH}\""
		exit 1
	esac

	# Verify that prototype root directory for this architecture exists

	if [ ! -d ${ROOT_PROTO} ]
	then
		error "Prototype root directory ${ROOT_PROTO} does not exist"
		error "Use the \"config_server\" command"
		exit 1
	fi

	# Arguments okay.  Record start in log and catch signals

	log "$* Started `date`"
	trap "sig_abort; wrapup 1" 1 2 3 15

	# Do real work in a sub-shell, to capture error output for log
	# Redirect standard input to /dev/null, just in case something
	# tries to read.

	(
		do_cmd ${1+"$@"} 2>&1
	) </dev/null | tee ${TMP_ERR}

	# Record any error output to log, and display to user
	# If there was an error, pass exit status up

	cmp -s ${TMP_ERR} /dev/null
	wrapup $?
}

#
# Verify client name and directories, and do operation
#

do_cmd()
{
	trap 1 2 3 15

	SERVER=${SERVER-`hostname`}

	# Make sure root directory exists

	if [ ! -d ${CLIENT_ROOT} ]
	then
		error "Client root directory \"${CLIENT_ROOT}\" does not exist"
		exit 1
	fi

	/etc/chown root ${CLIENT_ROOT}/. || fatal "Must be super-user" 
	chmod 755 ${CLIENT_ROOT}/. && chmod g+s ${CLIENT_ROOT}

	# If error occurred, have subprocess exit
	if [ $? -ne 0 ]
	then
		exit 1
	fi

	# Verify that client /usr/boot directory exists
	# Must look in two places - /usr/boot and exec/kvm/<arch>/boot

	Usrboot="${CLIENT_USR}/boot"
	if [ ! -d ${Usrboot} -a "$MACH" != "Series4" -a "$MACH" != "Series5"  \
				-a "$MACH" != "Series6"	-a "$MACH" != "S4000" ]
	then
		Usrboot="${EXPORT_USR}/kvm/${MACH_NAME}/boot"
		if [ ! -d ${Usrboot} ]
		then
			fatal "Directory \"${Usrboot}\" does not exist"
		fi
	fi

	# Now do clone

	cd ${ROOT_PROTO}
	find . -depth -print | grep -v "^./tftpboot" | 
			cpio -pdum ${CLIENT_ROOT} 2>/dev/null

	# If error occurred, have subprocess exit
	if [ $? -ne 0 ]
	then
		exit 1
	fi

	if [ "$MACH" != "Series4" -a "$MACH" != "Series5"  \
		-a "$MACH" != "Series6" -a "$MACH" != "S4000" ]
	then
		cd ${Usrboot}
		mkdir ${CLIENT_ROOT}/sbin 2>/dev/null
		List="init mount ifconfig"
		for i in sh hostname intr ../stand/sh ../../../${MACH_NAME}/bin/hostname
		do
			if [ -f "$i" ]
			then
				List="$List $i"
			fi
		done
		cp $List ${CLIENT_ROOT}/sbin
		if [ $? -ne 0 ]
		then
			exit 1
		fi
	fi

	# Preferred location for /vmunix is under kvm because
	# multiple Solbourne client types may symlink their /usr trees
	# so looking under /export/exec/ NOT under kvm is dangerous!

	Unixdir="${EXPORT_USR}/kvm/${MACH_NAME}/stand"
	if [ ! -f ${Unixdir}/vmunix ]
	then
		if [ -f ${Usrboot}/vmunix ]
		then
			Unixdir=${Usrboot}
		elif [ -f ${Usrboot}/../stand/vmunix ]
		then
			Unixdir=${Usrboot}/../stand
		elif [ -f ${Unixdir}/../boot/vmunix ]
		then
			Unixdir=${Unixdir}/../boot
		else
			fatal "Can not find client /vmunix"
		fi
	fi

	if [ ! -f ${Unixdir}/kadb ]
	then
		fatal "Can not find client /kadb"
	fi
	
	cp ${Unixdir}/vmunix ${CLIENT_ROOT} &&
		cp ${Unixdir}/kadb ${CLIENT_ROOT}
	if [ $? -ne 0 ]
	then
		fatal "Can not copy client /vmunix and /kadb"
	fi

	# Make normal home directories

	mkdir ${CLIENT_ROOT}/home ${CLIENT_ROOT}/home/${SERVER} 2>/dev/null

	# If home is nonstandard, we want it too

	if [ ! -d ${CLIENT_HOME}/${SERVER} ]
	then
		mkdir -p ${CLIENT_HOME}/${SERVER} 2>/dev/null
	fi

	# Modify files in client /etc directory

	cd ${CLIENT_ROOT}/etc

	# rc.boot needs to know client real name

	update_rcboot

	# rc.local needs domain and yellow pages updates

	if [ ${DOMAIN} != noname ]; then
		echo ${DOMAIN} > defaultdomain
	fi

	# fstab needs totally new entries

	create_fstab

	# Add server and client inetaddrs from servers /etc/hosts

	update_hosts

	case "${MACH}" in
	sun2 | sun3 | sun4 | sun4c | sun386 )
		# Add /etc/hostname.??0 files for SunOS4.1 and later
	
		echo ${CLIENT} >hostname.le0
		echo ${CLIENT} >hostname.ie0
		echo ${CLIENT} >hostname.ec0
		;;

	Series4 | Series5 | Series6 | S4000 )
		# Don't need anything here; hostname.ei0 will
		# be made by config_system on first boot
		;;

	*)
		error "Invalid machine architecture \"${MACH}\""
		exit 1
	esac
}

#
# Set client name in rc.boot
#

update_rcboot()
{
	if grep -s "set noname.*shcat /etc/hostname" rc.boot
	then
		# SunOS4.1 or later systems use /etc/hostname.??0 files
		ed - rc.boot <<-_EOF_
			H
			g/ifconfig.*shcat/i\\
			 				if ifconfig \$1 >/dev/null 2>/dev/null; then
			g/ifconfig.*shcat/a\\
			 				fi
			w
			q
		_EOF_
	else
		# Pre-SunOS 4.1
		ed - rc.boot <<-_EOF_ 
			H
			g/hostname=/s/.*/hostname=${CLIENT}/
			w
			q
		_EOF_
	fi
}

#
# Build new fstab for client
#

create_fstab()
{
	# Handle home directory more generally

	if [ "${CLIENT_HOME}" != "${CLIENT_ROOT}/home" ]
	then
		Home="${CLIENT_HOME}	/home	nfs	rw 0 0"
		if [ "`expr ${CLIENT_HOME} : '..*\(:\)'`" != ":" ]
		then
			Home="${SERVER}:$Home"
		fi
	else
		Home="#${SERVER}:/home			/home		nfs	rw 0 0"
	fi

	# Check to see if /usr/share needs to be mounted as well

	Share=`(cd /usr/share; /bin/pwd)`

	if [ "$Share" != "/usr/share" ]
	then
		Share="${SERVER}:$Share		/usr/share	nfs	ro 0 0"
	else
		Share="#${SERVER}:/usr/share		/usr/share	nfs	ro 0 0"
	fi

	# Now test for ${EXPORT_DIR}/crash

	if [ -d ${EXPORT_DIR}/crash ]
	then
		Crash="`(cd ${EXPORT_DIR}/crash; /bin/pwd)`"
		Crash="${SERVER}:${Crash}	/var/crash	nfs	rw 0 0"
	else
		Crash="#${SERVER}:${EXPORT_DIR}/crash		/var/crash	nfs	rw 0 0"
	fi

	# Test for new /usr/kvm structure

	if [ -d ${EXPORT_DIR}/exec/kvm/${MACH_NAME} ]
	then
		Kvm="${SERVER}:${EXPORT_DIR}/exec/kvm/${MACH_NAME}	/usr/kvm	nfs	rw 0 0"
	else
		Kvm="#${SERVER}:${EXPORT_DIR}/exec/kvm/${MACH_NAME}	/usr/kvm	nfs	rw 0 0"
	fi

	cat >fstab <<-_EOF_
		${SERVER}:${CLIENT_ROOT}	/		nfs	rw 0 0
		${SERVER}:${CLIENT_USR}	/usr		nfs	rw 0 0
		$Kvm
		$Home
		$Share
		$Crash
	_EOF_

	# For the first Solbourne S4000 release, /usr/include & /usr/share/sys
	# need special treatment.

	Hostarch=`arch -k`

	case "${MACH}" in
	Series4 | Series5 | Series6 | S4000)
		if [ "${Hostarch}" != "${MACH}" ]
		then
			if [ -d ${EXPORT_DIR}/exec/kvm/${MACH_NAME}/include ]
			then
				echo "${SERVER}:${EXPORT_DIR}/exec/kvm/${MACH_NAME}/include	/usr/include	nfs	ro 0 0" >>fstab
			fi
		fi
		;;
	esac

	if [ "X$KVM_REPORT" != "X" ]
	then
		if [ -d ${EXPORT_DIR}/exec/kvm/${MACH_NAME} ]
		then
			echo ${EXPORT_DIR}/exec/kvm/${MACH_NAME} > $KVM_REPORT
		else
			> $KVM_REPORT
		fi
	fi
}

#
# update client /etc/hosts file
#

update_hosts()
{
	# Add server and client inetaddrs to hosts

	if [ "${DOMAIN}" != "noname" ]
	then
		ypmatch ${SERVER} ${CLIENT} hosts | \
			 sed -e 's/[ 	][	 ]*/	/' >>hosts || exit 1
	else
		egrep "${SERVER}|${CLIENT}" <${SERVER_HOSTS} >>hosts || exit 1
	fi

	ed - hosts <<-_EOF_ 
		H
		g/loghost/s///
		g/${CLIENT}/s/$/ loghost/
		w
		q
	_EOF_
}

#
# fatal error - print message and exit
#

fatal()
{
	error $*
	exit 1
}

#
# error() prints an error message to stderr
#

error()
{
	echo "$Myname: $*" 1>&2
}

#
# usage() prints a usage message (usage is in the variable Usage)
#

usage()
{
	echo "usage: $Myname $Usage" 1>&2
	exit 2
}


#
# Signal cleanup.  Print message to user and to log
#

sig_abort()
{
	log "Aborted by signal"
}

#
# Record message in installation log
#
log()
{
	echo "$Myname: $*" >>${LOG}
}

#
# Final command wrap up.  Record errors and completion in log.
# Remove temporary files
#

wrapup()
{
	trap '' 1 2 3 15

	if [ -f ${TMP_ERR} ]
	then
		cat ${TMP_ERR} >>${LOG}
	fi

	log "Completed with status $1 `date`"
	rm -f ${TMP_ERR}
	if [ "$1" != "0" ]
	then
		log "Command failed due to error.  Cleaning up ${CLIENT_ROOT}"
		error "Command failed due to error.  Cleaning up ${CLIENT_ROOT}"
		if [ -d "${CLIENT_ROOT}" ]
		then
			cd ${CLIENT_ROOT}
			rm -rf `ls -a|egrep -v '^\.$|^\.\.$'`
		fi
	fi
	exit $1
}

#
# Perform main function
#

main ${1+"$@"}
exit 0
