#! /bin/ksh -p
#
# ident "@(#)scvxinstall.ksh 1.4     01/09/24 SMI"
#
# Copyright (c) 2000-2001 by Sun Microsystems, Inc.
# All rights reserved.
#

#####################################################
#
# General comments
#
#####################################################
#
# Scvxinstall provides automatic VxVM installation and root disk
# encapsulation for SunCluster 3.0, hiding the complex steps required and
# protecting the system from user mistakes which can severely impact cluster
# availability.
#
# Among other things, scvxinstall checks for:
#
# - must be run as root
# - all nodes must be run in cluster mode
# - root disk must have slice 2 as the overlap slice (set to entire disk)
# - root disk must have 2 free (unassigned) partitions
# - /global/.devices/node@N must be the only global filesystem on the root disk
# - supported versions of SunOS
#
#####################################################

#####################################################
#
# Global constants which may be set from the environment
#
#####################################################
#
# SC_CDIMAGE_PATHS provides the list of cdimage paths to search in finding
#  the Volume Manager packages.
#
# SC_VXIO_MAJOR specifies the vxio major number.
#
#####################################################


#####################################################
#
# Global Constants
#
#####################################################

# The base directory
typeset -r SC_BASEDIR=/					# Base directory

# The program name
typeset -r PROG=${0##*/}				# Program name
typeset -r ARGS="$*"					# Arguments

# The process ID
typeset -r PID=$$					# Process ID

# SUNWesu is required for use of awk(1)			# SUNWesu
typeset -r SC_ESUPKG=SUNWesu

# Installed VxVM packages
typeset -r SC_VXVM_VXIO_PKG="VRTSvxvm"			# Package sets up vxio
typeset -r SC_VXVM_VERS_PKG="VRTSvxvm"			# Check version
typeset -r SC_VXVM_LIC_PKG="VRTSlic"			# License package
typeset -r SC_VXVM_REQ_PKGS="VRTSvxvm VRTSvmdev"	# Required packages
							# Installed packages
typeset -r SC_VXVM_PKGS="${SC_VXVM_LIC_PKG} ${SC_VXVM_REQ_PKGS} VRTSvmman"

# Set the PATH
typeset SC_BINDIRS=${SC_BASEDIR}usr/cluster/bin:${SC_BASEDIR}usr/cluster/lib/sc
typeset SC_VXBINDIRS=${SC_BASEDIR}usr/sbin:${SC_BASEDIR}etc/vx/bin
PATH=${SC_BINDIRS}:${SC_VXBINDIRS}:/bin:/usr/bin:/sbin:/usr/sbin; export PATH

# /etc/name_to_major
typeset -r SC_NAME_TO_MAJOR=${SC_BASEDIR}etc/name_to_major
typeset -r SC_VXIO_MAJOR=${SC_VXIO_MAJOR:-210}

# /etc/vfstab
typeset -r SC_VFSTAB=${SC_BASEDIR}etc/vfstab

# Log files
typeset -r SC_LOGDIR=${SC_BASEDIR}var/cluster/logs/install # install logs
typeset -r SC_LOGFILE=${SC_LOGDIR}/${PROG}.log.${PID}	# log file

# Temp files
typeset -r SC_TMPDIR=${SC_BASEDIR}var/cluster/run	# temp directory
typeset -r SC_SCVXDIR=${SC_TMPDIR}/${PROG}		# my temp directory
typeset -r SC_ADMIN=${SC_SCVXDIR}/${PROG}.admin		# pkgadd admin file
typeset -r SC_RSP=${SC_SCVXDIR}/${PROG}.response	# pkgadd response file
typeset -r SC_LOCKFILE=${SC_SCVXDIR}/${PROG}.lock	# lock file
typeset -r SC_ROOTDGFILE=${SC_SCVXDIR}/${PROG}.rootdg	# rootdg file
typeset -r SC_TMPERR=${SC_SCVXDIR}/${PROG}.errs.${PID}	# temp error file

# flag files to remember stuff we've already done
typeset -r SC_COMPLETE=${SC_SCVXDIR}/${PROG}.complete
typeset -r SC_RUNRC=${SC_SCVXDIR}/${PROG}.runrc

# scconf error codes
typeset -r SC_SCCONF_EBUSY=12

# cdrom
#
#  There must be an SC_CDIMAGE_OS_ARRAY element for each supported release
#  of SunOS (as given by uname -r).   And, there must be an array element
#  in SC_CDIMAGE_PATHS_ARRAY listing all supported cdimage path components
#  for each OS element.  There is a one-to-one correspondence between
#  the elements in SC_CDIMAGE_OS_ARRAY and SC_CDIMAGE_PATHS_ARRAY.
#
#  In scvx_init(), SC_CDIMAGE_PATHS is set to the correct list of path
#  components for the installed SunOS, if it is not otherwise first set
#  in the caller's environment.
#
typeset -r SC_DFLT_CDIMAGE=/cdrom/cdrom0
typeset SC_CDIMAGE_OS_ARRAY
typeset SC_CDIMAGE_PATHS_ARRAY
set -A SC_CDIMAGE_OS_ARRAY
set -A SC_CDIMAGE_PATHS_ARRAY

SC_CDIMAGE_OS_ARRAY[0]=5.8				# SunOS 5.8
SC_CDIMAGE_PATHS_ARRAY[0]="pkgs Solaris_8/pkgs"

# VxVM generated files that we check for the existence of
typeset -r SC_VXVM_ENCAP_CONFIGFILE=${SC_BASEDIR}etc/vx/reconfig.d/disks-cap-part		# file that contains the CTD name of the rootdisk to be encapsulated

# Other junk
typeset -r SC_VXVM_LICENSE_FEATURES="VXVM SSA"		# not used
typeset -r SC_VXVM="Volume Manager"
integer -r SC_ABORT_TIMEOUT=20

#####################################################
#
# Global Variables
#
#####################################################
typeset SC_NODES				# list of configured nodes
typeset SC_MYNODENAME				# my node name
typeset SC_MYNODEID				# my nodeid
typeset SC_FIRSTNODE				# "first" node
typeset SC_SUNOS				# SunOS release
typeset SC_CDIMAGE_PATHS			# cdrom image paths per OS
typeset SC_ROOTCTD				# root disk name (cNtNdN)
typeset SC_ROOTDISK				# root disk name (cNtNdNs2)
typeset SC_ROOTRDSK				# root dev (/dev/rdsk/cNtNdNs2)
typeset SC_ROOTARG				# -R arg for pkg commands

typeset SC_PERFORM_ENCAP			# do encap ("true" or "false")
typeset SC_PKG_PATH				# path to packages
typeset SC_LICENSES				# array of license tokens
set -A SC_LICENSES

integer SC_REBOOT_REQUIRED=0			# reboot flag


######################################################################
######################################################################

#####################################################
#
# cleanup() [exitstatus]
#
#	exitstatus			status with which to exit
#
#	Cleanup lock files and other temp files.
#
#	If "exitstatus" is given, exit with that status.
#
#	This function either does not return or always returns 0.
#
#####################################################
cleanup()
{
	typeset exitstatus=$1

	# If we do not own the lock file, we are done
	if [[ -f ${SC_LOCKFILE} ]] && [[ "$(cat ${SC_LOCKFILE})" != ${PID} ]]; then
		if [[ -n "${exitstatus}" ]]; then
			exit ${exitstatus}
		fi
		return 0
	fi

	# Cleanup lock file and other temp files
	rm -f ${SC_ADMIN} ${SC_RSP} ${SC_ROOTDGFILE} ${SC_LOCKFILE} ${SC_TMPERR}

	if [[ -n "${exitstatus}" ]]; then
		exit ${exitstatus}
	fi
	return 0
}

#####################################################
#
# verify_isroot()
#
#       Print an error message and return non-zero
#       if the user is not root.
#
#####################################################
verify_isroot()
{
	typeset -r uid=$(expr "$(id)" : 'uid=\([0-9]*\)*')  

        # make sure uid was set
	if [[ -z "${uid}" ]]; then
		printf "$(gettext '%s:  Cannot get uid.')\n" ${PROG} >&2
		return 1
	fi

	# check for root
	if [[ ${uid} -ne 0 ]]; then
		printf "$(gettext '%s:  Must be root.')\n" ${PROG} >&2
		return 1
	fi

	return 0      
}

#####################################################
#
# openlog
#
#	Create the log file.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
openlog()
{
	echo "\n${PROG} ${ARGS}\n" >>${SC_LOGFILE} || return 1

	return 0
}

#####################################################
#
# logmsg()
#
#	Print stdin to stdout and to the install log file.
#	If the install log has not been created, just
#	print to stdout.
#
#####################################################
logmsg()
{
	if [[ ! -f "${SC_LOGFILE}" ]]; then
		cat
	else
		tee -a ${SC_LOGFILE}
	fi
}

#####################################################
#
# logerr()
#
#	Print stdin to stderr and to the install log file.
#	If the install log has not been created, just
#	print to stderr.
#
#####################################################
logerr()
{
	if [[ ! -f "${install_log}" ]]; then
		cat >&2
	else
		tee -a ${install_log} >&2
	fi
}

#####################################################
#
# scvx_get_online_nodecount()
#
#	Print the number of online nodes.
#
#	Return values:
#
#		zero		always returned
#
#####################################################
scvx_get_online_nodecount()
{
	(
		LANG=C; export LANG;
		scstat -n | awk '
			BEGIN {
				i=0
			}

			/^ *Cluster node:/ {
				if ($4 == "Online")
					++i
			}

			END {
				print i
			}
		'
	)

	return 0
}

#####################################################
#
# scvx_get_nodecount()
#
#	Print the number of configured nodes.
#
#	SC_NODES must be set before calling this function.
#
#	Return values:
#
#		zero		always returned
#
#####################################################
scvx_get_nodecount()
{
	if [[ -n "${SC_NODES}" ]]; then
		set -- ${SC_NODES};  echo $#
	fi

	return 0
}

#####################################################
#
# scvx_get_nodelist()
#
#       Print the list of configured nodes.
#
#	Return values:
#
#		zero		always returned
#
#####################################################
scvx_get_nodelist()
{
        (
		LANG=C; export LANG
		scconf -p | sed -n 's/^ *Cluster nodes:[ 	]*\(.*\)/\1/p'
	)

	return 0
}                

#####################################################
#
# verify_ismember
#
#
#       Print an error message and return non-zero
#       if this node is not a member of the cluster.
#
#####################################################
verify_ismember()
{
        if [[ -x /usr/sbin/clinfo ]]; then
                /usr/sbin/clinfo > /dev/null 2>&1
                if [[ $? -eq 0 ]]; then
                        return 0
                fi
        fi

	printf "$(gettext '%s:  This node is not currently in the cluster.')\n" ${PROG} | logerr
        return 1
}

#####################################################
#
# verify_fullmembership
#
#       Print an error message and return non-zero
#       if not all configured nodes are currently members
#	of the cluster.
#
#	This function assumes that verify_ismember() has already
#	been called.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
verify_fullmembership()
{
	integer config_count=$(scvx_get_nodecount)
	integer online_count=$(scvx_get_online_nodecount)
	integer errs=0

	# If verify_ismember() was called, then WE should at least be configed
	if [[ ${config_count} -eq 0 ]]; then
		printf "$(gettext '%s:  Internal error - bad node count.')\n" ${PROG} | logerr
		((errs+=1))
	fi

	# If verify_ismember() was called, then WE should at least be Online
	if [[ ${online_count} -eq 0 ]]; then
		printf "$(gettext '%s:  Internal error - bad membership count.')\n" ${PROG} | logerr
		((errs+=1))
	fi

	if [[ ${errs} -ne 0 ]]; then
		return 1
	fi

	# Make sure that the two counts are identical
	if [[ ${config_count} -ne ${online_count} ]]; then
		printf "$(gettext '%s:  All nodes must be current members of the cluster.')\n" ${PROG} | logerr
		return 1
	fi

	return 0
}

#####################################################
#
# verify_isquorum_init
#
#
#       Print an error message and return non-zero
#       if the cluster quorum is not yet initialized.
#
#####################################################
verify_isquorum_init()
{
	typeset mode
	integer isenabled

	isenabled=$(
		LANG=C; export LANG
		mode="$(scconf -p | sed -n 's/^Cluster install mode:[   ]*\([^ ]*\).*/\1/p')"
                if [[ -n "${mode}" ]] && [[ "${mode}" == "enabled" ]]; then
                        echo 1
                else
                        echo 0
                fi
        )

	if [[ ${isenabled} -eq 1 ]]; then
		printf "$(gettext '%s:  Cluster \"installmode\" is still enabled.')\n" ${PROG} | logerr
		printf "$(gettext '%s:  Please run scsetup(1M) to initialize quorum and disable \"installmode\".')\n" ${PROG} | logerr
		return 1
	fi

        return 0
}

#####################################################
#
# scvx_init()
#
#	Perform general initialization.
#
#	It verifies that SUNWesu is installed.
#
#	It initializes the following global variables:
#		SC_NODES
#		SC_FIRSTNODE
#		SC_MYNODENAME
#		SC_MYNODEID
#		SC_SUNOS
#		SC_CDIMAGE_PATHS
#		SC_ROOTCTD
#		SC_ROOTDISK
#		SC_ROOTRDSK
#		SC_ROOTARG
#
#	It creates /var/cluster/run/${PROG}, if it is not already there.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
scvx_init()
{
	typeset node
	typeset tmp_array

	typeset special
	integer i

	#
	# Make sure that SUNWesu is installed
	#
	scvx_is_pkg_installed ${SC_ESUPKG}
	if [[ $? -ne 0 ]]; then
		printf "$(gettext '%s:  \"%s\" is not installed.')\n" ${PROG} ${ESUPKG} | logerr
		return 1
	fi

	#
	# Set SC_NODES, the list of configured cluster nodes
	#
	SC_NODES="$(scvx_get_nodelist)"
	if [[ -z "${SC_NODES}" ]]; then
		printf "$(gettext '%s:  Unable to establish the list of cluster nodes.')\n" ${PROG} | logerr
		return 1 
	fi

	#
	# Set SC_FIRSTNODE
	#
	set -A tmp_array ${SC_NODES}
	SC_FIRSTNODE=${tmp_array[0]}

	#
	# Set SC_MYNODENAME, the name of this node
	#
	SC_MYNODENAME=$(uname -n)
	if [[ -z "${SC_MYNODENAME}" ]]; then
		printf "$(gettext '%s:  Unable to determine the name of this node.')\n" ${PROG} | logerr
		return 1
	fi

	# Make sure my nodename is in the list
	let found=0
	for node in ${SC_NODES}
	do
		if [[ ${node} == ${SC_MYNODENAME} ]]; then
			let found=1
			break
		fi
	done
	if [[ ${found} -eq 0 ]]; then
		printf "$(gettext '%s:  Solaris node name does not match cluster node name for this node.')\n" ${PROG} | logerr
		return 1
	fi

	#
	# Get my node ID, SC_MYNODEID
	#
	SC_MYNODEID=$(clinfo -n)
	if [[ -z "${SC_MYNODEID}" ]]; then
		printf "$(gettext '%s:  Unable to determine the node ID for this node.')\n" ${PROG} | logerr
		return 1
	fi

	#
	# Set SC_SUNOS and SC_CDIMAGE_PATHS
	#
	SC_SUNOS=$(uname -r)

	# Make sure we support the SunOS, and get the index
	let i=0
	while [[ -n "${SC_CDIMAGE_OS_ARRAY[i]}" ]]
	do
		if [[ "${SC_CDIMAGE_OS_ARRAY[i]}" == "${SC_SUNOS}" ]]; then
			break
		fi
		((i += 1))
	done
	if [[ -z "${SC_CDIMAGE_OS_ARRAY[i]}" ]]; then
		printf "$(gettext '%s:  This version of %s is not supported.')\n" ${PROG} "Solaris (SunOS ${SC_SUNOS})" | logerr
		return 1
	fi

	# If not already set, set SC_CDIMAGE_PATHS
	if [[ -z "${SC_CDIMAGE_PATHS}" ]]; then
		SC_CDIMAGE_PATHS="${SC_CDIMAGE_PATHS_ARRAY[i]}"
		if [[ -z "${SC_CDIMAGE_PATHS}" ]]; then
			printf "$(gettext '%s:  Internal error - no %s.')\n" ${PROG} "PATHS" | logerr
			return 1
		fi
	fi

	#
	# Set SC_ROOTCTD, SC_ROOTDISK and SC_ROOTRDSK
	#
	special=$(mount -V / | awk '{ print $(NF -1) }')

	# Make sure that this is not a DID device
	if [[ "${special}" == /dev/did/dsk/d*s[0-7] ]];  then
		printf "$(gettext '%s:  The root file system is mounted on a DID device.')\n" ${PROG} | logerr 
		return 1
	fi

	# Also, make sure that this is a regular Solaris disk name
	# The logic to test and use the root device doesn't 
	#  work after encapsulation.  
	scvx_is_encapsulation_done
	if [[ $? -ne 1 ]]; then
	        if [[ "${special}" != /dev/dsk/c*t*d*s[0-7] ]];  then
		      printf "$(gettext '%s:  The root file system is mounted on an unrecognized device.')\n" ${PROG} | logerr
		      return 1
		fi

		# Remove the path and change the slice to s2
		special=$(IFS=/ ; set -- ${special};  shift 3;  echo $1)
		SC_ROOTCTD=$(IFS=s ; set -- ${special};  echo $1)
		SC_ROOTDISK=${SC_ROOTCTD}s2
		SC_ROOTRDSK=/dev/rdsk/${SC_ROOTDISK}
	fi

	#
	# Set SC_ROOTARG
	#
	if [[ -n "${SC_BASEDIR}" ]] && [[ "${SC_BASEDIR}" != "/" ]]; then
		SC_ROOTARG="-R ${SC_BASEDIR}"
	else
		SC_ROOTARG=
	fi

	#
	# If necessary, create the temp directory for scvxinstall
	#
	if [[ ! -d "${SC_TMPDIR}" ]]; then
		printf "$(gettext '%s:  Cannot find directory %s.')\n" ${PROG} "${SC_TMPDIR}" | logerr
		return 1
	fi
	if [[ ! -d "${SC_SCVXDIR}" ]]; then
		mkdir -m 0755 ${SC_SCVXDIR}
		if [[ $? -ne 0 ]]; then
			printf "$(gettext '%s:  Unable to create %s.')\n" ${PROG} "${SC_SCVXDIR}" | logerr
			return 1
		fi
		chgrp sys ${SC_SCVXDIR}
		if [[ $? -ne 0 ]]; then
			printf "$(gettext '%s:  Unable to set group for %s.')\n" ${PROG} "${SC_SCVXDIR}" | logerr
			return 1
		fi
	fi

	return 0
}

#####################################################
#
# scvx_setlock()
#
#       Check for the "lockfile".  If it already
#       exists, print an error, and return with non-zero.
#       Otherwise, cleanup any old temp files and create a new
#	lockfile with our pid inside.
#
##################################################### 
scvx_setlock()
{
        # Check for SC_LOCKFILE
        if [[ -f ${SC_LOCKFILE} ]]; then
                printf "$(gettext '%s:  Another instance of this program may already be running.')\n" ${PROG} | logerr
                printf "$(gettext '%s:  If not, remove %s and try again.')\n" ${PROG} "${SC_LOCKFILE}" | logerr
                return 1
        fi

	# Cleanup any old temp files
	cleanup

        # Create lockfile
        echo ${PID} >${SC_LOCKFILE} || return 1

        return 0      
}

#####################################################
#
# show_usage()
#
#	Show scvxinstall usage info
#
#	Return values:
#
#		zero		always returned
#
#####################################################
show_usage()
{
	printf "%s:  %s -s\n" "$(gettext 'usage')"  ${PROG}
	printf "\t%s [-L <license> ...] [-d <cdrom>]\n" ${PROG}
	printf "\t%s -i|-e [-L <license> ...] [-d <cdrom>]\n" ${PROG}
	printf "\t%s -H\n" ${PROG}
	echo

	printf "    $(gettext 'Options:')\n"
	printf "\t    %-20s%s\n" "-s" "$(gettext 'show status')"
	printf "\t    %-20s%s\n" "-i" "$(gettext 'install only')"
	printf "\t    %-20s%s\n" "-e" "$(gettext 'install and encapsulate')"
	printf "\t    %-20s%s\n" "-L <license>" "$(gettext 'license token')"
	printf "\t    %-20s%s\n" "-d <cdrom>" "$(gettext 'cdrom image directory')"
	printf "\t    %-20s%s\n" "-H" "$(gettext 'show this message')"
	echo

	return 0
}

#####################################################
#
# show_status()
#
#	Show status of vxvm installation.
#
#	Return values:
#
#		zero		always returned
#
#####################################################
show_status()
{
	integer vxvm_installed=0
	typeset feature
	typeset features

	if [[ -f ${SC_COMPLETE} ]]; then
                printf "$(gettext '%s has already been run to completion on this node.')\n" ${PROG} | logmsg
	fi

	# Print status of DMP
	scvx_is_dmp_disabled
	if [[ $? -eq 0 ]]; then
		printf "$(gettext '%s is disabled.')\n" DMP | logmsg
	else
		printf "$(gettext '%s is NOT disabled.')\n" DMP | logmsg
	fi

	# Print status of VxVM package installation
	scvx_is_pkgadd_done
	if [[ $? -eq 0 ]]; then
		printf "$(gettext 'The %s package installation step is complete.')\n" "${SC_VXVM}" | logmsg
		((vxvm_installed+=1))
	else
		printf "$(gettext 'The %s package installation step is NOT complete.')\n" "${SC_VXVM}" | logmsg
	fi

	# Print status of name-to-major changes
	scvx_is_ntm_done
	case $? in
	0)	printf "$(gettext 'The %s major number is set to %d.')\n" "vxio" ${SC_VXIO_MAJOR} | logmsg
		;;
	1)	printf "$(gettext 'The %s major number is NOT set.')\n" "vxio" | logmsg
		;;
	2)	printf "$(gettext 'The %s major number is NOT set to %d.')\n" "vxio" ${SC_VXIO_MAJOR} | logmsg
		;;
	esac

	# Print status of license setting
	features="$(scvx_is_licensing_done)"
	for feature in ${features}
	do
		printf "$(gettext 'The \"%s\" %s feature is licensed.')\n" ${feature} "${SC_VXVM}" | logmsg
	done
	if [[ -z "${features}" ]]; then
		printf "$(gettext 'None of the %s features are licensed.')\n" "${SC_VXVM}" | logmsg
	fi

	# Print status of VxVM root disk encapsulation
	scvx_is_encapsulation_done
	if [[ $? -eq 0 || $? -eq 1 ]]; then
		printf "$(gettext 'The %s root disk encapsulation step is completed.')\n" "${SC_VXVM}" | logmsg
	else
		printf "$(gettext 'The %s root disk encapsulation step is NOT completed.')\n" "${SC_VXVM}" | logmsg
	fi

	# Print status of vfstab
	scvx_is_vfstab_update_done
	if [[ $? -eq 0 ]]; then
		printf "$(gettext 'The %s file includes the necessary updates.')\n" /etc/vfstab | logmsg
	else
		printf "$(gettext 'The %s file does NOT include the necessary updates.')\n" /etc/vfstab | logmsg
	fi

	# Print status of reminor state
	scvx_is_reminor_done
	if [[ $? -eq 0 ]]; then
		printf "$(gettext 'The %s %s step is complete.')\n" "rootdg" "reminoring" | logmsg
	else
		printf "$(gettext 'The %s %s step is NOT complete.')\n" "rootdg" "reminoring" | logmsg
	fi

	return 0
}

#####################################################
#
# scvx_get_action()
#
#	Set SC_PERFORM_ENCAP to "true" or "false", based
#	on response from the user.
#
#	Return values:
#
#		zero		always returned
#
#####################################################
scvx_get_action()
{
	typeset answer
	typeset foo

	typeset lyes="$(gettext 'yes')"
	typeset lno="$(gettext 'no')"

	answer=
	echo
	while [[ -z "${answer}" ]]
	do
		printf "$(gettext 'Do you want %s to encapsulate root [no]?  ')\a" "${SC_VXVM}"
		read answer foo

		# Default?
		if [[ -z "${answer}" ]]; then
			answer="${lno}"
		fi

		# White space?
		if [[ -n "${foo}" ]]; then
			answer=
			continue
		fi

		# If English, allow y, Y, yes, YES, n, N, no, NO
		if [[ "${lyes}" == "yes" ]] && [[ "${lno}" == "no" ]]; then
			answer=$(echo ${answer} | nawk '{ print tolower($1) }')
			if [[ "${answer}" == "y" ]]; then
				answer=yes
			elif [[ "${answer}" == "n" ]]; then
				answer=no
			fi
		fi

		# Make sure the answer is yes or no
		if [[ "${answer}" != "${lyes}" ]] &&
		    [[ "${answer}" != "${lno}" ]];  then
			printf "$(gettext 'Please answer \"%s\" or \"%s\".')\n\n\a" "${lyes}" "${lno}"
			answer=
			continue
		fi
	done
	echo

	if [[ "${answer}" == "${lyes}" ]]; then
		SC_PERFORM_ENCAP=true
	else
		SC_PERFORM_ENCAP=false
	fi

	return 0
}

#####################################################
#
# scvx_check_pkgpath() pkg_path
#
#	pkg_path		package path to test
#
#	Check to see if the given "pkg_path" leads to the VxVM
#	packages.  If one or more of the packages are not found,
#	print the list to stdout.
#
#	Return values:
#
#		zero		the VxVM packages are found
#		non-zero	the VxVM packages are not found
#
#####################################################
scvx_check_pkgpath()
{
	typeset pkg_path=${1}

	typeset pkg
	integer errs

	# verify path
	if [[ ! -d "${pkg_path}" ]]; then
		echo ${SC_VXVM_PKGS}
		return 1
	fi

	# verify packages
	let errs=0
	for pkg in ${SC_VXVM_PKGS}
	do
		if [[ ! -d ${pkg_path}/${pkg} ]]; then
			# Skip the license package as it only appears in 
			# versions 3.2 and later
			if [[ ${pkg} == ${SC_VXVM_LIC_PKG} ]]; then
				continue
			fi
			echo ${pkg}
			((errs += 1))
		fi
	done

	return ${errs}
}

#####################################################
#
# scvx_construct_pkgpath() pkg_path_base
#
#	pkg_path_base		package path base
#
#	Use the "pkg_path_base" and the list of package paths
#	in SC_CDIMAGE_PATHS to construct a complete package path.
#	If one is found, it is printed on stdout.
#
#	Return values:
#
#		zero		complete package path found
#		non-zero	cannot find VxVM packages
#
#####################################################
scvx_construct_pkgpath()
{
	typeset pkg_path_base=${1}
	typeset cdimage_paths

	# Make sure it is set to something
	if [[ -z "${pkg_path_base}" ]]; then
		return 1
	fi

	# Maybe we don't need to add anything
	scvx_check_pkgpath ${pkg_path_base} >/dev/null
	if [[ $? -eq 0 ]]; then
		echo ${pkg_path_base}
		return 0
	fi

	# Search the list of SC_CDIMAGE_PATHS
	for cdimage_path in ${SC_CDIMAGE_PATHS}
	do
		scvx_check_pkgpath ${pkg_path_base}/${cdimage_path} >/dev/null
		if [[ $? -eq 0 ]]; then
			echo ${pkg_path_base}/${cdimage_path}
			return 0
		fi
	done

	# Not found
	return 1
}

#####################################################
#
# scvx_get_location() [is_interactive]
#
#	is_interactive			if set, prompt user
#
#	If packages are not already installed, this function
#	sets or resets SC_PKG_PATH, upon success.
#	If "is_interactive" is set, the user is prompted.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
scvx_get_location()
{
	typeset is_interactive=${1}

	typeset pkg_path
	typeset cdimage_path
	typeset new_path
	typeset pkg
	typeset dflt
	typeset foo

	# If packages are already installed, we are done
	scvx_is_pkgadd_done
	if [[ $? -eq 0 ]]; then
		return 0
	fi

	#
	# Non-Interactive
	#
	if [[ -z "${is_interactive}" ]] && [[ -z "${SC_PKG_PATH}" ]]; then
		SC_PKG_PATH=${SC_DFLT_CDIMAGE}
	fi

	# If SC_PKG_PATH is set, do not prompt for it
	if [[ -n "${SC_PKG_PATH}" ]]; then

		# Re-construct SC_PKG_PATH
		new_path=$(scvx_construct_pkgpath ${SC_PKG_PATH})
		if [[ -z "${new_path}" ]]; then
			printf "$(gettext '%s:  Cannot find %s packages at %s.')\n" ${PROG} "${SC_VXVM}" ${SC_PKG_PATH}
			return 1
		fi
		SC_PKG_PATH=${new_path}

		# We are done
		return 0
	fi

	#
	# Interactive - prompt for the path
	#

	# Set "dflt" if cdrom0 is loaded with a supported CD
	dflt=
	new_path=$(scvx_construct_pkgpath ${SC_DFLT_CDIMAGE})
	if [[ -n "${new_path}" ]]; then
		dflt=${SC_DFLT_CDIMAGE}
	fi

	pkg_path=
	while [[ -z "${pkg_path}" ]]
	do
		# Prompt, with possible default
		if [[ -n "${dflt}" ]]; then
			printf "$(gettext 'Where is the %s cdrom [%s]?  ')\a" "${SC_VXVM}" ${dflt}
		else
			printf "$(gettext 'Where is the %s cdrom?  ')\a" "${SC_VXVM}"
		fi

		# Get answer
		read pkg_path foo
		if [[ -n "${foo}" ]]; then
			pkg_path=
			continue
		fi

		# If no answer and default, use default
		if [[ -z "${pkg_path}" ]] && [[ -n "${dflt}" ]]; then
			pkg_path=${dflt}
		fi

		# If no answer and no default, beep and repeat
		if [[ -z "${pkg_path}" ]]; then
			continue
		fi

		#
		# See if the packages are there.
		# The user may supply either the cdimage directory
		# OR the packages location directory.
		#
		new_path=$(scvx_construct_pkgpath ${pkg_path})
		if [[ -z "${new_path}" ]]; then
			printf "$(gettext 'Cannot find %s packages at %s.')\n\n\a" "${SC_VXVM}" ${pkg_path}
			pkg_path=
			continue
		fi

		# Done
		pkg_path=${new_path}
	done
	echo

	# Okay, set the PKG_PATH to path-to-packages
	SC_PKG_PATH=${pkg_path}

	return 0
}

#####################################################
#
# scvx_get_ltoken()
#
#	Get license token from the user.
#
#	Return values:
#
#		zero		always returned
#
#####################################################
scvx_get_ltoken()
{
	integer i
	typeset license=

	scvx_is_licensing_done >/dev/null
	if [[ $? -eq 0 ]]; then
		
		echo
		printf "    $(gettext 'One or more %s features are already licensed.')\n" "${SC_VXVM}" | logmsg
		printf "    $(gettext 'If you do not want to supply an additional license key, just')\n" | logmsg
		printf "    $(gettext 'press ENTER.  Otherwise, you may provide one additional key.')\n" | logmsg

		echo
		printf "$(gettext 'Please enter a %s license key [%s]:  ')\a" "${SC_VXVM}" "none"
		read license
		echo

		# Make sure none is "none"
		if [[ -z "${license}" ]] || [[ "$(echo ${license} | nawk '{ print tolower($1) }')" == none ]]; then
			license=none
		fi
	else
		echo
		while [[ -z "${license}" ]]
		do
			printf "$(gettext 'Please enter a %s license key:  ')\a" "${SC_VXVM}"
			read license

			# Don't let them type "none"
			if [[ "$(echo ${license} | nawk '{ print tolower($1) }')" == none ]]; then
				license=
				continue
			fi
		done
		echo
	fi

	# save license key
	let i=0
	while [[ -n "${SC_LICENSES[i]}" ]]
	do
		((i += 1))
	done
	SC_LICENSES[i]="${license}"
}

#####################################################
#
# verify_encap_requirements()
#
#	Verify scvxinstall requirements for encapsulation:
#
#		- root disk has slice 2 and 2 free partitions
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
verify_encap_requirements()
{
	# Print message
	printf "$(gettext 'Verifying encapsulation requirements.')\n" | logmsg

	# verify our root disk requirements

	# get root disk
	# make sure slice 2 exists and starts at cylinder 0
	slice2=$(prtvtoc -h ${SC_ROOTRDSK} | awk '$1 == "2" { print $4 }')
	if [[ -z "${slice2}" ]] || [[ "${slice2}" != 0 ]]; then
		printf "$(gettext '%s:  Root disk must have slice 2 set to the entire disk.')\n" ${PROG} | logerr
		return 1
	fi

	# make sure we have 2 free partitions
	slices="$(echo $(prtvtoc -h ${SC_ROOTRDSK} | wc -l))"
	if [[ $slices -gt 6 ]]; then
		printf "$(gettext '%s:  Root disk must have 2 free slices.')\n" ${PROG} | logerr
		return 1
	fi

	return 0
}

#####################################################
#
# scvx_get_symlink filename
#
#	Print the name of the file pointed to by the sym link.
#
#	Return values:
#
#		zero		always returned
#
#####################################################
scvx_get_symlink()
{
	typeset filename=$1

	if [[ -z "${filename}" ]] || [[ ! -L "${filename}" ]]; then
		return 0
	fi

	ls -l ${filename} | awk '{ print $NF }'

	return 0
}

#####################################################
#
# scvx_is_dmp_disabled()
#
#	Return non-zero if DMP is not fully disabled;  otherwise,
#	return 0.
#
#	Return values:
#
#		zero		DMP is fully disabled
#		non-zero	DMP is not fully disabled
#
#####################################################
scvx_is_dmp_disabled()
{
	if [[ ! -d /dev/vx ]] ||
	    [[ ! -L /dev/vx/dmp ]] ||
	    [[ ! -L /dev/vx/rdmp ]] ||
	    [[ "$(scvx_get_symlink /dev/vx/dmp)" != /dev/dsk ]] ||
	    [[ "$(scvx_get_symlink /dev/vx/rdmp)" != /dev/rdsk ]]; then
		return 1
	fi

	return 0
}

#####################################################
#
# disable_DMP()
#
#	Disable DMP by linking /dev/vx/{r}dmp to /dev/{r}dsk.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
disable_DMP()
{
	# See if DMP is already disabled
	scvx_is_dmp_disabled
	if [[ $? -eq 0 ]]; then
		printf "$(gettext '%s is already disabled.')\n" DMP | logmsg
		return 0
	fi

	# Print message
	printf "$(gettext 'Disabling %s.')\n" DMP | logmsg

	# Create /dev/vx, if it is not already there
	if [[ ! -d /dev/vx ]]; then
		mkdir -m 0755 /dev/vx
		if [[ $? -ne 0 ]]; then
			printf "$(gettext '%s:  Unable to create %s.')\n" ${PROG} /dev/vx | logerr
			return 1
		fi
	fi

	# Create /dev/vx/dmp, if it is not already there
	if [[ ! -r /dev/vx/dmp ]]; then
		ln -s /dev/dsk /dev/vx/dmp
		if [[ $? -ne 0 ]]; then
			printf "$(gettext '%s:  Unable to create %s.')\n" ${PROG} /dev/vx/dmp | logerr
			return 1
		fi

	# if it is already there, it should be a sym link
	# However versions of VxVM (3.1.1 and later) require DMP to be enabled.
	# Thus, if DMP cannot be disabled, then we will not exit but instead
	# continue the installation.
	else
		if [[ ! -L /dev/vx/dmp ]] ||
	    	    [[ "$(scvx_get_symlink /dev/vx/dmp)" != /dev/dsk ]]; then
			printf "$(gettext '%s:  %s is not set up correctly.')\n" ${PROG} /dev/vx/dmp | logerr
			printf "$(gettext '%s:  Warning: Unable to disable %s, but installation will continue...')\n" ${PROG} DMP | logerr
		fi
	fi

	# Create /dev/vx/rdmp, if it is not already there
	if [[ ! -r /dev/vx/rdmp ]]; then
		ln -s /dev/rdsk /dev/vx/rdmp
		if [[ $? -ne 0 ]]; then
			printf "$(gettext '%s:  Unable to create %s.')\n" ${PROG} /dev/vx/rdmp | logerr
			return 1
		fi

	# if it is already there, it should be a sym link
	# However versions of VxVM (3.1.1 and later) require DMP to be enabled.
	# Thus, if DMP cannot be disabled, then we will not exit but instead
	# continue the installation.
	else
		if [[ ! -L /dev/vx/rdmp ]] ||
	    	    [[ "$(scvx_get_symlink /dev/vx/rdmp)" != /dev/rdsk ]]; then
			printf "$(gettext '%s:  %s is not set up correctly.')\n" ${PROG} /dev/vx/rdmp | logerr
			printf "$(gettext '%s:  Warning: Unable to disable %s, but installation will continue...')\n" ${PROG} DMP | logerr
		fi
	fi

	return 0
}

#####################################################
#
# scvx_is_pkg_installed() package [partial]
#
#	Check to see if the given "package" is installed.
#	if "partial" is given, just check to see if the
#	packages are partially installed.
#
#	Return zero if the package installed;  otherwise,
#	return non-zero.   If "partial" is given, return zero
#	if the package is ONLY partially installed.
#
#	Return values:
#
#		zero		the package is installed
#		non-zero	the package is not installed
#
#####################################################
scvx_is_pkg_installed()
{
	typeset package=$1
	typeset partial=$2

	# Check argument
	if [[ -z "${package}" ]]; then
		return 1
	fi

	# Partial?
	if [[ -n "${partial}" ]]; then
		partial="-p"
	fi

	# See if the package is installed
	pkginfo -q ${partial} ${SC_ROOTARG} ${package} >/dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		return 1
	fi

	return 0
}

#####################################################
#
# scvx_is_pkgadd_done
#
#	Checks to see if the VxVM package add step completed.
#	Return non-zero if not all of the packages are fully installed.
#
#	Return values:
#
#		zero		All required VxVM pkgs are fully installed
#		non-zero	All required VxVM pkgs are NOT fully installed
#
#####################################################
scvx_is_pkgadd_done()
{
	typeset pkg

	for pkg in ${SC_VXVM_REQ_PKGS}
	do
		# If not installed, return 1
		scvx_is_pkg_installed ${pkg}
		if [[ $? -ne 0 ]]; then
			return 1
		fi

		# If installed, but only partially, return 1
		scvx_is_pkg_installed ${pkg} check_partial
		if [[ $? -eq 0 ]]; then
			return 1
		fi
	done

	return 0
}

#####################################################
#
# setup_pkgadd_stuff()
#
#	Create the admin and response files for auto-pkgadd.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
setup_pkgadd_stuff()
{
	# setup admin file
	cat >${SC_ADMIN} <<END
mail=
instance=quit
partial=quit
runlevel=nocheck
idepend=nocheck
rdepend=nocheck
space=quit
setuid=nocheck
conflict=nocheck
action=nocheck
basedir=default
END
	if [[ $? -ne 0 ]]; then
		printf "$(gettext '%s:  Unable to create %s.')\n" ${PROG} ${SC_ADMIN} | logerr
		return 1
	fi

	# setup response file
	cat << EOF >${SC_RSP}
REQ_OS_VERS=5.8
EOF
	if [[ $? -ne 0 ]]; then
		printf "$(gettext '%s:  Unable to create %s.')\n" ${PROG} ${SC_RSP} | logerr
		return 1
	fi

	return 0
}

#####################################################
#
# install_pkgs()
#
#	Install VRTS* packages.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
install_pkgs()
{
	typeset pkg
	typeset cmd
	integer ntm_status

	# See if packages are already fully installed
	scvx_is_pkgadd_done
	if [[ $? -eq 0 ]]; then
		printf "$(gettext 'The %s package installation is already complete.')\n" "${SC_VXVM}" | logmsg
		return 0
	fi

	# Print message
	printf "$(gettext 'Installing packages from %s.')\n" ${SC_PKG_PATH} | logmsg

	# Create the admin and response files
	setup_pkgadd_stuff || return 1

	# Add each of the packages
	for pkg in ${SC_VXVM_PKGS}
	do
		# If already installed, skip it
		scvx_is_pkg_installed ${pkg}
		if [[ $? -eq 0 ]]; then

			# But, first, make sure it is not a partial
			scvx_is_pkg_installed ${pkg} check_partial
			if [[ $? -eq 0 ]]; then
				printf "$(gettext '%s:  %s is found to be only partially installed.')\n" ${PROG} ${pkg} | logerr
				printf "$(gettext '%s:  You must remove %s using pkgrm.')\n" ${PROG} ${pkg} | logerr
				return 1
			fi

			# Skip to the next package
			continue
		fi

		# Check for the Veritas license package VRTSlic being
		# introduced in VxVM3.2 and later versions.  This package must
		# be installed prior to all other VRTS packages.
		if [[ ${pkg} == ${SC_VXVM_LIC_PKG} && ! -d "${SC_PKG_PATH}/${SC_VXVM_LIC_PKG}" ]]; then
			# No VRTSlic package found!  Must be a version of 
			# VxVM prior to 3.2.  So skip to the next package
			continue
		fi

		# Print message
		printf "$(gettext 'Installing %s.')\n" ${pkg} | logmsg

		# Make sure vxio is not already set up, if this package does it
		if [[ ${pkg} == ${SC_VXVM_VXIO_PKG} ]]; then
			scvx_is_ntm_done
			ntm_status=$?
			if [[ ${ntm_status} -ne 1 ]]; then
				printf "$(gettext '%s:  The %s major number has already been set in %s.')\n" ${PROG} "vxio" ${SC_VXIO_MAJOR} ${SC_NAME_TO_MAJOR} | logerr
				printf "$(gettext '%s:  Cannot install \"%s\".')\n" ${PROG} ${pkg} | logerr
				return 1
			fi
		fi

		# Okay, add the package
		cmd="pkgadd -a ${SC_ADMIN} -r ${SC_RSP} -d ${SC_PKG_PATH} ${SC_ROOTARG} ${pkg}"
		echo "\n${cmd}" >> ${SC_LOGFILE}
		${cmd} >> ${SC_LOGFILE} 2>&1
		if [[ $? -ne 0 ]]; then
			printf "$(gettext '%s:  Failed to install %s.')\n" ${PROG} ${pkg} | logerr
			printf "$(gettext '%s:  Check %s for more information.')\n" ${PROG} ${SC_LOGFILE} | logerr
			return 1
		fi
	done

	return 0
}

#####################################################
#
# scvx_is_ntm_done
#
#	Checks to see if the name_to_major step is completed
#	by verifying that the vxio major number is correctly
#	set to SC_VXIO_MAJOR.
#
#	Return non-zero if the step is not complete.
#
#	Return values:
#
#		zero		vxio major number is set to SC_VXIO_MAJOR
#		1		vxio major number is not set at all
#		2		vxio major number is not set to SC_VXIO_MAJOR
#
#####################################################
scvx_is_ntm_done()
{
	typeset major

	# See if we find vxio is set to 
	major=$(awk '/^vxio[ \t]/ {print $2}' ${SC_NAME_TO_MAJOR})
	if [[ -z "${major}" ]]; then
		return 1
	fi
	if [[ ${major} != ${SC_VXIO_MAJOR} ]]; then
		return 2
	fi

	return 0
}

#####################################################
#
# scvx_do_ntm()
#
#	Verify that vxio driver used major number SC_VXIO_MAJOR.
#	If not, then repair.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
scvx_do_ntm()
{
	typeset major
	typeset driver
	typeset driver_entry
	integer count
	integer ntm_status

	# See if vxio is already in the name_to_major file
	scvx_is_ntm_done
	ntm_status=$?
	if [[ ${ntm_status} -eq 0 ]]; then
		printf "$(gettext 'The %s major number has already been set to %d.')\n" "vxio" ${SC_VXIO_MAJOR} | logmsg
		return 0
	fi

	# Print message
	printf "$(gettext 'Setting the %s major number to %d.')\n" "vxio" ${SC_VXIO_MAJOR} | logmsg

	# Count the number of lines using our major number
	count=$(egrep -v '^#' ${SC_NAME_TO_MAJOR} | egrep -c -e '[ 	]'${SC_VXIO_MAJOR}'[ 	]' -e '[ 	]'${SC_VXIO_MAJOR}'$')

	# Get the driver
	case ${count} in
	0)	# Not used at all
		driver=vxio
		;;
	*)	# At least one occurrence of major number
		driver=$(egrep -v '^#' ${SC_NAME_TO_MAJOR} | egrep -e '[ 	]'${SC_VXIO_MAJOR}'[ 	]' -e '[ 	]'${SC_VXIO_MAJOR}'$' | awk '{print $1}')
		;;
	esac

	# Make sure nobody else is trying to use our major number
	if [[ ${count} -gt 1 ]] || [[ ${driver} != "vxio" ]];  then
		# Print each driver that it using our major number
		for driver_entry in ${driver}
		do
			printf "$(gettext '%s:  Major number %d is already in use by the driver %s.')\n" ${PROG} ${SC_VXIO_MAJOR} ${driver_entry} | logerr
		done
		printf "$(gettext '%s:  %s uses major number %d for %s.')\n" ${PROG} ${PROG} ${SC_VXIO_MAJOR} "vxio" | logerr
		printf "$(gettext '%s:  You may need to use manual procedures for installing %s.')\n" ${PROG} "VxVM" | logerr
		return 1
	fi

	# If it is not in the file, add it
	if [[ ${ntm_status} -eq 1 ]]; then
		echo "vxio ${SC_VXIO_MAJOR}" >> ${SC_NAME_TO_MAJOR}
		if [[ $? -ne 0 ]];  then
			printf "$(gettext '%s:  Failed to add %s to %s.\n')\n" ${PROG} ${SC_VXIO_MAJOR} ${SC_NAME_TO_MAJOR} | logerr
			return 1
		fi

	# Otherwise, we should just need to reset it
	elif [[ ${ntm_status} -eq 2 ]]; then
		ed -s ${SC_NAME_TO_MAJOR} << EOF >/dev/null 2>&1
/^vxio[ 	]/c
vxio ${SC_VXIO_MAJOR}
.
w
q
EOF
		if [[ $? -ne 0 ]]; then
			printf "$(gettext '%s:  Failed to update %s.\n')\n" ${PROG} ${SC_NAME_TO_MAJOR} | logerr
			return 1
		fi
	fi

	# Set the re-boot flag
	((SC_REBOOT_REQUIRED+=1))

	return 0
}

#####################################################
#
# scvx_is_licensing_done
#
#	Checks to see if the VxVM licensing step completed.
#	Prints a list of licensed features.
#
#	Return values:
#
#		zero		one or more features are licensed
#		non-zero	no features are licensed
#
#####################################################
scvx_is_licensing_done()
{
	integer found
	typeset feature
	typeset features
	typeset mode

	# Make sure we have VxVM
	scvx_is_pkgadd_done
	if [[ $? -ne 0 ]]; then
		return 1
	fi

	#
	# Start vxconfigd, if it is not already running;
	# vxconfigd establishes hardware licenses.
	#
	mode="$(
		LANG=C; export LANG
		vxdctl mode | awk '/mode:/ {
			if ($1 == "mode:")
				mode=$2
		}
		END {
		if (NR ==1)
			print mode
		}'
	)"
	if [[ -z "${mode}" ]]; then
		# Cannot get the mode of vxconfigd
		printf "$(gettext '%s:  Unexpected response from %s.')\n" ${PROG} "vxdctl" | logerr
		return 1
	elif [[ "${mode}" == "not-running" ]]; then
		# Start a new vxconfigd in disabled mode
		vxconfigd -m disable >/dev/null 2>&1
		if [[ $? -ne 0 ]]; then
			printf "$(gettext '%s:  Failed to start \"%s\".')\n" ${PROG} "vxconfigd" | logerr
			return 1
		fi
	fi

	# Get the list of features which might have valid licenses
	features="$(
		LANG=C; export LANG
		vxlicense -p | nawk '/[Ff]eature/ {
			found_feature=0
			for (i = 0;  i <= NF;  i++) {
				if (tolower($i) == "feature") {
					found_feature=1
				} else if (tolower($i) == "name:" &&
				    found_feature == 1) {
					found_feature=2
				} else if (found_feature == 2) {
					print $i
					break
				} else {
					found_feature=0
				}
			}
		}'     
	)"

	# Now, print the list of any licensed features
	let found=0
	for feature in ${features}
	do
		vxlicense -t ${feature} >/dev/null 2>&1
		if [[ $? -eq 0 ]]; then
			echo ${feature}
			((found += 1))
		fi
	done
	if [[ ${found} -ne 0 ]]; then
		return 0
	fi

	return 1
}

#####################################################
#
# scvx_install_license() [is_interactive]
#
#	Install VxVM usage license.  If "is_interactive" is set
#	and one was not given on the command line, prompt the user for
#	the license.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
scvx_install_license()
{
	is_interactive=${1}

	integer i
	integer found
	integer licensed
	integer status
	integer failed

	typeset feature
	typeset features

	# See if we already have a license
	let found=0
	features="$(scvx_is_licensing_done)"
	for feature in ${features}
	do
		printf "$(gettext 'The \"%s\" %s feature is already licensed.')\n" ${feature} "${SC_VXVM}" | logmsg
		((found += 1))
	done

	# Non-Interactive
	if [[ -z "${is_interactive}" ]] && [[ -z "${SC_LICENSES[0]}" ]]; then
		SC_LICENSES[0]="none"
	fi

	# If not on the command line, and interactive, get from the user now.
	if [[ -z "${SC_LICENSES[0]}" ]]; then
		scvx_get_ltoken
	fi

	# If "none", we are done, as long as something is licensed.
	if [[ -z "${SC_LICENSES[0]}" ]] || [[ "${SC_LICENSES[0]}" == "none" ]]; then
		# We should not get here if this entered at the prompt
		if [[ ${found} -eq 0 ]]; then
			printf "$(gettext '%s:  A %s license is required.')\n" ${PROG} "${SC_VXVM}" | logerr
			return 1
		fi
		return 0
	fi

	# Print message
	if [[ -z "${SC_LICENSES[1]}" ]]; then
		printf "$(gettext 'Installing %s license.')\n" "${SC_VXVM}" | logmsg
	else
		printf "$(gettext 'Installing %s licenses.')\n" "${SC_VXVM}" | logmsg
	fi

	# install licenses
	let i=0
	let licensed=0
	while [[ -n "${SC_LICENSES[i]}" ]]
	do
		echo "${SC_LICENSES[i]}" | vxlicense -c >/dev/null 2>${SC_TMPERR}
		status=$?
		if [[ -s "${SC_TMPERR}" ]]; then
			logerr <${SC_TMPERR}
		fi
		rm -f ${SC_TMPERR}
		if [[ ${status} -ne 0 ]]; then
			printf "$(gettext '%s:  Bad license key - \"%s\".')\n" ${PROG} "${SC_LICENSES[i]}" | logerr
		else
			((licensed += 1))
		fi
		((i += 1))
	done
	((failed = i - licensed))
	if [[ ${failed} -eq 1 ]]; then
		printf "$(gettext '%s:  Failed to install %s license.')\n" ${PROG} "${SC_VXVM}" | logerr
		return 1
	elif [[ ${failed} -gt 1 ]]; then
		printf "$(gettext '%s:  Failed to install %s licenses.')\n" ${PROG} "${SC_VXVM}" | logerr
		return 1
	fi

	return 0
}

#####################################################
#
# scvx_is_encapsulation_done
#
#	Checks to see if the rootdisk has already been encapsulated or
#	if we completed setup for root disk encapsulation.
#
#	Return values:
#
#		zero		Root disk encapsulation step is complete
#		one		Root disk has already been encapsulated
#		two		Root disk encapsulation step is not complete
#
#####################################################
scvx_is_encapsulation_done()
{
	typeset ctd

	# Make sure we have VxVM
	scvx_is_pkgadd_done
	if [[ $? -ne 0 ]]; then
		return 2
	fi

	# Make sure that the rootdisk has not already been successfully
	# encapsulated.
	scvx_is_rootdisk_encapsulated
	if [[ $? -eq 0 ]]; then
		return 1
	fi

	# Check if the setup for rootdisk encapsulation has been
	# completed.
	if [[ -f ${SC_VXVM_ENCAP_CONFIGFILE} ]]
	then
		ctd="$(
			LANG=C;  export LANG
			cat ${SC_VXVM_ENCAP_CONFIGFILE} | awk '/${SC_ROOTCTD}/ {
				if ($1 == "${SC_ROOTCTD}")
					print $1
			}'
		)"	
		if [[ $ctd == $SC_ROOTCTD ]]
		then
			return 0
		fi
	fi
	return 2
}

#####################################################
#
# scvx_prepare_encapsulation()
#
#	Configure root disk for VxVM encapsulation.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
scvx_prepare_encapsulation()
{
	typeset mode
	typeset ctd
	typeset ret

	# See if the rootdisk has already been encapsulated, or if we are 
	# already set up to encapsulate
	scvx_is_encapsulation_done
	ret=$?
	if [[ $ret -eq 0 ]]; then
		printf "$(gettext 'The %s root disk encapsulation step is already completed.')\n" "${SC_VXVM}" | logmsg
		return 0
	elif [[ $ret -eq 1 ]]; then
		printf "$(gettext '%s:  The rootdisk has already been successfully encapsulated on this node.')\n" ${PROG} | logerr
		return 1
	fi

	# Print message
	printf "$(gettext 'Arranging for %s encapsulation of the root disk.')\n" "${SC_VXVM}" | logmsg

	#
	# Proceed with rootdisk encapsulation preparation.		
	#

	# The vxconfigd daemon may have already been started by the license 
	# check operation.  But, if not, start it now in disabled mode.
	mode="$(
		LANG=C; export LANG
		vxdctl mode | awk '/mode:/ {
			if ($1 == "mode:")
				mode=$2
		}
		END {
		if (NR ==1)
			print mode
		}'
	)"
	if [[ -z "${mode}" ]]; then
		# Cannot get the mode of vxconfigd
		printf "$(gettext '%s:  Unexpected response from %s.')\n" ${PROG} "vxdctl" | logerr
		return 1
	elif [[ "${mode}" == "not-running" ]]; then
		# Start a new vxconfigd in disabled mode
		vxconfigd -m disable >/dev/null 2>&1
		if [[ $? -ne 0 ]]; then
			printf "$(gettext '%s:  Failed to start \"%s\".')\n" ${PROG} "vxconfigd" | logerr
			return 1
		else
			# Successfully started the vxconfigd daemon in disabled
			# mode.
			printf "$(gettext 'The vxconfigd daemon has been started and is in disabled mode ...')\n" | logmsg
		fi
	elif [[ "${mode}" != "disabled" ]]; then
		# vxconfigd daemon is started but not in disabled mode 
		printf "$(gettext '%s:  The vxconfigd daemon is in \"%s\" mode but needs to be in \"disable\" mode.')\n" "${PROG}" ${mode} | logerr
		return 1
	else
		# vxconfigd daemon is started and is in disabled mode.
		printf "$(gettext 'The vxconfigd daemon has been started and is in disabled mode...')\n" | logmsg
	fi

	# Re-initialize the volboot file
	# vxconfigd should be running in 'disable' mode for the volboot to 
	# be re-initialzed.  Any existing volboot file is simply rewritten,
	# so it is ok if 'vxdctl init' has been executed beforehand.
	vxdctl init
	if [[ $? -ne 0 ]];  then
		# Failure 'vxdctl init'
		printf "$(gettext '%s:  \"%s\" failed.')\n" ${PROG} "vxdctl init" | logerr
		return 1
	else
		# Success 'vxdctl init'
		printf "$(gettext 'Reinitializied the volboot file...')\n" | logmsg
	fi

	# Create rootdg.
	# If a rootdg has already been created, then skip this step.
	vxdg list rootdg > /dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		# Create rootdg.	
		vxdg init rootdg
		if [[ $? -ne 0 ]]; then
			# Failure in creating the rootdg for the first time.
			printf "$(gettext '%s:  Failed to create %s using \"%s\".')\n" ${PROG} "rootdg" "vxdg init root" | logerr
			return 1
		else
			# Success in creating the rootdg for the first time.
			printf "$(gettext 'Created the rootdg...')\n" | logmsg
		fi
	else
		# Use the existing rootdg
		printf "$(gettext '%s:  rootdg already exists so %s will attempt to utilize it.')\n" ${PROG} ${PROG} | logmsg
	fi

	# Add the Solaris root disk to rootdg
	# If the rootdisk is already part of rootdg, then skip this step.
	ctd="$(
		LANG=C; export LANG
		vxdctl list | awk '/${SC_ROOTDISK}/ {
			if ($2 == "${SC_ROOTDISK}")
				 print $2
		}'
	)"
	if [[ -z "${ctd}" ]]; then
		# Add the rootdisk to the rootdg.
		vxdctl add disk ${SC_ROOTDISK} type=sliced
		if [[ $? -ne 0 ]]; then
			# Failure in adding rootdisk to rootdg
			printf "$(gettext '%s:  Failed to add root disk \"%s\" to %s.')\n" ${PROG} ${SC_ROOTDISK} "rootdg" | logerr
			return 1
		else
			# Success in adding rootdisk to rootdg
			printf "$(gettext 'Added the rootdisk to the rootdg...')\n" | logmsg
		fi
	else
		# The rootdisk has already been added to the rootdg.
		printf "$(gettext '%s:  The rootdisk \"%s\" already has been added to the rootdg so %s will attempt to utilize it.')\n" ${PROG} ${SC_ROOTDISK} ${PROG} | logmsg 
	fi

	# Run vxencap
	# Since multiple runs of vxencap are not harmful, there is no need to
	# check anything prior to its execution. 
	vxencap rootdisk_${SC_MYNODEID}=${SC_ROOTDISK} >/dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		# Failure in vxencap
		printf "$(gettext '%s:  \"%s\" failed for root disk.')\n" ${PROG} "vxencap" | logerr
		return 1
	else
		# Success in vxencap
		printf "$(gettext 'The setup to encapsulate rootdisk is complete...')\n" | logmsg
	fi
  
	# Set the re-boot flag
	((SC_REBOOT_REQUIRED+=1))

	return 0
}

#####################################################
#
# scvx_is_vfstab_update_done
#
#	Checks to see if the vfstab updates are completed.
#
#	Return values:
#
#		zero		vfstab has the necessary updates
#		non-zero	vfstab does not have the necessary updates
#
#####################################################
scvx_is_vfstab_update_done()
{
	typeset globaldevmp=/global/.devices/node@${SC_MYNODEID}

	integer found

	typeset special
	typeset fsckdev
	typeset mountp
	typeset remains

	# Get the two devices
	let found=0
	while read special fsckdev mountp remains
        do
                case ${special} in
                '#'* | '')      # Ignore comments, empty lines
                                continue
                                ;;
                esac

                if [[ "${mountp}" = "${globaldevmp}" ]]; then
			let found=1
			break
                fi
        done < ${SC_VFSTAB}

	# Did we find it?
	if [[ ${found} -eq 0 ]]; then
		return 1
	fi

	#
	# If either of these are still DID devices, then the updates have
	# not yet been completed.   By looking for DID devices, rather
	# than checking for the absence of regular Solaris device names,
	# we still get the same desired results even if VxVM has completely
	# finished the encapsulation process.
	#
	if [[ "${special}" == /dev/did/dsk/d*s[0-7] ]] ||
	    [[ "${fsckdev}" == /dev/did/rdsk/d*s[0-7] ]]; then
		return 1
	fi

	return 0
}

#####################################################
#
# update_vfstab()
#
#	Update /etc/vfstab to use /dev/{r}dsk/cXtXdX name for
#	/global/.devices instead of /dev/did/{r}dsk so VxVM
#	can recognize it is on the root disk.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
update_vfstab()
{
	typeset globaldevmp=/global/.devices/node@${SC_MYNODEID}

	integer i
	typeset foo

	typeset special
	typeset gspecial
	typeset fsckdev
	typeset gfsckdev
	typeset mountp
	typeset gmountp
	typeset remains
	typeset gremains
	typeset globals
	set -A globals

	typeset dev
	typeset rdev
	typeset disk
	typeset slice

	typeset new_dev
	typeset new_rdev

	typeset vfstabline

	scvx_is_vfstab_update_done
	if [[ $? -eq 0 ]]; then
		printf "$(gettext 'The %s file already includes the necessary updates.')\n" /etc/vfstab | logmsg
		return 0
	fi

	# Print message
	printf "$(gettext 'Updating %s entry in %s.')\n" /global/.devices /etc/vfstab | logmsg

	#
	# Get the two devices we need to change.
	# Also, stash the device names of all global devices other than
	# the one for "globaldevmp"
	#
	let i=0
	set -A globals
	gspecial=
	gfsckdev=
	while read special fsckdev mountp remains
        do
                case ${special} in
                '#'* | '')      # Ignore comments, empty lines
                                continue
                                ;;
                esac

                if [[ "${mountp}" = "${globaldevmp}" ]]; then
			if [[ -n "${gspecial}" ]]; then
				printf "$(gettext '%s:  More than one entry found in %s for %s.')\n" ${PROG} ${SC_VFSTAB} ${globaldevmp} | logerr
				return 1
			fi
			gspecial="${special}"
			gfsckdev="${fsckdev}"
			gmountp="${mountp}"
			gremains="${remains}"
			continue
                fi

		if [[ "${remains}" == *global* ]]; then
			foo=
			if [[ "${special}" == /dev/dsk/c*t*d*s[0-7] ]]; then
				foo=$(IFS=/ ; set -- ${special};  shift 3;  echo $1)
			elif [[ "${special}" == /dev/did/dsk/d*s[0-7] ]]; then
				foo=$(IFS=/ ; set -- ${special};  shift 4;  echo $1)
			elif [[ "${special}" == /dev/global/dsk/d*s[0-7] ]]; then
				foo=$(IFS=/ ; set -- ${special};  shift 4;  echo $1)
			fi
			if [[ -n "${foo}" ]]; then
				globals[i]=$(IFS=s ; set -- ${foo}; echo $1)
				((i += 1))
			fi
		fi
        done < ${SC_VFSTAB}

	# Make sure we found what we were looking for
	if [[ -z "${gspecial}" ]]; then
		printf "$(gettext '%s:  %s does not have an entry for %s.')\n" ${PROG} ${SC_VFSTAB} ${globaldevmp} | logerr
		return 1
	fi

	#
	# Make sure that these are not DID devices
	#
	# This should never fail, since the test for checking
	# whether or not this step is complete in
	# scvx_is_vfstab_update_done() is to see if
	# DID devices are still being used.
	#
	if [[ "${gspecial}" != /dev/did/dsk/d*s[0-7] ]] ||
	    [[ "${gfsckdev}" != /dev/did/rdsk/d*s[0-7] ]]; then
		printf "$(gettext '%s:  DID devices are still in use for %s.')\n" ${PROG} ${globaldevmp} | logerr
		return 1
	fi

	# Verify that the DID devices are the same
	dev=$(IFS=/ ; set -- ${gspecial};  shift 4;  echo $1)
	rdev=$(IFS=/ ; set -- ${gfsckdev};  shift 4;  echo $1)
	if [[ "${dev}" != "${rdev}" ]]; then
		printf "$(gettext '%s:  Unexpected device names for %s.')\n" ${PROG} ${globaldevmp} | logerr
		return 1
	fi

	# Get the disk and slice number
	disk=$(IFS=s ; set -- ${dev}; echo $1)
	slice=$(IFS=s ; set -- ${dev}; echo $2)

	#
	# Get the Solaris device names
	#
	# We have to echo the output from scdidadm to get rid of the
	# extra tab;  scdidadm ends each line with a tab!
	#
	new_rdev=$(echo $(scdidadm -l -o path ${disk}))
	if [[ $? -ne 0 ]] || [[ -z "${new_rdev}" ]]; then
		printf "$(gettext '%s:  DID device %s is unknown.')\n" ${PROG} ${disk} | logerr
		return 1
	fi
	if [[ ${new_rdev} != /dev/rdsk/c*t*d* ]];  then
		printf "$(gettext '%s:  %s is mounted on an unrecognized device.')\n" ${PROG} ${globaldevmp} | logerr
		return 1
	fi
	if [[ ${new_rdev} != *s[0-7] ]]; then
		new_rdev=${new_rdev}s${slice}
	fi
	new_dev=$(echo ${new_rdev} | sed 's#rdsk#dsk#')
	if [[ -z "${new_dev}" ]]; then
		printf "$(gettext '%s:  Unexpected sed(1) error.')\n" ${PROG} | logerr
		return 1
	fi

	#
	# Make sure that neither the Solaris device name for root nor the
	# DID name for root is used in any other global device name.
	#
	for foo in ${globals[*]}
	do
		if [[ /dev/dsk/${foo}s${slice} == ${new_dev} ]] ||
		    [[ ${foo} == ${disk} ]]; then
			printf "$(gettext '%s:  Unsupported global device (%s) mount from the root disk.')\n" ${PROG} ${foo} | logerr
			return 1
		fi
	done

	# Construct our new vfstab line
	vfstabline="${new_dev}	${new_rdev}	${gmountp}	${gremains}"

	# Edit vfstab, by commenting out the original line and adding the new 
	foo=$(echo ${gspecial} | sed 's#/#\\/#g')
	ed -s ${SC_VFSTAB} << EOF >/dev/null 2>&1
/^${foo}[ 	]/s/^/#/
\$a
${vfstabline}
.
w
q
EOF
	if [[ $? -ne 0 ]]; then
		printf "$(gettext '%s:  Failed to update %s.')\n" ${PROG} ${SC_VFSTAB} | logerr
		return 1
	fi

	# Set the re-boot flag
	((SC_REBOOT_REQUIRED+=1))

	return 0
}

#####################################################
#
# scvx_is_reminor_done
#
#	Checks to see if reminoring has been completed.
#	Note that this is performed by the RC script.
#
#	Return values:
#
#		zero		reminoring is complete
#		non-zero	reminoring is not complete
#
#####################################################
scvx_is_reminor_done()
{

    #  if special devices directories haven't been created, then 
    #  reminoring can't have been done
    if [[ ! -d /dev/vx/rdsk ]]; then
            return 1
    fi

    if [[ ! -d /dev/vx/dsk ]]; then
            return 1
    fi

    #  Compute the reminored minor number
    node=`/usr/sbin/clinfo -n`
    new_minor=`/usr/bin/expr $node \* 50`
    major_minor=`printf "%d,%3d" ${SC_VXIO_MAJOR} ${new_minor}`

    # See if the correct minor number has been set
    ls -l /dev/vx/dsk | grep "${major_minor}" > /dev/null
    if [[ $? -eq 1 ]]; then
          return 1
    fi

    # See if the correct minor number has been set
    ls -l /dev/vx/rdsk | grep "${major_minor}" > /dev/null
    return $?
}

#####################################################
#
# scvx_reboot()
#
#	This function attains its re-boot token, then
#	re-boots.
#
#	Return values:
#
#		zero		re-boot is not required
#		non-zero	failure
#
#####################################################
scvx_reboot()
{
	integer printflg=0
	integer status

	# First, let's see if we need to do a reboot
	if [[ ${SC_REBOOT_REQUIRED} -eq 0 ]]; then
		printf "$(gettext 'Skipping re-boot.\n')\n" | logmsg
		return 0
	fi

	# Get the boot token
	while true
	do
		scrconf -b
                case $? in
		0)			# We got the boot token
			break
			;;
			
		${SC_SCCONF_EBUSY})	# Somebody else is booting
			if [[ ${printflg} -eq 0 ]]; then
				printf "$(gettext 'Waiting for all nodes to re-join the cluster ...')\n" | logmsg
				((printflg+=1))
			fi
			sleep 5
			;;

		*)			# Error
			printf "$(gettext '%s:  Failed to get permission to re-boot.')\n" ${PROG} | logerr
			return 1
			;;
		esac
	done

	# Print message
	echo | logmsg
	printf "$(gettext 'This node will be re-booted in %d seconds.')\n" ${SC_ABORT_TIMEOUT} | logmsg
	printf "$(gettext 'Type %s to abort ')" "Ctrl-C" | logmsg

	# Give them a chance to hit Ctrl-C
	let i=0
	while [[ $i -lt ${SC_ABORT_TIMEOUT} ]]
	do
		echo ".\c" | logmsg
		sleep 1
		((i += 1))
	done
	echo | logmsg

	# Cleanup
	cleanup

	# Re-boot in non-cluster mode
	reboot -- -x

	# We are done
	exit 0
}

#####################################################
#
# scvx_doit() [is_interactive]
#
#	is_interactive			interactive
#
#	This function performs the main function for
#	VxVM installation and encapsulation tasks.
#
#	If "is_interactive" is given, it means that
#	this is being run interactively;   it is okay
#	to prompt for information.   Otherwise,
#	prompting is not allowd.
#
#	Return values:
#
#		zero		success
#		non-zero	failure
#
#####################################################
scvx_doit()
{
	typeset is_interactive=${1}

	integer i
	typeset new_path

	# has scvxinstall already installed VxVM?
	if [[ -f ${SC_COMPLETE} ]]; then
                printf "$(gettext '%s:  %s has already been run to completion on this node.')\n" ${PROG} ${PROG} | logerr
		printf "$(gettext '%s:  The presence of \"%s\" indicates prior completion.')\n" ${PROG} ${SC_COMPLETE} | logerr

		echo | logerr
                printf "$(gettext '%s:  Removal of the completion file is considered risky.')\n" ${PROG} | logerr
                printf "$(gettext '%s:  Attempts to re-run this program could result in unrecoverable damage.')\n" ${PROG} | logerr

		return 1
	fi

	# If interactive, see if we need to encapsulate (set SC_PERFORM_ENCAP)
	if [[ -n "${is_interactive}" ]]; then
		scvx_get_action
	fi

	# Get location of packages, if packages are not yet installed
	scvx_get_location ${is_interactive} || return 1

	# Disable DMP, if it is not already disabled
	disable_DMP || return 1
	
	# Install packages, if they are not already installed
	install_pkgs || return 1
	
	# Check and fix major number, if necessary
	scvx_do_ntm || return 1

	# Installation is complete
	printf "$(gettext '%s installation is complete.')\n" "${SC_VXVM}" | logmsg

	# if we're not encapsulating the root disk, we're done
	if [[ "${SC_PERFORM_ENCAP}" != true ]]; then
		if [[ ${SC_REBOOT_REQUIRED} -ne 0 ]]; then
			printf "\n$(gettext 'Please remember to re-boot this node before configuring VxVM.')\n\n\a" | logmsg
		fi
		return 0
	fi
	
	# Start vxconfigd and install license, if necessary
	scvx_install_license ${is_interactive} || return 1

	# Starting the encapsulation process ...
	echo | logmsg
	printf "$(gettext 'The %s root disk encapsulation step will begin in %d seconds.')\n" "${SC_VXVM}" ${SC_ABORT_TIMEOUT} | logmsg
	printf "$(gettext 'Type %s to abort ')" "Ctrl-C" | logmsg

	# Give them a chance to hit Ctrl-C
	let i=0
	while [[ $i -lt ${SC_ABORT_TIMEOUT} ]]
	do
		echo ".\c" | logmsg
		sleep 1
		((i += 1))
	done
	echo | logmsg

	# Check requirements for encapsulation
	verify_encap_requirements || return 1

	# Prepare for encapsulation, if necessary
	scvx_prepare_encapsulation || return 1
	
	# Update vfstab, if necessary
	update_vfstab || return 1

	# Arrange for the RC script to run
	echo ${SC_LOGFILE} > ${SC_RUNRC} || return 1

	# Reboot, when we get the token
	scvx_reboot || return 1

	# We should never get here
	return 0
}

#####################################################
#
# scvx_is_rootdisk_encapsulated()
#
#	This function checks to see if the rootdisk has
#	already been encapsulated.  (This prevents this
#	script from being run again and corrupting the
#	node installation.)
#
#	Return values:
#
#		zero		the rootdisk is currently encapsulated
#		non-zero	the rootdisk is NOT currently encapsulated.
#
#####################################################
scvx_is_rootdisk_encapsulated()
{
	typeset device
	# Has the rootdisk already been encapsulated?
	# The way to tell is to see if / is mounted from 
	# a Veritas volume (/dev/vx/...)
	# If it has, then there is nothing to be done.
	device=$(mount -V / | awk '/\/dev\/vx/ {print $(NF-1)}')
	if [[ -n $device ]]
	then
		return 0
	fi
	return 1
}

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

integer lindex
integer sflg=0
integer Hflg=0
integer iflg=0
integer eflg=0
integer Lflg=0
integer dflg=0

typeset is_interactive=
typeset c

typeset mode

umask 022

# Parse command line options
let lindex=0
set -A SC_LICENSES
while getopts :sieHL:d: c
do
	case ${c} in
	s)	# Show status
		if [[ -n "${mode}" ]]; then
			show_usage >&2
			cleanup 1
		fi
		((sflg += 1))
		mode=$c
		;;

	H)	# Show help
		if [[ -n "${mode}" ]]; then
			show_usage >&2
			cleanup 1
		fi
		((Hflg += 1))
		mode=$c
		;;

	i)	# Set install mode
		if [[ -n "${mode}" ]]; then
			show_usage >&2
			cleanup 1
		fi
		SC_PERFORM_ENCAP=false
		((iflg += 1))
		mode=$c
		;;

	e)	# Set encapsulate mode
		if [[ -n "${mode}" ]]; then
			show_usage >&2
			cleanup 1
		fi
		SC_PERFORM_ENCAP=true
		((eflg += 1))
		mode=$c
		;;

	L)	# License key
		((Lflg += 1))
		license="${OPTARG}"

		# Make sure none is "none"
		if [[ "$(echo ${license} | nawk '{ print tolower($1) }')" == none ]]; then
			license=none
			let lindex=0
			set -A SC_LICENSES
		fi

		# Add it to the array of licenses
		if [[ "${SC_LICENSES[0]}" != "none" ]]; then
			SC_LICENSES[lindex]="${license}"
			((lindex += 1))
		fi
		;;

	d)	# Path
		if [[ ${dflg} -gt 0 ]]; then
			show_usage >&2
			cleanup 1
		fi
		SC_PKG_PATH="${OPTARG}"
		;;

	*)	# Unknown option
		if [[ ${c} == \? ]]; then
			printf "$(gettext '%s:  Unknown option, -%c.')\n" ${PROG} ${OPTARG}
		fi
		show_usage >&2
		cleanup 1
		;;
	esac
done

# Make sure there are no extra arguments
shift $((OPTIND - 1))
if [[ $# -ne 0 ]]; then
	show_usage >&2
	cleanup 1
fi

# Default mode is interactive
if [[ -z "${mode}" ]]; then
	mode=interactive
	is_interactive=1
else
	is_interactive=
fi

# Make sure that -l and -d were only given with legal modes
if [[ ${Lflg} -gt 0 ]] || [[ ${dflg} -gt 0 ]]; then
	if [[ ${iflg} -eq 0 ]] &&
	    [[ ${eflg} -eq 0 ]] &&
	    [[ -z "${is_interactive}" ]]; then
		show_usage >&2
		cleanup 1
	fi
fi

# Do it
case ${mode} in

# Show status
s)
	# Make sure we are root
	verify_isroot || cleanup 1

	# Make sure we are in the cluster
	verify_ismember || cleanup 1

	# Initialize global variables
	scvx_init || cleanup 1

	# Show status
	show_status

	# Done
	cleanup 0
	;;

# Show help
H)
	# Just print the usage message to stdout
	show_usage

	# Done
	cleanup 0
	;;

# Everything else
i|e|interactive)

	# Make sure we are root
	verify_isroot || cleanup 1

	# Use a log file for this path
	openlog || cleanup 1

	# Make sure we are in the cluster
	verify_ismember || cleanup 1

	# Make sure that the rootdisk is not already encapsulated
	scvx_is_rootdisk_encapsulated && { printf "$(gettext 'The rootdisk has been encapsulated on this node.')\n" ; cleanup 1 ; }

	# Initialize global variables
	scvx_init || cleanup 1

	# Arrange for cleanup on SIGHUP or SIGINT
	trap 'cleanup 10' HUP INT 

	# Create the lock file
	scvx_setlock || cleanup 1

	# Make sure we start off with full cluster membership
	verify_fullmembership || cleanup 1

	# Make sure that quorum has been initialized
	verify_isquorum_init || cleanup 1

	# VxVM installation
	scvx_doit ${is_interactive} || cleanup 1

	# Done
	cleanup 0
	;;

# Internal error
*)
	# Print error
	printf "$(gettext '%s:  Internal error - unknown mode.')\n" ${PROG}

	# Done
	cleanup 1
esac

# We should never get here
exit 0
