#!/sbin/sh
#
#ident  "@(#)rcS.sh 1.147     00/10/29 SMI"
#
# Copyright (c) 1992-1999 Sun Microsystems, Inc.  All Rights Reserved.
#

#
# the 2.X install "rcS" file
# run by init(8) to create the environment for doing the installation
# replaces normal rcS
#
#* init starts
# *     mount tmpfs onto /tmp
# *     copy any needed files into /tmp...
# *     device reconfigure
# *     figure out root and /cdrom
# *     mount /cdrom
#

PLATFORM=`/sbin/uname -p`
export PLATFORM

I386="i386"
SPARC="sparc"
PPC="ppc"

ROOT=/tmp/root
LOGS=${ROOT}/var/sadm/system/logs

Network="no"
FJS_BOOT="no"
DoDrvconfig="yes"
SINGLE_USER=0
USING_DHCP=0

#
# Functions
#

#
# use shell to snarf the base device name so we can make slice 0's name
# now we (only) do OBP style names
# INPUT: $1 - the rootfs device name
# OUTPUT: spits out on stdout the short device name of the cdrom device
#
basedevof() {
    D=$1    # Device
    T=$2    # Type

    # if we had expr on root, this is what we would simply do
    # U=`expr $D : '\(.*\):.*'
    # echo "${U}:a"

    # but we don't have expr and would like to live without it
    # so we use set to separate at all ":"
    IFS=":"
    set -- ${D}
    # get everything up till last ":" into U
    U=$1
    shift ;
    while [ $# -gt 1 ] ; do
        U=${U}:$1
        shift ;
    done
    # now we got everything except the stuff after the last ":",
    # which we assume was just a partition letter

    # x86 & ppc use p0 device for hsfs.  sparc uses s0 device.
    # These map to :q and :a respectively under /devices/...

    if [ "${PLATFORM}" = "${SPARC}" ]; then
        echo "${U}:a"
    else
        if [ "${T}" = "ufs" ]; then
            echo "${U}:b"
        else
            echo "${U}:q"
        fi
    fi
}

#
# Find and mount the CD image using DHCP
#
dhcp_find_and_mount_cdrom() {
	/sbin/dhcpagent -a

	#
	# Look for the root boot parameters;
	# For dhcpinfo:	SrootNM  returns the root file system server name
	#		SrootPTH returns the root file system path
	#
	if rs=`/sbin/dhcpinfo SrootNM` && rp=`/sbin/dhcpinfo SrootPTH` ; then
		Rootfs=$rs:$rp
		#echo "/sbin/rcS.dhcp:  Rootfs = $Rootfs"
		echo "${Rootfs} - / ${Roottype} - no ro" >> /etc/vfstab
	else
		echo "ERROR: dhcpagent unable to access network information"
		exec /sbin/sh
	fi

	#
	# Look for the install boot parameter;
	# For dhcpinfo:	SinstNM  returns the install file system server name
	#		SinstPTH returns the install file system path
	#
	if is=`/sbin/dhcpinfo SinstNM` && ip=`/sbin/dhcpinfo SinstPTH` ; then
		Installfs=$is:$ip
		#echo "/sbin/rcS.dhcp:  Installfs = $Installfs"
	else
		echo "ERROR: dhcpinfo unable to access network install information"
		exec /sbin/sh
	fi

	# Get the server IP address so we can complain about it by name if need be
	DHCPServerAddr=`/sbin/dhcpinfo ServerID`

	# update the hosts file with the proper name to address translation for our
	# install server.
	echo "`/sbin/dhcpinfo SinstIP4`	$is" >> /etc/inet/hosts

	/sbin/mount -F ${Installtype} -o ro ${Installfs} /cdrom >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		# Bad information was returned by this DHCP server
		# display what information is available and 
		# exit to allow the user to correct the situation
		#
		echo "received from DHCP server at $DHCPServerAddr"
		echo "install info:  server $is, path $ip"
		echo "root info:  server $rs, path $rp"
		echo "ERROR:  Unable to NFS mount ${Installfs}"
		echo "             Exiting to shell."
		exec /sbin/sh
	fi
 
	# Verify that the mounted /cdrom is a legal Solaris distribution
	# Do this by looking for .cdtoc
	# 
	if [ ! -f /cdrom/.cdtoc ]; then
		/sbin/umount /cdrom 2>/dev/null
		echo "ERROR: The product distribution does not contain "
		echo "       a product table of contents"
		echo ""
		echo "Type: ${Installtype}, Path: ${Installfs}"
		echo "received from DHCP server at $DHCPServerAddr"
		echo "install info:  server $is, path $ip"
		echo "root info:  server $rs, path $rp"
		exec /sbin/sh
	fi

	echo "${Installfs} - /cdrom ${Installtype} - no ro" >> /etc/vfstab
}

#
# Find and mount the CD image using bootparams
#
bootparams_find_and_mount_cdrom() {
	#
	# net_device_list contains a ":" delimited list
	# of network devices
	# do an auto-revarp on each of them with the
	# exception of the loopback device
	#
	old_ifs=$IFS
	IFS=":"
	set -- $net_device_list
	for i
	do
		#
		# skip the auto-revarp for the loopback device
		#
		if [ "$i" = "lo0" ]; then
			continue
		fi
		/sbin/ifconfig $i auto-revarp -trailers >/tmp/dev.$$ 2>&1
		ipaddr=`/sbin/ifconfig $i |grep inet |awk '{print $2;}'`
		if [ "X$ipaddr" != "X0.0.0.0" ] ; then
			# The interface configured itself correctly
			echo "Configured interface $i"
			/sbin/ifconfig $i up
		else
			echo "Skipping interface $i"
		fi
	done
	IFS=$old_ifs
	/sbin/hostconfig -p bootparams 2> /dev/null

	#
	# if not booting from the net add root entry to 
	# /etc/vfstab 
	#
	if [ "${Network}" != "yes" ]; then
		echo "${Rootfs} - / ${Roottype} - no ro" >> /etc/vfstab
	else
		#
		# Look for the root boot parameter;
		# bpgetfile returns $1 = server name, $2 = server IP addr, $3 = path
		#
		set -- ""
		set -- `/sbin/bpgetfile`
		SERVER_IPADDR=$2
		if [ $2"x" != "x" ]; then
			Rootfs=$1:$3
			echo "${Rootfs} - / ${Roottype} - no ro" >> /etc/vfstab
		else
			echo "ERROR: bpgetfile unable to access network information"
			exec /sbin/sh
		fi

		# get the server's netmask
		if [ -x /sbin/get_netmask ]; then
			netmask=`/sbin/get_netmask $SERVER_IPADDR 2>/dev/null`
			if [ -n "$netmask" ]; then
				/sbin/ifconfig -a netmask 0x${netmask}  >/dev/null 2>&1
			fi
		fi

		#
		# Look for the install boot parameter;
		# bpgetfile returns $1 = server name, $2 server IP addr, $3 = path
		#
		set -- ""
		set -- `/sbin/bpgetfile install`
		if [ $2"x" != "x" ]; then
			Installfs=$2:$3
		else
			echo "ERROR: bpgetfile unable to access network install information"
			exec /sbin/sh
		fi
	fi

	/sbin/mount -F ${Installtype} -o ro ${Installfs} /cdrom >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		if [ "${Installtype}" = "hsfs" ]; then
			# only used internally for testing
			echo "hsfs mount failed, trying ufs..."
			Installfs=`basedevof ${Rootfs} ufs`
			if [ -b ${Installfs} ] ; then
				/sbin/mount -F ufs -o ro ${Installfs} /cdrom
			else
				echo "ERROR: ${Installfs} does not exist, unable to mount /cdrom"
			fi
		else
			# there is a bad entry in the bootparams map
			# display what information is available and 
			# exit to allow the user to correct the situation
			#
			echo "install entry: "`/sbin/bpgetfile install`
			echo "root entry: "`/sbin/bpgetfile`
			echo "ERROR:  Unable to NFS mount ${Installfs}"
			echo "             Exiting to shell."
			exec /sbin/sh
		fi
	fi

	# Verify that the mounted /cdrom is a legal Solaris distribution
	# Do this by looking for .cdtoc
	# 
	if [ ! -f /cdrom/.cdtoc ]; then
		/sbin/umount /cdrom 2>/dev/null
		echo "ERROR: The product distribution does not contain "
		echo "       a product table of contents"
		echo ""
		echo "Type: ${Installtype}, Path: ${Installfs}"
		if [ "${Network}" = "yes" ]; then
			echo "bootparams entries:"
			echo "install entry: "`/sbin/bpgetfile install`
			echo "root entry: "`/sbin/bpgetfile`
		fi
		exec /sbin/sh
	fi

	# Loopback mount the full version of /usr on the cdrom
	# 
	if [ "${Roottype}" != "nfs" ]; then
		/sbin/mount -F lofs /cdrom/Solaris_*/Tools/Boot/usr /usr
		mount_return_code=$?
		if [ $mount_return_code -ne 0 ]; then
			echo "Unable to mount /cdrom/Solaris_*/Tools/Boot/usr"
			exec /sbin/sh
		fi
	fi

	echo "${Installfs} - /cdrom ${Installtype} - no ro" >> /etc/vfstab
}


###################################################
###################################################
#           Main
#

#
# Mount tmpfs and procfs
#
if [ ! -f /tmp/.rcSmnt ]; then
	# mount tmpfs, for now it can't swap so we can't fill it too full
	/sbin/mount -F tmpfs swap /tmp
	if [ $? -ne 0 ]; then
		echo "tmpfs mount failed."
		/sbin/sh
	fi

	# mount proc
	/sbin/mount -F proc proc /proc
	if [ $? -ne 0 ]; then
		echo "proc mount failed."
		/sbin/sh
	fi
	
	# mount mnttab
	#
	/usr/lib/fs/mntfs/mount mnttab /etc/mnttab

	cat < /dev/null > /tmp/.rcSmnt
fi

#
# Check for no reboot flag
#
if [ "${RB_NOBOOTRC}" = "YES" ]; then
	RB_NOBOOTRC="no"
	export RB_NOBOOTRC
	/sbin/sh
fi

if [ -f /tmp/.rcSrun ]; then
	exit 0
fi

DownRevRoss=`echo "downrev_ross_detected/X" | adb /dev/ksyms /dev/kmem | \
	 ( read junk ; read junk ; read junk rev; echo $rev )`

if [ "$DownRevRoss" = "1" ]; then
    echo " "
    echo "The ROSS 605 CPU modules installed in this system are not fully"
    echo "compatible with this version of Solaris.  If this version of Solaris"
    echo "software is installed, this system will run only in uni-processor"
    echo "mode, which will affect performance."
    echo " "
    echo "Please upgrade your CPU module(s) in order to run in multi-processor"
    echo "mode."
    echo " "
    echo "    Do you want to continue with the installation?  If you choose"
    echo "    not to continue, previous system software will be left intact."
    echo "    Continue installation (y/n)?"
    read answer
    if [ "$answer" = "n" ]; then
    echo "Installation stopped. Previous system software has been left intact."
    echo "Please reboot."
	sync;sync
	/sbin/uadmin 2 0  # force it down 
    fi
    echo "WARNING: System performance will be affected. Are you sure (y/n)?"
    read answer
    if [ "$answer" = "n" ]; then
    echo "Installation stopped. Previous system software has been left intact."
    echo "Please reboot."
	sync;sync
	/sbin/uadmin 2 0  # force it down 
    fi
fi

#
# Start the twirling dial
#
if [ -x /sbin/dial ]; then
	dial &
	dial_pid=$!
fi

#    
# Unpack writeable initialized files into /tmp.
# NOTE: send output to /tmp (not /dev/null) to avoid nfs bug on remote
#       ro mounted fs
( cd /.tmp_proto; find . -print -depth | cpio -pdm /tmp 2>/tmp/cpio.out )

mkdir -p /tmp/root/var/sadm/system/logs

MEMSIZE=`/sbin/mem`
echo "Memory free after tmpfs initialization: ${MEMSIZE}" >> ${LOGS}/sysidtool.log
if [ ${MEMSIZE} -lt 4000 ]; then 
    echo "ERROR: ${MEMSIZE}KB is not enough free memory to install Solaris 2"
    /sbin/uadmin 2 0  # force it down
fi

########
# Configured "/" writeable files may not be updated.
#
# create /etc/vfstab (/tmp/root/etc/vfstab)
echo "swap - /tmp tmpfs - no -" >> /etc/vfstab

#
# add the procfs mount line
#
echo "/proc - /proc proc - no -" >> /etc/vfstab

# configure devfs in /tmp/dev and /tmp/devices
# using find | cpio to preserve the directory attributes
find devices dev -depth -print | cpio -pdum /tmp >/dev/null 2>&1

#
# Loopback mount the newly plumbed devices onto the main
# file systems
#
/sbin/mount -F lofs /tmp/devices /devices

/sbin/mount -F lofs /tmp/dev /dev

_INIT_RECONFIG=set; export _INIT_RECONFIG
mkdir -p /tmp/etc
mkdir -p /tmp/etc/sysevent
/usr/lib/sysevent/syseventd -r /tmp
/usr/lib/devfsadm/devfsadmd -r /tmp -p /tmp/root/etc/path_to_inst

#
# PPC/Intel Unbundled Driver support - Sun private interface
# Copy driver scripts and data files onto the system from
# floppy, CD or netinstall image (if they exist). We are
# looking for the rc.d directory in the top level of the floppy
# or in /boot/rc.d on a CD or netinstall image.  Floppy files
# take precedence over CD or net files if the same file exists
# in both places.
#
if [ "${PLATFORM}" = "${I386}" -o "${PLATFORM}" = "${PPC}" ];
then

	/sbin/mount -F pcfs -o ro,foldcase /dev/diskette /mnt >/dev/null 2>&1
	status=$?

	if [ ${status} -ne 0 ]; then
		/sbin/mount -F ufs -o ro /dev/diskette /mnt >/dev/null 2>&1
		status=$?
	fi

	if [ ${status} -eq 0 ]; then
		if [ -d /mnt/rc.d ]; then
			FILES=`/usr/bin/ls /mnt/rc.d`
			if [ ! -z "${FILES}" ]; then
				/usr/bin/mkdir /tmp/diskette_rc.d
				/usr/bin/cp -p -r /mnt/rc.d/* /tmp/diskette_rc.d
			fi
		fi
		if [ -d /mnt/kernel ]; then
			FILES=`/usr/bin/ls /mnt/kernel`
			if [ ! -z "${FILES}" ]; then
				/usr/bin/mkdir -p /tmp/kernel
				/usr/bin/cp -p -r /mnt/kernel/* /tmp/kernel
			fi
		fi
		/sbin/umount /dev/diskette
	fi

	if [ -d /boot/rc.d ]; then
		if [ ! -d /tmp/diskette_rc.d ]; then
			/usr/bin/mkdir /tmp/diskette_rc.d
		fi
		for FILE in `/usr/bin/ls /boot/rc.d`; do
			RCPATH=/boot/rc.d/$FILE
			if [ -f $RCPATH -a ! -f /tmp/diskette_rc.d/$FILE ]; then
				/usr/bin/cp -p $RCPATH /tmp/diskette_rc.d/$FILE
			fi
		done
	fi

	if [ -r /tmp/diskette_rc.d/rcs1.sh ]; then
		/sbin/sh /tmp/diskette_rc.d/rcs1.sh
	fi
fi

#
# read bootargs for the boot device
# if fails - ignore and assume regular install
# if ok - see if preinstall bootargs set
#	and if possible, copy the /devices from the stub

# read prom for default boot dev
# looking for "FD=..."
set -- ""
set -- `/sbin/getbootargs 2>/dev/null`
if [ $# -gt 0 ] ; then
	while [ $# -gt 0 ] ; do
		case $1 in
		#
		# Public flags
		#
		FD=*)
			
			# at end of script, save root dev in /tmp/.preinstall
			# this is an unambiguous indication of stub boot
			FJS_BOOT="yes"
			From=`(IFS="="; set -- $1; echo "$2 $3 $4 $5" )`
			break
			;;

		install)
			INSTALL_BOOT="yes"
			cat < /dev/null > /tmp/.install_boot
			shift
			;;

		dhcp)
			TRY_DHCP="yes"
			shift
			;;

		tape*)
			echo "$1" >/tmp/.cjfiles_method
			shift
			;;

		#
		# Private flags
		#
		mansysid)
			cat < /dev/null > /tmp/.manual-sysid
			shift
			;;

		w)
			cat < /dev/null > /tmp/.nowin
			shift
			;;
		*)
			shift
			;;
		esac
	done
fi


#
# figure out root file system information (ie local or remote)
#
eval `/sbin/get_root -t Roottype -b Rootfs /`

case ${Roottype} in
	ufs|hsfs)            # we are on a ufs or hsfs (local machine)
		# get the name of the device for the Solaris distribution
		Installfs=`basedevof ${Rootfs} ""`
		if [ -b ${Installfs} ] ; then
			break
        else
            # "this never happens" :-)
			echo "ERROR: The Solaris Distribution, ${Installfs} does not exist"
			echo "             Exiting to shell."
			/sbin/sh
		fi
		# the slice 0 is type hsfs
		Installtype=hsfs
		;;
	nfs*)            # we are over the network (nfs, nfs2, nfs3)
		Roottype=nfs
		Network="yes"
		# set Installfs=... from config file from server
		Installtype=nfs
		;;
	*)              # fatal error - unknown "/" filesystem
		# we cannot use it as-is - note all the fs specific changes
		/sbin/dial $dial_pid
		while : ; do
			echo "FATAL ERROR: "/" file system type \"${Roottype}\" is unknown"
			echo "             Exiting to shell."
			/sbin/sh
		done
		;;
esac

#
# Configure network interfaces:
#	- software loopback interface
#	- hardware interfaces
# Complete the network configuration
#
/sbin/ifconfig lo0 plumb
/sbin/ifconfig lo0 127.0.0.1 up

#
# Configure all network interfaces
#
/sbin/ifconfig -a plumb > /dev/null 2>&1

if [ "X${Roottype}" = "Xufs" -o "X${Roottype}" = "Xhsfs" ] ; then
	# Try manually turning DHCP on
	if [ $USING_DHCP -ne 1 -a "X$TRY_DHCP" = "Xyes" ] ; then
		for i in `ifconfig -a |grep "^[a-z0-9]*:" |sed -e "s/: .*$//g"` ; do
			if [ $i = "lo0" ] ; then
				continue
			fi

			echo "Trying DHCP on $i"
			/sbin/ifconfig $i dhcp start wait 120
			if [ $? -eq 0 ] ; then
				echo Success
				USING_DHCP=1
				break
			else
				# No luck, give up on this interface
				/sbin/ifconfig $i dhcp drop
			fi
		done
	fi
else
	# Export net boot configuration strategy. _INIT_NET_IF is set to the
	# interface name of the netbooted interface if this is a net boot.
	# _INIT_NET_STRATEGY is set to the network configuration strategy.
	set -- `/sbin/netstrategy`
	if [ $? -eq 0 ]; then
		if [ "$1" = "nfs" -o "$1" = "cachefs" ]; then
			_INIT_NET_IF="$2"
		fi
		_INIT_NET_STRATEGY="$3"
		export _INIT_NET_IF _INIT_NET_STRATEGY 
	fi

	if [ "X${_INIT_NET_STRATEGY}" = "Xdhcp" ] ; then
		USING_DHCP=1
	fi
fi

#
# Get the complete list of network devices
# so that we can ifconfig them individually
#
for i in `ifconfig -a |grep "^[a-z0-9]*:"` ; do
	echo $i |grep "^[a-z0-9]*:" >/dev/null 2>&1
	if [ $? -eq 1 ]; then
		continue
	fi
	net_device_list="${i}${net_device_list}"
done

if [ $USING_DHCP -eq 1 ] ; then
	echo "Using DHCP for network configuration information."
	dhcp_find_and_mount_cdrom
else
	echo "Using RPC Bootparams for network configuration information."
	bootparams_find_and_mount_cdrom
fi

echo "fd - /dev/fd fd - no -" >> /etc/vfstab
/sbin/mount -F fd /dev/fd

#####
### Intel/PPC private interface for unbundled device drivers
### Execute diskette shell script
if [ ${PLATFORM} = ${PPC} -o ${PLATFORM} = ${I386} ]; then
	if [ -r /tmp/diskette_rc.d/rcs3.sh ]; then
		/sbin/sh /tmp/diskette_rc.d/rcs3.sh
	fi
fi

##########
# now we have /usr, we can load our keyboard mappings
# (architecture specific mechanisms)

# Included from init.d/keymap

#
# Systems with no hardware keyboard ID will provide an eeprom value.
#
if test -x /usr/lib/set_keyboard_layout
then
	/usr/lib/set_keyboard_layout
fi

# Load the keymap for the attached keyboard.
/usr/bin/loadkeys

# Initialize the keyboard defaults

[ -h /dev/kbd -a -x /usr/bin/kbd ] && /usr/bin/kbd -i >/dev/null 2>&1

# end of init.d/keymap code

# save the name of the root device in /tmp/.preinstall
if [ "${FJS_BOOT}" = "yes" -a "${From}" ]; then
	FromDisk=`echo ${From} | ( read d n junk ; echo $d )`
	if [ -b /devices/${FromDisk} ]; then
		lsline=`ls -l /dev/dsk | grep ${FromDisk}`
		if [ "${lsline}" ]; then
			shortname=`( set -- ${lsline} ;
				while [ $# -gt 3 ]; do
					shift;
				done
			if [ "$2" = "->" ]; then echo "$1";
			    else echo "" ; fi )`
			if [ -b /dev/dsk/${shortname} ]; then
				echo /dev/dsk/${shortname} > \
				/tmp/.preinstall
			fi
		fi
	fi
fi

##########
# Intel config cleanup logic
if [ -x /usr/sbin/install.d/atconfig ]; then
	/usr/sbin/install.d/atconfig
fi

#####
### Intel/PPC - Sun private device driver update interface
if [ ${PLATFORM} = ${PPC} -o ${PLATFORM} = ${I386} ]; then
	if [ -r /tmp/diskette_rc.d/rcs9.sh ]; then
		/sbin/sh /tmp/diskette_rc.d/rcs9.sh
	fi
fi

########
# PowerPC Virtual OpenFirmware validation
VOFCHECK=/usr/sbin/install.d/vofcheck
if [ -x ${VOFCHECK} ]; then
	${VOFCHECK}
	if [ $? != 0 ]; then
		if [ ! -z "${dial_pid}" ]; then
			kill $dial_pid >/dev/null 2>&1
		fi
		echo
		echo "ERROR: The Solaris boot diskette must be inserted in the diskette"
		echo "       drive to continue the Solaris installation program."
		echo
		echo "       > Insert the Solaris diskette and press the Enter key."
		echo "         The system will reboot."
		read a < /dev/console
		uadmin 2 0
	fi
fi

#####
# Intel - Initialize boot properties
if [ "`uname -m`" = "i86pc" ] && [ -x /usr/sbin/eeprom ]; then
	/usr/sbin/eeprom -I
fi

###########################################################################
# now we exit rcS, and the rc files bring the system further
# on up (ie networking comes up...)
###########################################################################

if [ ! -z "${dial_pid}" ]; then
	kill $dial_pid >/dev/null 2>&1
fi

cat < /dev/null > /tmp/.rcSrun

exit 0
