#!/usr/bin/sh
#
# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#pragma ident	"@(#)config_tftp.sh	1.4	10/02/23 SMI"
#
# This script is always invoked by libsmoss with three args:
#	<subcmd> <clientname> <client ether address> [<platform>]
# The subcmd must be on of add, delete, and modify.
# The ether address is assumed to be in the usual format of
#	x:x:x:x:x:x
# where x is a one or two digit hex number.
# The platform arg is only provided for add and must be one of
# i86pc, sun4u, sun4us or sun4v.
#

#
# Convert ETHERADDR to canonical form with hex digits in upper case
#
convert_etheraddr()
{
	ether_addr=
	for i in 1 2 3 4 5 6; do
		hex=`echo ${ETHERADDR} | cut -d : -f $i | tr '[a-f]' '[A-F]'`
		ether_addr=${ether_addr}:`echo "ibase = 16 ; $hex" | bc`
	done
	ether_addr=`echo ${ether_addr} | \
   	awk -F: '{printf "%02x%02x%02x%02x%02x%02x", $2, $3, $4, $5, $6, $7}'`

	ETHER_UPPER=`echo ${ether_addr} | tr '[a-f]' '[A-F]'`
}

name_to_ipaddr()
{
	line=`grep -v "^#" /etc/hosts | grep "[	 ]$1[	 ]"`
	hostip=`echo $line | (read hostip junk junk junk; echo $hostip)`
        if [ X"$hostip" != X ]; then
                echo "$hostip"
                return 0
        fi
        echo "ipaddr-for-$1"
        return 0
}

#
# Modify client's bootenv.rc, build grub menu, create boot archive,
# and lofs mount client's /boot area under /tftpboot/<clientname>.
#
add_i386_client()
{
	# lofs mount /boot of client to /tftpboot
	mkdir -p /tftpboot/${CLIENTNAME}
	mount -F lofs /export/root/${CLIENTNAME}/boot /tftpboot/${CLIENTNAME}
	echo "/export/root/${CLIENTNAME}/boot - /tftpboot/${CLIENTNAME} lofs - yes ro" >> /etc/vfstab

	#
	# setup properties in bootenv.rc
	# Note: rootopts should be set to read only to avoid failure of
	#	SMF boot-archive service.
	#
	BOOTENVRC=/export/root/${CLIENTNAME}/boot/solaris/bootenv.rc
	echo "setprop fstype 'nfsdyn'" >> ${BOOTENVRC}
	echo "setprop server-name '${HOSTNAME}'" >> ${BOOTENVRC}
	echo "setprop server-path '/export/root/${CLIENTNAME}'" >> ${BOOTENVRC}
	echo "setprop server-rootopts 'ro'" >> ${BOOTENVRC}

	# create boot archive link to /boot to make them available for tftp
	/sbin/bootadm -a update -R /export/root/${CLIENTNAME} -p ${CLIENTISA}
	if [ $? != 0 ] ; then
		echo "config_tftp(${CLIENTNAME}): boot archive construction failed"
	fi

	rm -f /export/root/${CLIENTNAME}/boot/boot_archive
	rm -f /export/root/${CLIENTNAME}/boot/amd64/boot_archive
	ln /export/root/${CLIENTNAME}/platform/i86pc/boot_archive \
		/export/root/${CLIENTNAME}/boot/boot_archive
	ln /export/root/${CLIENTNAME}/platform/i86pc/amd64/boot_archive \
		/export/root/${CLIENTNAME}/boot/amd64/boot_archive

	if [ ! -f /export/root/${CLIENTNAME}/boot/platform/i86pc/kernel/unix ] ; then
		mkdir -p /export/root/${CLIENTNAME}/boot/platform/i86pc/kernel
		ln /export/root/${CLIENTNAME}/platform/i86pc/kernel/unix \
  /export/root/${CLIENTNAME}/boot/platform/i86pc/kernel/unix
	fi

	if [ ! -f /export/root/${CLIENTNAME}/boot/multiboot ] ; then
		ln /export/root/${CLIENTNAME}/platform/i86pc/multiboot \
  /export/root/${CLIENTNAME}/boot/multiboot

	fi

	if [ ! -f /export/root/${CLIENTNAME}/boot/platform/i86pc/kernel/amd64/unix ] ; then
		mkdir -p /export/root/${CLIENTNAME}/boot/platform/i86pc/kernel/amd64
		ln /export/root/${CLIENTNAME}/platform/i86pc/kernel/amd64/unix \
  /export/root/${CLIENTNAME}/boot/platform/i86pc/kernel/amd64/unix
	fi

	# setup menu.lst file content
	menufile=/export/root/${CLIENTNAME}/boot/grub/menu.lst
	rm -f ${menufile}
	touch ${menufile}
	echo "default=0" >> ${menufile}
	echo "timeout=10" >> ${menufile}
	echo "title Solaris Diskless Client" >> ${menufile}
	echo "	root (nd)" >> ${menufile}
	echo "# If console is on ttya|ttyb, replace kernel line with" >> ${menufile}
	echo "# one of the commented lines" >> ${menufile}
	echo "	kernel /${CLIENTNAME}/multiboot" >> ${menufile}
	echo "#	kernel /${CLIENTNAME}/multiboot -B console=ttya" >> ${menufile}
	echo "#	kernel /${CLIENTNAME}/multiboot -B console=ttyb" >> ${menufile}
	echo "	module /${CLIENTNAME}/boot_archive" >> ${menufile}

	# setup menu.lst.01<ether_addr> link
	convert_etheraddr
	#keep current working directory
	TMP_CURPWD=${PWD}
	rm -f /tftpboot/menu.lst.01${ETHER_UPPER}
	#links need to be relative so first move into the correct directory
	cd /tftpboot
	ln -s ./${CLIENTNAME}/grub/menu.lst ./menu.lst.01${ETHER_UPPER}
	#now move back to the previous working directory to be safe
	cd ${TMP_CURPWD}

	# copy over pxegrub; don't do symlink -- pxegrub must be at top level
	rm -f /tftpboot/01${ETHER_UPPER}
	cp /tftpboot/${CLIENTNAME}/grub/pxegrub /tftpboot/01${ETHER_UPPER}

	echo "\nIf not already configured, enable PXE boot by creating" > /dev/tty
	echo "a macro which contains the following values:" > /dev/tty
	echo "	Boot server IP (BootSrvA) : `name_to_ipaddr ${HOSTNAME}`" > /dev/tty
	echo "	Boot file      (BootFile) : 01${ETHER_UPPER}" > /dev/tty
	echo "\nIf console is on a serial port, edit /tftpboot/menu.lst.01${ETHER_UPPER}" > /dev/tty
	echo "(see comments in the file)." > /dev/tty
}

#
# The only thing to do is recreate client's boot archive.
#
modify_client()
{
	# the client's platform is not provided in this case
	for CLIENTISA in i86pc sun4u sun4v sun4us
	do
		if [ -f /export/root/${CLIENTNAME}/platform/${CLIENTISA}/boot_archive ]; then
			/sbin/bootadm -a update \
				-R /export/root/${CLIENTNAME} -p ${CLIENTISA}
			if [ $? != 0 ] ; then
				echo "config_tftp(${CLIENTNAME}): boot archive update failed"
			fi
		fi
	done
}

#
# Unmount /tftpboot/<hostname>, delete it from /etc/vfstab, delete
# pxegrub, and menu.lst.
#
delete_client()
{
	umount /tftpboot/${CLIENTNAME}
	rmdir /tftpboot/${CLIENTNAME}
	grep -v "[	 ]*/tftpboot/${CLIENTNAME}[ 	]*lofs[ 	]*" \
	    /etc/vfstab > /etc/vfstab.config_tftp
	if [ $? = 0 ] ; then
		mv /etc/vfstab /etc/vfstab-
		mv /etc/vfstab.config_tftp /etc/vfstab
	else
		rm -f /etc/vfstab.config_tftp
	fi

	# The ether addr is not provided on delete, we try to
	# figure it out in order to cleanup.
	ether_upper=`ls -l /tftpboot/menu.lst.* | \
	    grep /tftpboot/${CLIENTNAME} | \
	    cut -f3 -d. | (read ether junk; echo $ether)`
	if [ X"$ether_upper" != X ]; then
		rm -f /tftpboot/menu.lst.$ether_upper
		rm -f /tftpboot/$ether_upper
	fi
}

add_sparc_client()
{
	# lofs mount /boot of client to /tftpboot
	mkdir -p /tftpboot/${CLIENTNAME}
	mount -F lofs /export/root/${CLIENTNAME}/boot /tftpboot/${CLIENTNAME}
	echo "/export/root/${CLIENTNAME}/boot - /tftpboot/${CLIENTNAME} lofs - yes ro" >> /etc/vfstab

	# create boot archive link to /boot to make them available for tftp
	/sbin/bootadm -a update -R /export/root/${CLIENTNAME} -p ${CLIENTISA}
	if [ $? != 0 ] ; then
		echo "config_tftp(${CLIENTNAME}): boot archive construction failed"
	fi

	rm -f /export/root/${CLIENTNAME}/boot/boot_archive
	ln /export/root/${CLIENTNAME}/platform/${CLIENTISA}/boot_archive \
		/export/root/${CLIENTNAME}/boot/boot_archive

	if [ ! -f /export/root/${CLIENTNAME}/boot/platform/${CLIENTISA}/kernel/unix ] ; then
		mkdir -p /export/root/${CLIENTNAME}/boot/platform/${CLIENTISA}/kernel
		ln /export/root/${CLIENTNAME}/platform/${CLIENTISA}/kernel/unix \
  /export/root/${CLIENTNAME}/boot/platform/${CLIENTISA}/kernel/sparcv9/unix
	fi

	if [ ! -f /export/root/${CLIENTNAME}/boot/platform/${CLIENTISA}/kernel/sparcv9/unix ] ; then
		mkdir -p /export/root/${CLIENTNAME}/boot/platform/${CLIENTISA}/kernel/sparcv9
		ln /export/root/${CLIENTNAME}/platform/${CLIENTISA}/kernel/sparcv9/unix \
  /export/root/${CLIENTNAME}/boot/platform/${CLIENTISA}/kernel/sparcv9/unix
	fi

}

merge_bootarchive_filelists()
{
	#
	# Common to all when adding a client: merge the filelist.ramdisk
	# and filelist.safe into one full filelist.ramdisk and an empty
	# filelist.safe.  This is necessary as inetboot does not have the
	# ability to read under the archive to the boot device so all
	# files must be available in the ramdisk.
	#
	SAFE_LIST="/export/root/${CLIENTNAME}/boot/solaris/filelist.safe"
	RAMDISK_LIST="/export/root/${CLIENTNAME}/boot/solaris/filelist.ramdisk"

	# filelist.safe doesn't exist in all the update releases.
	# Checking for filelist.safe may render diskless client configuration
	# of older releases incomplete. Don't check if filelist.safe exists.
	if [ ! -f $RAMDISK_LIST ]; then
		echo "config_tftp(${CLIENTNAME}): missing filelist.ramdisk"
		exit 0
	fi

	# easiest way to accomplish this while preserving existing attributes?
	tmp_filelist=/tmp/filelist.tmp.$$
	cat $RAMDISK_LIST $SAFE_LIST 2> /dev/null | sort -u > $tmp_filelist
	cat $tmp_filelist > $RAMDISK_LIST
	cat < /dev/null > $SAFE_LIST
	rm -f $tmp_filelist
}

add_client()
{

    case ${CLIENTISA} in
	i86pc)
		# test for pxegrub based boot
		if [ ! -f /export/root/${CLIENTNAME}/platform/i86pc/multiboot ] ; then
			exit 0
		fi
		merge_bootarchive_filelists
		add_i386_client
		;;

	sun4u | sun4v | sun4us)
		# test for archive-based boot
		if [ ! -f /export/root/${CLIENTNAME}/boot/solaris/bin/create_ramdisk ] ; then
			exit 0
		fi
		merge_bootarchive_filelists
		add_sparc_client
		;;

	*)
	    	/usr/bin/printf "usage: $0 $1 $2 $3 $4 - invalid isa\n"
		exit 1
		;;
    esac
}

SUBCMD=$1
CLIENTNAME=$2
HOSTNAME=`/usr/bin/hostname`

/usr/bin/printf "config_tftp: $0 $1 $2 $3 $4\n"

case ${SUBCMD} in
    add)
	if [ $# != 4 ]; then
	    	/usr/bin/printf "usage: $0 $1 $2 $3 - no platform specified\n"
		exit 1
	fi
	ETHERADDR=$3
	CLIENTISA=$4
	ETHER_UPPER=
	add_client
	;;
    modify)
	modify_client
	;;
    delete)
	delete_client
	;;
    *)
    	/usr/bin/printf "usage: $0 $1 $2 $3 $4 - invalid command\n"
	exit 1
	;;
esac
