#!/sbin/sh
###############################################################################
#
# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#	Copyright 1992-95 AT&T Global Information Solutions
#
# ident	"@(#)lulib.sh	5.71	09/08/03 SMI"
#
# CONTENTS:        library of shell script functions for Live Upgrade modules
#
# This file is meant to be sourced at the very beginning of each live upgrade shell script
# in a preamble that should look very much like the following code snippet:
#
###  
###  LU_PROG_FULL_PATH="$0"
###  LU_PROG_NAME="`basename ${LU_PROG_FULL_PATH}`"; export LU_PROG_NAME
###
###  # Dot the defaults file.
###  if [ ! -s /etc/default/lu ]
###  then
###          echo "${LU_PROG_NAME}: ""`gettext 'ERROR: Live Upgrade not installed properly (/etc/default/lu not found).'`"
###          exit 1
###  fi
###  . /etc/default/lu
###  
###  # Default global variables we expect to be set from /etc/default/lu.
###
###  LUBIN=${LUBIN:=/usr/lib/lu}
###  
###  # Dot the Live Upgrade library functions.
###  if [ ! -s ${LUBIN}/lulib ]
###  then
###          echo "${LU_PROG_NAME}: ""`gettext 'ERROR: The Live Upgrade product is not installed properly (${LUBIN}/lulib not found).'`"
###          exit 1
###  fi
###
###  . ${LUBIN}/lulib
#
###############################################################################

#################################################################################################
# Name:		<main>
# Description:	Main code (outside of any function definitions) - executed when script is sourced.
#		This library should be sourced ONLY after /etc/default/lu is sourced - it will
#		provide default values for all of the variables that SHOULD be defined in that file
#		as well as set variables and check conditions that all scripts depend on.
# Local Prefix:	<none>
# Arguments:	<none>
#################################################################################################

# Establish a sane default umask.
umask 022

# If LU_DEBUG is not defined, define it as "0"

if [ -z "${LU_DEBUG}" ] ; then
	LU_DEBUG="0"
	export LU_DEBUG
fi

# Setup the text domain from which all localized messages are retrieved.

TEXTDOMAIN="SUNW_INSTALL_LU_SCRIPTS" ; export TEXTDOMAIN

# Setup LUPRINTF environment variable.
# This variable is used to output any messages to the various valid destinations.
# Set the default to 'echo', then look for the luprintf utility, and set LUPRINTF
# as appropriate.

LUPRINTF="echo"
if [ -x /etc/lib/lu/luprintf ] ; then
  LUPRINTF="/etc/lib/lu/luprintf"
elif [ ! -f /etc/lib/lu/luprintf ] ; then
  echo "lulib: `gettext \"ERROR: Live Upgrade not installed properly (/etc/lib/lu/luprintf not found).\"`"
fi
export LUPRINTF

# Setup LU_SYSTEM_ARCH environment variable.
# This variable contains the system processor architecture (processor generic type),
# such as 'sparc' or 'i386'.

LU_SYSTEM_ARCH="${LU_SYSTEM_ARCH:=`/bin/uname -p`}" ; export LU_SYSTEM_ARCH

# Setup LU_HARDWARE_ARCH environment variable.
# This variable contains the system hardware architecture (processor specific type),
# such as 'sun', 'sun4c', 'sun4d', 'sun4m', 'sun4u', or 'i86pc'.

LU_HARDWARE_ARCH="${LU_HARDWARE_ARCH:=`/bin/uname -m`}" ; export LU_HARDWARE_ARCH

# Setup LU_HARDWARE_IMPLEMENTATION environment variable.
# This variable contains the system hardware implementation (platform specific type),
# such as 'SUNW,Ultra-1', 'SUNW,Ultra-Enterprise', 'i86pc', etc.

LU_HARDWARE_IMPLEMENTATION="${LU_HARDWARE_IMPLEMENTATION:=`/bin/uname -i`}" ; export LU_HARDWARE_IMPLEMENTATION

# Setup the default syslog facility and priority values.

LU_SYSLOG_FACILITY="${LU_SYSLOG_FACILITY:=local0}" ; export LU_SYSLOG_FACILITY
LU_SYSLOG_PRIORITY="${LU_SYSLOG_PRIORITY:=notice}" ; export LU_SYSLOG_PRIORITY

# Setup other defaults used by all scripts.

LU_COMPARE_DATABASE_DIR="/etc/lu/compare"; export LU_COMPARE_DATABASE_DIR
LU_MANDATORY_CONTENT_CONTROL_FILE="/etc/lu/lu_content_control"; export LU_MANDATORY_CONTENT_CONTROL_FILE
LU_BE_CONFIG_FILE="${LU_BE_CONFIG_FILE:=/etc/lu/.BE_CONFIG}" ; export LU_BE_CONFIG_FILE
LU_LUTAB_FILE="${LU_LUTAB_FILE:=/etc/lutab}" ; export LU_LUTAB_FILE
LU_PROG_NAME="${LU_PROG_NAME:=live upgrade}"
COPYLOCK="${COPYLOCK:=/etc/lu/COPY_LOCK}" ; export COPYLOCK
CURR_VARS="${CURR_VARS:=/etc/lu/.CURR_VARS}" ; export CURR_VARS
LUBIN="${LUBIN:=/usr/lib/lu}" ; export LUBIN
LUETCBIN="${LUETCBIN:=/etc/lib/lu}" ; export LUETCBIN
NEXT_ACTIVE="${NEXT_ACTIVE:=/etc/lu/.NEXT_ACTIVE}" ; export NEXT_ACTIVE
LU_DB_LOCAL="${LU_DB_LOCAL:=/etc/lu/ludb.local.xml}" ; export LU_DB_LOCAL
LU_DB_SYNC_LOCAL="${LU_DB_SYNC_LOCAL:=/etc/lu/ludb.sync-initial.xml}" ; export LU_DB_SYNC_LOCAL
LU_DB_GLOBAL="${LU_DB_GLOBAL:=/etc/lu/ludb.global.xml}" ; export LU_DB_GLOBAL
LU_SYNCLIST="${LU_SYNCLIST:=/etc/lu/synclist}" ; export LU_SYNCLIST
LU_SYNC_LOG_FILE="${LU_SYNC_LOG_FILE:=/etc/lu/sync.log}" ; export LU_SYNC_LOG_FILE
SYNCKEY="${SYNCKEY:=/etc/lu/.SYNCKEY}"

#
# The BOOT_MENU_FILE environment variable is used on both, x86 and SPARC
# architectures and therefore needs to be initialized independent of
# architecture. In case of x86 it is used to look for boot menu file,
# /boot/grub/menu.lst and in case of SPARC it is used to look for file,
# /{zpool}/boot/menu.lst.
#
BOOT_MENU_FILE="menu.lst"; export BOOT_MENU_FILE

#
# variables used for Newboot
#
if [ "${LU_SYSTEM_ARCH}" = "i386" ]; then
	MULTI_BOOT=platform/i86pc/multiboot
	export MULTI_BOOT  # identifies multi BOOT
	SYMDEF=platform/i86pc/boot/solaris/bin/symdef
	export SYMDEF	# id for DBOOT
	FAILSAFE_MULTI_BOOT=boot/multiboot
	export FAILSAFE_MULTI_BOOT
	FAILSAFE_DBOOT_UNIX='boot/platform/i86pc/kernel/unix'
	export FAILSAFE_DBOOT_UNIX
	BOOT_ARCHIVE=platform/i86pc/boot_archive
	export BOOT_ARCHIVE
	GRUB_DIR=boot/grub
	export GRUB_DIR
	LU_MINIROOT_ARCHIVE="x86.miniroot"
	export LU_MINIROOT_ARCHIVE
	LU_FAILSAFE_ARCHIVE=boot/x86.miniroot-safe
	export LU_FAILSAFE_ARCHIVE
	LU_FAILSAFE64_DIR=boot/amd64
	export LU_FAILSAFE64_DIR
	LU_FAILSAFE64_ARCHIVE=${LU_FAILSAFE64_DIR}/x86.miniroot-safe
	export LU_FAILSAFE64_ARCHIVE
	LU_GRUB_BOOT_ENV="/platform/i86pc/boot/solaris/bootenv.rc"
	export LU_GRUB_BOOT_ENV
	LU_GRUB_FILELIST="/platform/i86pc/boot/solaris/filelist.ramdisk"
	export LU_GRUB_FILELIST
	BOOT_MENU_PREFIX='#----- '
	export BOOT_MENU_PREFIX
	BOOT_MENU_HDR_SUFFIX=' - ADDED BY LIVE UPGRADE - DO NOT EDIT  -----'
	export BOOT_MENU_HDR_SUFFIX
	BOOT_MENU_FTR_SUFFIX=' -------------- END LIVE UPGRADE ------------'
	export BOOT_MENU_FTR_SUFFIX
	BOOT_MENU_DIR=boot/grub
	export BOOT_MENU_DIR
	BOOT_MENU=${BOOT_MENU_DIR}/${BOOT_MENU_FILE}
	export BOOT_MENU
	INSTALLGRUB=sbin/installgrub
	export INSTALLGRUB
	LU_SIGN_DIR=/boot/grub/bootsign
	export LU_SIGN_DIR
	LU_SIGN_BACKUP=/etc/bootsign
	export LU_SIGN_BACKUP
	FINDROOT_INSTALLGRUB=/etc/lu/installgrub.findroot
	export FINDROOT_INSTALLGRUB
	FINDROOT_STAGE1=/etc/lu/stage1.findroot
	export FINDROOT_STAGE1
	FINDROOT_STAGE2=/etc/lu/stage2.findroot
	export FINDROOT_STAGE2
	GRUB_CAP=/boot/grub/capability
	export GRUB_CAP

	GRUB_slice="/etc/lu/GRUB_slice"
	export GRUB_slice
	GRUB_root="/etc/lu/GRUB_root"
	export GRUB_root
	GRUB_backup_menu="/etc/lu/GRUB_backup_menu"
	export GRUB_backup_menu
	LU_GRUB_TIMEOUT_CMD="timeout" 
	export LU_GRUB_TIMEOUT_CMD
	LU_GRUB_TIMEOUT_VALUE="10"
	export LU_GRUB_TIMEOUT_VALUE
	LU_GRUB_DEFAULT_CMD="default"
	export LU_GRUB_DEFAULT_CMD
	LU_GRUB_TITLE_CMD="title"
	export LU_GRUB_TITLE_CMD
	LU_GRUB_ITEM_SEP=""
	export LU_GRUB_ITEM_SEP
	LU_GRUB_MENU_PERM="0644"
	export LU_GRUB_MENU_PERM
	LU_GRUB_SPLASH_CMD="splashimage"
	export LU_GRUB_SPLASH_CMD
	LU_GRUB_SPLASH_PATH="/boot/grub/splash.xpm.gz"
	export LU_GRUB_SPLASH_PATH

	BOOTADM_HDR="#---------- ADDED BY BOOTADM - DO NOT EDIT ----------"
	export BOOTADM_HDR
	BOOTADM_FTR="#---------------------END BOOTADM--------------------"
	export BOOTADM_FTR
	BOOTADM_BOOTENV="Solaris bootenv rc"
	export BOOTADM_BOOTENV
	BOOTADM_TRANSIENT="Solaris_reboot_transient"
	export BOOTADM_TRANSIENT
	# biosdev related
	LU_BIOSDEV=/sbin/biosdev
	export LU_BIOSDEV
elif [ "${LU_SYSTEM_ARCH}" = "sparc" ]; then
	BOOT_ARCHIVE=platform/${LU_HARDWARE_ARCH}/boot_archive
	export BOOT_ARCHIVE
	LU_MINIROOT_ARCHIVE="sparc.miniroot"
	export LU_MINIROOT_ARCHIVE
else
	${LUPRINTF} -Eelp2 "`gettext 'Unsupported system architecture'`"
	exit 1
fi

LU_DIR=/etc/lu; export LU_DIR

LU_BOOT_LOGICAL="" ; export LU_BOOT_LOGICAL

LU_WIZARD_ARCHIVE="javaui.cpio.bz2" ; export LU_WIZARD_ARCHIVE

[ "${LU_OUTPUT_FORMAT}" = "xml" ] || LU_OUTPUT_FORMAT='text'
export LU_OUTPUT_FORMAT

# This is a special variable that is changed when this script is built;
# the special string that is set in the following assignment is changed
# to the version of Solaris under which this version of Live Upgrade is
# intended to run against. This prevents live upgrade from upgrading to
# a release of Solaris that it was not built to upgrade to. For example,
# this would contain "5.9" if the version of Solaris that can be upgraded
# to is 5.9.

LU_BUILT_FOR_SOLARIS_VERSION="5.10"

# Check for super-user permissions.

if [ -z "${_LU__IS_ROOT_}" ] ; then
  if [ "`/bin/id | /bin/cut -f 1 -d '(' | /bin/cut -f 2 -d '='`" -ne "0" ] ; then
    if [ -x /etc/lib/lu/luprintf ] ; then
      ${LUPRINTF} -Eelp2 "`gettext 'Super user privilege is required to run this program.'`"
    else
      echo "${LU_PROG_NAME}: ""`gettext 'Super user privilege is required to run this program.'`"
    fi
    exit 1
  fi
  _LU__IS_ROOT_="yes" ; export _LU__IS_ROOT_
fi

################################################################################
# This is used to loop over the list of devices in a zpool, using the
# output of the 'zpool status' command
# ARGS
#	$1	pool name
#	$2	if set to yes, return only the first device found
# Returns
#	0	Command successful
#	1	an error occurred
# Local prefix
#	lgzd
################################################################################
lulib_get_zfs_devs()
{

	if [ "$#" -ne 2 -o -z "$1" ]; then
           ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_get_zfs_devs <pool-name> <first_only>'`"
	   return 1
	fi

	lgzd_pool="$1"
	lgzd_first="$2"

	blob=`/usr/bin/env LC_ALL=C /sbin/zpool status "$lgzd_pool"`
	if [ "$?" -ne 0 ]; then
           ${LUPRINTF} -Eelp2 "`gettext 'zpool status command failed for pool <%s>'`" "$lgzd_pool"
	   return 1
	fi

	start=`echo "$blob" | /usr/bin/grep -n "NAME" | cut -d: -f1`
	start=`expr $start + 2`
	echo "$blob" | tail +$start | awk '{print $1}' | while read dev; do
	    if [ -z "$dev" ]; then
	       continue;
	    elif [ "$dev" = "errors:" ]; then
	       break
	    elif [ "$dev" != "mirror" ]; then
	        echo "$dev" | sed 's+^c+/dev/dsk/c+'
		if [ "$lgzd_first" = yes ]; then
	           break
		fi
	    fi
	done

	return 0
}

get_first_zfs_dev()
{
    lulib_get_zfs_devs "$1" "yes"
}

#################################################################################################
# Given a block device node name, returns the corresponding char device
# node name
#################################################################################################

lulib_get_cdevice()
{

# Can't depend on Solaris devattr for device info. need to recode this.
#       alias=`devattr $1 bdevice`
#       if [ -z "$alias" ]; then
#               return 1
#       fi
#       eval `devattr -v $alias cdevice`
        echo $1 |  sed "s/\/vol\//\/rvol\//g" | sed  "s/\/dsk\//\/rdsk\//g"
}

#################################################################################################
# lulib_check_pbe_mounts - verifies that all of the PBE file systems are mounted.
# RETURN VALUES: Returns 0 for success and 1 for failure.
# REQUIREMENTS: The calling program MUST define "LUBIN" before using lulib_check_pbe_mounts.
#################################################################################################

lulib_check_pbe_mounts()
{
	lcpm_ret=0
	lcpm_pbeName="`lulib_lucurr`"
	${LUPRINTF} -lp2D - "`gettext 'lulib_check_pbe_mounts calling lumk_iconf.'`"
	$LUBIN/lumk_iconf -S "${lcpm_pbeName}" > /etc/lu/tmp/icf.$$
	if [ $? = 0 ] ; then
		# 1. Get list of all vfstab entries where mount at boot == "yes" and
		#    fsck pass != "-".
		lcpm_vfstab=`/usr/bin/cat /etc/vfstab | /usr/bin/awk  -e 'BEGIN {ORS = "|" }
		{ if(($1 !~ /^#/) && ($5 != "-" || $6 == "yes")) print "^"$3"$" }'`

		# 2. Get all the mount points listed in mnttab. 
		lcpm_mnttab=`/sbin/mount | /usr/bin/awk -e 'BEGIN{ORS = "|"}{print "^"$1"$"}'`

		# 3. Remove the mount points listed in ICF file which do not satisfy
		#    1. If result of this operation is not a subset of result of 2,
		#    then we have a problem moving ahead.
		#    Note 'X' used in reg exp below is just a dummy character, which
		#    will never be first character of any mount point name. 
		lcpm_req_mounts=`/usr/bin/awk -F: -e '$6 == "" {print $2}' \
		    /etc/lu/tmp/icf.$$ |
		    /usr/bin/egrep -e "($lcpm_vfstab X)" |
		    /usr/bin/egrep -v -e "($lcpm_mnttab X)"`
		if [ $? -eq 0 ]
		then
			lcpm_normalized_rm=`echo $lcpm_req_mounts`
			${LUPRINTF} -Eelp2 "`gettext 'The following required file systems are \
not mounted by the currently running OS <%s>'`" "$lcpm_normalized_rm"
			lcpm_ret=1
		fi
	else
		lcpm_ret=1
	fi
	# Return status. We do not do a exit here because it is a
	# function that is dotted in
	return $lcpm_ret
}

#################################################################################################
# lulib_validate_be_for_copy {ICF file} - verifys that all of the PBE file 
#       systems are mounted and that the OS can support vxfs-root if the 
#       root file system type is vxfs
# Input: $1 = the BE to check ("" means to use the current BE)
# RETURN VALUES: Returns 0 for success and 1 for failure.
# REQUIREMENTS: The calling program MUST define "LUBIN" before using lulib_validate_be_for_copy.
#################################################################################################

lulib_validate_be_for_copy()
{
	ICF=$1
###
### NEED TO ADD CODE THAT CHECKS THE $1 ARGUMENT AND "DOES THE RIGHT THING"...
###

        # verify the all required PBE file systems are mounted
        lulib_check_pbe_mounts || return 1
        validate_fs_type=`awk -F: '$2 == "/" && $6 == "" {print $4}' $ICF`
        if [ "$validate_fs_type" = "vxfs" ]
        then
                # The following code may need refining if/when Solaris
                # supports vxfs on root
                if [ ! -f /sbin/ckroot ]
                then
                        validate_abe=`awk -F: '$2 == "/" {print $1}' $ICF`
                        ${LUPRINTF} -Eelp2 "`gettext 'Boot environment <%s> is configured with the root file system as 'vxfs' but the currently running OS cannot support this configuration. You will need to create a new boot environment that has root on a supported file system type.'`" "${validate_abe}"
			${LUPRINTF} -Eelp2 "`gettext 'Vxfs-root not supported by currently running OS.'`"
                        return 1
                fi
        fi
        return 0
}

#################################################################################################
# Function: lulib_get_devsize
# Input:
#    $1 = Device which can hold a file system
# Return Code:
#    0 - success.
#    1 - failure.
# Outputs: On success: a string equal to the numeric capacity of the input device
# Function:
#    Using device.tab, determines the size of a given device.
# Notes:
#    If the input device isn't in PBE's device.tab, the device.tab on
#    target BE is searched.
#################################################################################################

lulib_get_devsize()
{
  SLICE="$1"

  #
  # If the 'dev' is a zvol then get its size
  #
  if [ `echo $1 | grep /dev/zvol` ]; then
	POOL=`echo "$1" | /bin/nawk -F/ '{ print $5 }'`
	ZVOLNM=`echo "$1" | /bin/nawk -F/ '{ print $6 }'`
	SIZE=`/sbin/zfs get -Hp volsize "${POOL}"/"${ZVOLNM}" | /bin/nawk '{ print $3}'`
	if [ "$?" -ne "0" ] ; then
		 ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine size of zvol <%s>.'`" $1
		return 1
	fi
	SIZE_BLKS=`expr $SIZE '/' 512`
	SIZE_REM=`expr $SIZE '%' 512`
	if [ "$SIZE_REM" -ne 0 ] ; then
		SIZE_BLKS=`expr $SIZE_BLKS '+' 1`
	fi
	echo "$SIZE_BLKS"
	return 0
  fi

  #
  # If the 'dev' is a dataset, then get its size
  #
  ZSIZE=`[ -x /sbin/zfs ] && /sbin/zfs get -Hpo value used "$1" 2> /dev/null`
  if [ $? = 0 ]; then
	SIZE_BLKS=`expr $ZSIZE '/' 512`
	SIZE_REM=`expr $ZSIZE '%' 512`
	if [ "$SIZE_REM" -ne 0 ]; then
	    SIZE_BLKS=`expr $SIZE_BLKS '+' 1`
	fi
	echo "$SIZE_BLKS"
	return 0
  fi

  # Do we really need to define DEV_DIR???
  DEV_DIR=/dev/rdsk
  if [ `echo $1 | grep /dev/md ` ]; then
    DEV_DIR=`dirname $1 | sed 's/\/dsk/\/rdsk/'`
  fi
  if [ `echo $1 | grep /dev/vx ` ] ; then
    DEV_DIR=`dirname $SLICE | sed 's/\/vx\/dsk/\/vx\/rdsk/g'`
    NODSK=`basename $SLICE`
  elif [ `echo $1 | grep /dev/global ` ] ; then
    DEV_DIR=`dirname $SLICE | sed 's/\/global\/dsk/\/global\/rdsk/g'`
    NODSK=`basename $SLICE`
  else
    NODSK=`echo $SLICE |  sed "s:..*dsk/\(..*\)$:\1:" `
  fi
  THE_DEVICE="${DEV_DIR}/${NODSK}"

  if [ -r "${THE_DEVICE}" ] ; then
    bytespersect="`devinfo -i \"${THE_DEVICE}\" 2>/dev/null | cut -f5`"
    if [ -n "${bytespersect}" -a "${bytespersect}" -ne "512" ] ; then
      ${LUPRINTF} -Eelp2 "`gettext 'Slice <%s> bytes per sector is NOT 512.'`" "${THE_DEVICE}"
      return 1
    fi
    size="`devinfo -p \"${THE_DEVICE}\" 2>/dev/null`"
    if [ "$?" -eq "0" ] ; then
      size="`echo \"${size}\" | cut -f5`"
      if [ -n "${size}" ] ; then
        ${LUPRINTF} -lp2D - "`gettext 'Slice <%s> bytes per sector <%s> size <%s>.'`" "${THE_DEVICE}" "512" "${size}"
        echo "$size"
        return 0
      fi
    fi
  fi

  THE_DEVICE="${DEV_DIR}/`echo $SLICE | cut -d\"/\" -f4`"
  if [ -r "${THE_DEVICE}" ] ; then
    bytespersect="`devinfo -i \"${THE_DEVICE}\" 2>/dev/null | cut -f5`"
    if [ -n "${bytespersect}" -a "${bytespersect}" -ne "512" ] ; then
      ${LUPRINTF} -Eelp2 "`gettext 'Slice <%s> bytes per sector is NOT 512.'`" "${THE_DEVICE}"
      return 1
    fi
    size="`devinfo -p \"${THE_DEVICE}\" 2>/dev/null`"
    if [ "$?" -eq "0" ] ; then
      size="`echo \"${size}\" | cut -f5`"
      if [ -n "${size}" ] ; then
        ${LUPRINTF} -lp2D - "`gettext 'Slice <%s> bytes per sector <%s> size <%s>.'`" "${THE_DEVICE}" "512" "${size}"
        echo "$size"
        return 0
      fi
    fi
  fi
  
  ${LUPRINTF} -Ielp2 "`gettext 'Unable to determine size or capacity of slice <%s>.'`" "${SLICE}"
  return 1
}

#################################################################################################
# Function: lulib_get_pool_from_slice
# Input:
#    Device which contains a zfs pool
# Function:
#    Return the name of the pool that the device is part of
# Returns:	0 - success - pool name was found
#		1 - failure - could not find device, or device is not part of
#				a pool
#################################################################################################

lulib_get_pool_from_slice()
{
	# ensure the device is a raw device
	if [ -b "$1" ]; then
		# attempt to substitute rdsk for dsk
		llgpfs_dev=`echo "$1" | /bin/sed 's+/dsk/+/rdsk/+'`
		if [ "$1" = "$llgpfs_dev" ]; then
			# attempt to use a ",raw" suffix
			llgpfs_dev="$1",raw
		fi
	else
		llgpfs_dev="$1"
	fi
	llgpfs_line=`LC_ALL=C /usr/sbin/fstyp -v "$llgpfs_dev" | /bin/egrep '^name:| name='`
	if [ $? != 0 ]; then
	    return 1
	fi
	echo "$llgpfs_line" | cut -d\' -f2
	return 0
}

#################################################################################################
# Function: lulib_fstyp
# Input:
#    Device which can hold a file system
# Function:
#    Return the file system type for the specified device. First, try all known and supported
#    file system types starting with "ufs" (the most likely base file system), followed by all
#    file system types we know of (like vxfs). Finally, attempt to use the generic /usr/sbin/fstyp
#    to see if it can be heuristically determined. The reason we dont call /usr/sbin/fstyp only
#    is because of the use of heuristics in fstyp, it implies that the result of fstyp is
#    not guaranteed to be accurate.
# Returns:	0 - success - file system type returned.
#		1 - failure - file system type NOT returned.
#################################################################################################

lulib_fstyp()
{
	llfst_device="$1"

	# Check to see if device is block or character special; if not,
	# attempt to translate into block or character special device.

	if [ ! -b "${llfst_device}" -a ! -c "${llfst_device}" ] ; then
		# first check to see if it's a zfs dataset
		[ -x /sbin/zfs ] && /sbin/zfs list -Ho name "${llfst_device}" > /dev/null 2>&1
		if [ $? = 0 ]; then
			echo "zfs"
			return 0
		fi

		# try going through df
		llfst_dfdevice="`/usr/sbin/df -n \"${llfst_device}\" 2>&1`"
		if [ "$?" -eq "0" ] ; then
			llfst_fst="`echo ${llfst_dfdevice} | /bin/sed 's/.*:[ ]*//'`"
			${LUPRINTF} -lp2D 4 "`gettext 'Device <%s> is file system type <%s> [from df].'`" "${llfst_device}" "${llfst_fst}"
			echo "${llfst_fst}"
			return 0
		else
			${LUPRINTF} -lp2D 4 "`gettext 'Device <%s> is not a block or character device and it is not currently mounted.'`" "${llfst_device}"
			return 1
		fi
	fi

	# Check for known supported file systems first to avoid fstyp heuristics.

	for llfst_fst in ${LU_SUPPORTED_FILE_SYSTEM_TYPES} ; do
		if [ -d "/usr/lib/fs/${llfst_fst}" -a -x "/usr/lib/fs/${llfst_fst}/fstyp" ] ; then
			/usr/lib/fs/${llfst_fst}/fstyp \
			    "${llfst_device}" > /dev/null 2>&1
			if [ "$?" -eq "0" ] ; then
				${LUPRINTF} -lp2D 4 "`gettext 'Device <%s> is file system type <%s> [from %s/fstyp].'`" "${llfst_device}" "${llfst_fst}" "${llfst_fst}"
				echo "${llfst_fst}"
				return 0
			fi
			${LUPRINTF} -lp2D 4 "`gettext 'Device <%s> is NOT file system type <%s>.'`" "${llfst_device}" "${llfst_fst}"
		fi
	done

	# Not a known supported file system - use generic fstyp just in case...

	llfst_fst="`/usr/sbin/fstyp \"${llfst_device}\" | /bin/head -1`"
	if [ "$?" -eq "0" ] ; then
		${LUPRINTF} -lp2D 4 "`gettext 'Device <%s> is file system type <%s> [from generic/fstyp].'`" "${llfst_device}" "${llfst_fst}"
		echo "${llfst_fst}"
		return 0
	fi
	${LUPRINTF} -Eelp2 "`gettext 'Device <%s> file system type cannot be determined.'`" "${llfst_device}"
	return 1
}

#################################################################################################
# lulib_validate_lulock - Checks the LU COPY_LOCK file and removes it if it is
#    invalid. In order for a LOCK to be valid, it must either have a
#    "at" job scheduled, or have a lu process actively running.
# RETURN VALUES: Returns 0 if the COPY_LOCK file doesn not exist.
#              : Returns 1 if the COPY_LOCK existed but was invalid and removed
#	       : Returns 2 if the COPY_LOCK exists and a valid scheduled job exists.
#	       : Returns 3 if the COOPY_LOCK exists and a valid currently running job exists
#           	
#################################################################################################

lulib_validate_lulock()
{
        TMP_PS=/tmp/PS.$$
        PROCS=/tmp/PROCS
        PROCS1=/tmp/PROCS1
        COPYLOCK=${COPYLOCK:=/etc/lu/COPY_LOCK}
        OK_TO_REMOVE1=FALSE
        OK_TO_REMOVE2=FALSE

	#Return code when COPYLOCK doesn't exist
        [ ! -f $COPYLOCK ] && return 0

        # Dot in INFO from COPY_LOCK
        . $COPYLOCK

        if [ "$CL_STATUS" = "SCHEDULED" ]; then
                at -l | grep $CL_AT_JOB_NUM > /dev/null 2>&1
                if [ $? = 0 ]; then
                        #LOCK is good, do not remove
                        rm -f $TMP_PS $PROCS $PROCS1

			#Return code when COPYLOCK exists and a valid scheduled job exists
                        return 2
                else
                        OK_TO_REMOVE1=TRUE
                fi
        else
                OK_TO_REMOVE1=TRUE
        fi

        ps -ef > $PROCS

        ps -f | tail +2 | nawk '{print $2}' > $TMP_PS

        for REMOVE_PID in `cat $TMP_PS`
        do
                nawk -v REMOVE_PID=$REMOVE_PID '($2 != REMOVE_PID)' $PROCS > $PROCS1
                mv $PROCS1 $PROCS
        done
        grep -v fsflush $PROCS | egrep "pfinstall|patchadd|patchrm|luupgrade|pkgadd|pkgrm|luactivate|lucreate|lumake|lush|lucompare" > /dev/null 2>&1
        if [ $? != 0 ]; then
                OK_TO_REMOVE2=TRUE
        fi
        rm -f $TMP_PS $PROCS $PROCS1
        if [ "$OK_TO_REMOVE1" = "TRUE" -a "$OK_TO_REMOVE2" = "TRUE" ]  ; then
                ${LUPRINTF} -Ilp2 "`gettext 'Removing invalid lock file.'`"
                sleep 2
                rm -f $COPYLOCK

		#Return code when COPYLOCK existed but was invalid and removed
                return 1
        fi
	
	#Return code when COPYLOCK exists and there exists a currently running job
        return 3
}

#################################################################################################
# Name:		lulib_is_be_name_inuse.
# Description:	Validate a be name as being valid and inuse (in use by any BE).
# Local Prefix:	
# Arguments:	$1 = be name to validate.
# Example:      lulib_is_be_name_inuse
# Returns:	0 - the be name is valid and is inuse (used by a BE).
#		1 - the be name is valid and is not inuse (not used by a BE).
#		2 - the be name could not be looked up.
# Messages:	Messages are output if the BE name is not in a valid or cannot be looked up
#		or the BE name is not in use.
#################################################################################################

lulib_is_be_name_inuse()
{
  ibni_beName="$1"

  # If the /etc/lutab file does not exist, the BE cannot exist.
  if [ ! -f "${LU_LUTAB_FILE}" ] ; then
    lulib_be_name_valid "${ibni_beName}"
    if [ "$?" -eq "0" ] ; then
      ${LUPRINTF} -Eelp2 "`gettext 'The boot environment name <%s> does not exist.'`" "${ibni_beName}"
    fi
    return 1
  fi

  ERRMSG=`${LUETCBIN}/ludo is_be_name_inuse "${ibni_beName}" 2>&1`
  ret="$?"
  if [ "${ret}" -ne "0" ] ; then
    # Errors were encountered
    ${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
  fi

  return "${ret}"
}


#################################################################################################
# Name:		lulib_verify_be_unmounted
# Description:	Check to see if the a boot environment is not mounted; return error if it is.
# Local Prefix:	luvbu_
# Arguments:	$1 = be name to validate.
# Example:      lulib_verify_be_unmounted
# Returns:	0 - the be name is valid and is not mounted (is unmounted).
#		1 - the be name is valid and is mounted.
#		2 - the be name could not be looked up.
# Messages:	Messages are output if the BE name is not in a valid or cannot be looked up
#		or the BE is mounted.
#################################################################################################

lulib_verify_be_unmounted()
{
  luvbu_beName="$1"

  # If the /etc/lutab file does not exist, the BE cannot exist.
  if [ ! -f "${LU_LUTAB_FILE}" ] ; then
    lulib_be_name_valid "${luvbu_beName}"
    return "$?"
  fi

  # Make sure that the BE name is valid.
  ERRMSG=`${LUETCBIN}/ludo is_be_name_valid "${luvbu_beName}" 2>&1`
  ret="$?"
  if [ "${ret}" -ne "0" ] ; then
    # Errors were encountered
    ${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
    return "2"
  fi

  # Get the BE ID.
  luvbu_id="`${LUETCBIN}/ludo get_be_id \"${luvbu_beName}\" 2>&1`"
  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 '%s' "${luvbu_id}"
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to determine boot environment ID for target boot environment <%s>.'`" "${luvbu_beName}"
    return "2"
  fi

  # Find the status of the BE.
  luvbu_status="`${LUETCBIN}/ludo get_be_status_from_be_name \"${luvbu_beName}\"`"
  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to obtain the status of the boot environment <%s>.'`" "${luvbu_beName}"
    return "2"
  fi

  # If it is an incomplete BE then it may not be mounted.
  # Check to see if the root slice is mounted - just in case the user has
  # mounted the root slice manually...
  if [ "${luvbu_status}" != 'C' ] ; then
    # get the ROOT slice for the BE.
    luvbu_rslice="`${LUETCBIN}/ludo get_root_slice_from_be_name \"${luvbu_beName}\"`"
    if [ -n "${luvbu_rslice}" ] ; then
      ${LUETCBIN}/ludo get_mntpt_from_root_slice "${luvbu_rslice}" 2>/dev/null 1>&1
      [ "$?" -eq '0' ] && return 1
    fi
    # Either no root slice found or the root slice is not mounted.
    return 0
  fi

  # The BE must not currently be mounted.
  luvbu_tmp_result_file="/tmp/.lulib.results.tmp.$$"
  LU_OUTPUT_FORMAT=text ${LUBIN}/lumount -V "${luvbu_beName}" 2>${luvbu_tmp_result_file}
  ret="$?"
  if [ "${ret}" -eq "0" ] ; then
    # BE is not mounted - continue.
    /bin/rm -f "${luvbu_tmp_result_file}"
    return "0"
  elif [ "${ret}" -eq "3" ] ; then
    # BE is already mounted - issue error message and exit
    [ -s "${luvbu_tmp_result_file}" ] && ${LUPRINTF} -elp2 '%R' < ${luvbu_tmp_result_file}
    ${LUPRINTF} -Welp2 "`gettext 'The boot environment specified is \
currently mounted. To unmount the BE, run <%s>.'`" "/usr/sbin/luumount ${luvbu_beName}"
    /bin/rm -f "${luvbu_tmp_result_file}"
    return "1"
  fi

  # lumount failed in some strange way.
  [ -s "${luvbu_tmp_result_file}" ] && ${LUPRINTF} -elp2 '%R' < ${luvbu_tmp_result_file}
  ${LUPRINTF} -Welp2 "`gettext 'Unable to verify whether boot environment \
<%s> is mounted or is mountable.'`" "${luvbu_beName}"
  /bin/rm -f "${luvbu_tmp_result_file}"
  return "2"
}

#################################################################################################
# Name:		lulib_is_be_name_unused.
# Description:	Validate a be name as being valid and unused (not in use by any BE).
# Local Prefix:	ibnu_
# Arguments:	$1 = be name to validate.
# Example:      lulib_is_be_name_unused
# Returns:	0 - the be name is valid and is unused (not in use).
#		1 - the be name is valid and is not unused (is in use).
#		2 - the be name could not be looked up.
# Messages:	Messages are output if the BE name is not in a valid or cannot be looked up
#		or the BE name is in use.
#################################################################################################

lulib_is_be_name_unused()
{
  ibnu_beName="$1"

  # If the /etc/lutab file does not exist, the BE cannot exist.
  if [ ! -f "${LU_LUTAB_FILE}" ] ; then
    lulib_be_name_valid "${ibnu_beName}"
    return "$?"
  fi

  ERRMSG=`${LUETCBIN}/ludo is_be_name_unused "${ibnu_beName}" 2>&1`
  ret="$?"
  if [ "${ret}" -ne "0" ] ; then
    # Errors were encountered
    ${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
  fi

  return "${ret}"
}

#################################################################################################
# Name:		lulib_be_name_valid
# Description:	Validate a be name as being valid; NO ATTEMPT MADE TO CHECK TO SEE IF BE EXISTS!
# Local Prefix:	bnv_
# Arguments:	$1 = be name to validate.
# Example:      lulib_be_name_valid "be_name"
# Returns:	0 - the be name is valid and not a duplicate of
#		1 - the be name is not valid.
# Messages:	Messages are output if the BE name is not in a valid format. NO MESSAGES ARE OUTPUT
#		IF THE BE NAME IS VALID.
#################################################################################################

lulib_be_name_valid()
{
  ERRMSG=`${LUETCBIN}/ludo is_be_name_valid "$1" 2>&1`
  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
    return 1
  fi

  return 0
}

#################################################################################################
# Name:		lulib_validate_be
# Description:	Validate a be name exists and is complete; reject if optional check argument provided.
# Local Prefix:	vbe_
# Arguments:	$1 = be name to validate.
#		$2 = optional be name that $1 CANNOT be ("" defaults to no reject check)
#		$3 = optional if set ignore incomplete boot environments
# Example:      lulib_validate_be "newBeName" "currBeName"
# Returns:	0 - the be name is valid and not a duplicate of $2.
#		1 - the be name is not valid.
#		2 - the be name is a duplicate of $2.
#		3 - the be name is valid, not a duplicate of $2, but is incomplete.
# Side Effects: An existing COPYLOCK file has its contents read and executed as commands
#		by the shell - as a result all variables from the copylock get set.
# Messages:	Messages are output if the BE is not valid, if the BE is a duplicate of the
#		$2 BE, if the BE is incomplete
#################################################################################################

lulib_validate_be()
{
  vbe_BeName="$1"
  vbe_CurrBeName="$2"
  vbe_ignoreIncomplete="$3"

  # Validate second be name (if provided)
  if [ -n "${vbe_CurrBeName}" ] ; then
    lulib_be_name_valid "${vbe_CurrBeName}"
    if [ "$?" -ne "0" ] ; then
      return 1
    fi
  fi

  # Make certain the boot environment name specified is valid.
  vbe_beId=`${LUETCBIN}/ludo is_be_name_inuse "${vbe_BeName}" 2>&1`
  if [ "$?" -ne "0" ] ; then
    if [ -n "${vbe_beId}" ] ; then
      ${LUPRINTF} -Eelp2 '%s' "${vbe_beId}"
    else
      ${LUPRINTF} -Eelp2 "`gettext 'The boot environment <%s> is not valid.'`" "${vbe_BeName}"
    fi
    return 1
  fi

  # Do not allow the current BE to be the target.
  if [ -n "${vbe_CurrBeName}" -a "${vbe_BeName}" = "${vbe_CurrBeName}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The current (primary) boot environment <%s> may not be target boot environment.'`" "${vbe_BeName}"
    return 2
  fi

  # If the BE status is not complete then exit out.
  vbe_status=`${LUETCBIN}/ludo get_be_status_from_be_name "${vbe_BeName}"`
  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to obtain the status of the boot environment <%s>.'`" "${vbe_beName}"
    return 1
  fi

  if [ "$vbe_status" != "C" -a -z "${vbe_ignoreIncomplete}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The boot environment <%s> is not Complete.'`" "${vbe_BeName}"
    return 3
  fi
  return 0
}

#################################################################################################
# Name:		lulib_check_any_be_busy
# Description:	Make sure that no boot environment is currently being updated, clearing out
#		any stale copy lock file.
# Local Prefix:	<none>
# Arguments:	<none>
# Example:      lulib_check_any_be_busy
# Returns:	0 - There is NO boot environment is currently being updated.
#		1 - There IS a boot environment currently being updated.
# Side Effects: An existing COPYLOCK file has its contents read and executed as commands
#		by the shell - as a result all variables from the copylock get set.
#################################################################################################

lulib_check_any_be_busy()
{
  COPYLOCK=${COPYLOCK:=/etc/lu/COPY_LOCK}

  # Clean up any old COPYLOCK file.

  lulib_validate_lulock

  # See if an operation is currently in progress; if so, operations can not be performed.

  if [ -f "${COPYLOCK}" -a -s "${COPYLOCK}" ] ; then
    . ${COPYLOCK}
    if [ -n "$CL_STATUS" ];  then
      ${LUPRINTF} -Eelp2 "`gettext 'A Live Upgrade Copy Lock exists: Status <%s> Source BE <%s> Target BE <%s>.'`" "${CL_STATUS}" "${CL_SOURCE_BE}" "${CL_TARGET_BE}"
      return 1
    fi
  fi

  # not busy.
  return 0
}

#################################################################################################
# Name:		lulib_cannot_duplicate_option
# Description:	In validating command line options, emit error if option argument is specified twice.
# Local Prefix:	<none>
# Arguments:	$1 = setting of current option (initial value should be "").
#		$2 = new valid for option.
#		$3 = text describing option.
# Example:	lulib_cannot_duplicate_option "${flag_j}" "${OPTARG}" "-j" && 
# Returns:	return - option is not duplicated ($1 is empty/null).
#		usage()/exit_script(3) - option $3 is duplicated (error message output; program exits).
#################################################################################################

lulib_cannot_duplicate_option()
{
  if [ -n "$1" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The <%s> option may not be specified more than once: <%s> <%s>.'`" "$3" "$2" "$1"
    usage 3
  fi
}

#################################################################################################
# Name:		lulib_cannot_have_options
# Description:	In validating command line options, emit error if more than one specified option
#		argument is specified. CALL ONLY IF TWO OR MORE OPTIONS ARE SPECIFIED.
# Local Prefix:	<none>
# Arguments:	$1 = string containing contents of one or more options.
#		$2 = text describing option that can not accept $1 options.
#		$3 = text describing $1 options.
# Example:	lulib_cannot_have_options "${flag_a}${flag_b}" "-c" "-a or -b"
# Returns:	return - option is not present ($1 is empty/null).
#		usage()/exit_script(3) - option $3 is present (error message output; program exits).
#################################################################################################

lulib_cannot_have_options()
{
  if [ -n "$1" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The <%s> option may not be combined with any of the <%s> options.'`" "$2" "$3"
    usage 3
  fi
}

#################################################################################################
# Name:		lulib_cannot_have_option
# Description:	In validating command line options, emit error if only one single specified option
#		argument is specified. CALL ONLY IF ONE OPTION IS SPECIFIED.
# Local Prefix:	<none>
# Arguments:	$1 = string containing contents of one or more options.
#		$2 = text describing option that can not accept $1 options.
#		$3 = text describing $1 options.
# Example:	lulib_cannot_have_option "${flag_a}${flag_b}" "-c" "-a"
# Returns:	return - option is not present ($1 is empty/null).
#		usage()/exit_script(3) - option $3 is present (error message output; program exits).
#################################################################################################

lulib_cannot_have_option()
{
  if [ -n "$1" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The <%s> option may not be combined with the <%s> option.'`" "$2" "$3"
    usage 3
  fi
}

#################################################################################################
# Name:		lulib_cannot_have_conflicting_options
# Description:	In validating command line options, emit error if both specified options are present.
# Local Prefix:	<none>
# Arguments:	$1 = string containing contents of option one.
#		$2 = text describing option one.
#		$3 = string containing contents of option two.
#		$4 = text describing option two.
# Example:	lulib_cannot_have_conflicting_options "${flag_d}${flag_c}${flag_i}" "-d, -c, -i" "${flag_n}" "-n"
# Returns:	return - both options are not specified.
#		usage()/exit_script(3) - both options are specified (error message output; program exits).
#################################################################################################

lulib_cannot_have_conflicting_options()
{
  if [ -n "$1" -a -n "$3" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The <%s> option may not be combined with the <%s> options.'`" "$2" "$4"
    usage 3
  fi
}

#################################################################################################
# Name:		lulib_cannot_have_conflicting_option
# Description:	In validating command line options, emit error if both specified options are present.
# Local Prefix:	<none>
# Arguments:	$1 = string containing contents of option one.
#		$2 = text describing option one.
#		$3 = string containing contents of option two.
#		$4 = text describing option two.
# Example:	  lulib_cannot_have_conflicting_option "${flag_J}" "-f" "${flag_s}" "-s"
# Returns:	return - both options are not specified.
#		usage()/exit_script(3) - both options are specified (error message output; program exits).
#################################################################################################

lulib_cannot_have_conflicting_option()
{
  if [ -n "$1" -a -n "$3" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The <%s> option may not be combined with the <%s> option.'`" "$2" "$4"
    usage 3
  fi
}

#################################################################################################
# Name:		lulib_cannot_have_arguments
# Description:	In validating command line options, emit error if non-option arguments present.
# Local Prefix:	<none>
# Arguments:	$1 = string containing contents of command non-option arguments.
#		$2 = text describing option that cannot accept $1 options.
# Example:	lulib_cannot_have_argument "${cmdNames}" "-c"
# Returns:	return - non-option arguments not present ($1 is empty/null).
#		usage()/exit_script(3) - non-option arguments present (error message output; program exits).
#################################################################################################

lulib_cannot_have_argument()
{
  if [ -n "$1" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The <%s> option does not accept any command line parameters: <%s>.'`" "$2" "$1"
    usage 3
  fi
}

#################################################################################################
# Name:		lulib_must_have_option
# Description:	In validating command line options, emit error if one single option not present.
#		CALL ONLY IF A SINGLE OPTION IS MISSING.
# Local Prefix:	<none>
# Arguments:	$1 = string containing contents of option to check.
#		$2 = text describing option that requires $3 option.
#		$3 = text describing option that is required by $2 option.
# Example:	lulib_must_have_option "${flag_s}" "-c" "-s"
# Returns:	return - option argument is present ($1 is not empty/not null).
#		usage()/exit_script(3) - option $3 not present (error message output; program exits).
#################################################################################################

lulib_must_have_option()
{
  if [ -z "$1" ] ; then
    if [ -z "$2" ] ; then
      ${LUPRINTF} -Eelp2 "`gettext 'The <%s> option must be specified.'`" "$3"
    else
      ${LUPRINTF} -Eelp2 "`gettext 'The <%s> option requires the <%s> option to also be specified.'`" "$2" "$3"
    fi
    usage 3
  fi
}

#################################################################################################
# Name:		lulib_must_have_options
# Description:	In validating command line options, emit error if two or more options not present.
#		CALL ONLY IF TWO OR MORE OPTIONS ARE MISSING.
# Local Prefix:	<none>
# Arguments:	$1 = string containing contents of option to check.
#		$2 = text describing option that requires $3 option.
#		$3 = text describing option that is required by $2 option.
# Example:	lulib_must_have_options "${flag_s}" "-c" "-s, -q"
# Returns:	return - option argument is present ($1 is not empty/not null).
#		usage()/exit_script(3) - option $3 not present (error message output; program exits).
#################################################################################################

lulib_must_have_options()
{
  if [ -z "$1" ] ; then
    if [ -z "$2" ] ; then
      ${LUPRINTF} -Eelp2 "`gettext 'One of the <%s> options must be specified.'`" "$3"
    else
      ${LUPRINTF} -Eelp2 "`gettext 'The <%s> option requires one of the <%s> options to also be specified.'`" "$2" "$3"
    fi
    usage 3
  fi
}

#################################################################################################
# Name:		lulib_must_have_argument
# Description:	In validating command line options, emit error if non-option arguments not present.
# Local Prefix:	<none>
# Arguments:	$1 = string containing contents of command non-option arguments.
#		$2 = text describing option that requires non-option arguments.
# Example:	lulib_must_have_argument "${cmdNames}" "-r"
# Returns:	return - non-option argument is present ($1 is empty/null).
#		usage()/exit_script(3) - non-option arguments not present (error message output; program exits).
#################################################################################################

lulib_must_have_argument()
{
  if [ -z "$1" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The <%s> option requires one or more command line parameters which have not been provided.'`" "$2"
    usage 3
  fi
}

###############################################################################
# Name:		lulib_update_compare
# Description:	Replicate /etc/lu/compare contents to all boot environments
# Local Prefix:	luc_
# Arguments:	$1 = optional mount point to update database on:
#			== "" - update all complete boot environments
#			!= "" - update boot environment at specified mount point
#		$2 = name of boot environment mounted on "$1"
#			- used for informational message about database update
# Example:	lulib_update_compare
# Returns:	<none>
###############################################################################

lulib_update_compare()
{
	# grab arguments to function
	luc_mntpt="$1"
	luc_abeName="$2"

	# define temporary files and directories
	luc_beNamesFile="/tmp/.lulib.compupd.benames.$$"
	luc_beTmpMntpt="/tmp/.lulib.comupd.mntpt.$$"

	# Remove temporary files/directories (in case they already exist)
	/bin/rm -f "${luc_beNamesFile}"
	/bin/rm -rf "${luc_beTmpMntpt}"

	# If no compare databases present, nothing to do
	[ -d "${LU_COMPARE_DATABASE_DIR}" ] || return

	# If mount point provided, update database on mount point only
	if [ -n "${luc_mntpt}" ] ; then
		# ignore if not a directory
		[ -d "${luc_mntpt}" ] || return

		# ignore if live upgrade is not installed
		[ -d "${luc_mntpt}/etc/lu" ] || return

		# Output message indicating the be that is being updated
		[ -n "${luc_abeName}" ] && ${LUPRINTF} -lp2 "`gettext 'Updating \
compare databases on boot environment <%s>.'`" "${luc_abeName}"

		# remove existing compare database
		/bin/rm -rf "${luc_mntpt}${LU_COMPARE_DATABASE_DIR}" 2>/dev/null

		# replicate compare database on specified mount point
		/bin/cp -rp "${LU_COMPARE_DATABASE_DIR}" "${luc_mntpt}${LU_COMPARE_DATABASE_DIR}"

		return
	fi

	# Process all inactive (-A) and complete (-c) BEs
	# (that is, all complete BEs except the currently active BE).
	# If names cannot be determined, simply return
	${LUBIN}/lunames_list -A -c > "${luc_beNamesFile}"
	if [ $? -ne 0 -o ! -s ${luc_beNamesFile} ] ; then
		/bin/rm -f "${luc_beNamesFile}"
		return
	fi

	# Replicate /etc/lu/compare directory contents for each boot environment
	while read luc_beName ; do
		# Output message indicating the be that is being updated
		${LUPRINTF} -lp2 "`gettext 'Updating compare databases on boot \
environment <%s>.'`" "${luc_beName}"

		# Find the slice/fstype containing / for this boot environment
		set `${LUBIN}/lumk_iconf "${luc_beName}" 2>/dev/null | \
			    /bin/awk -F: '{
					if ($2 == "/") {
						printf("%s %s\n", $3, $4);
					}
				     }'` DUMMY

		# skip this boot environment if no slice/fstype available
		if [ "X$1" = "XDUMMY" ] ; then
			# No ICF on this BE?
			${LUPRINTF} -Ilp2 "`gettext 'Skipping update of boot environment \
<%s>: not configured properly.'`" "${luc_beName}"
			continue
		fi

		# Grab and verify slice to mount
		luc_dev="$1"

		# Ignore if no slice name found
		[ -z "${luc_dev}" ] && continue

		# Ignore if slice name is not a block device
		[ -b "${luc_dev}" ] || continue

		# Grab and verify file system type for slice to mount
		luc_fstyp="$2"

		# Ignore if no file system type found
		[ -z "${luc_fstyp}" ] && continue

		# See if root slice for the boot environment is currently mounted
		luc_beMntpt="`${LUETCBIN}/ludo get_mntpt_from_root_slice \"${luc_dev}\" 2>/dev/null`"
		[ $? -ne 0 ] && luc_beMntpt=""

		# If root slice is not mounted, mount on temporary mount point
		luc_okToUnmount=""
		if [ -z "${luc_beMntpt}" ] ; then
			# Create temporary mount point if it does not exist
			if [ ! -d "${luc_beTmpMntpt}" ] ; then
				/bin/mkdir "${luc_beTmpMntpt}" 2>/dev/null
				[ $? -eq 0 -a -d "${luc_beTmpMntpt}" ] || continue
			fi

			# Mount root slice for BE to update on temp mount point
			/usr/sbin/mount -F "${luc_fstyp}" "${luc_dev}" "${luc_beTmpMntpt}"
			if [ $? -ne 0 ] ; then
				# Mount failed, nuke temp dir and ignore slice
				/bin/rmdir "${luc_beTmpMntpt}"
				${LUPRINTF} -Eelp2 "`gettext 'Unable to mount root \
filesystem <%s> for boot environment <%s>.'`" "${luc_dev}"
				continue
			fi

			# Remember temp mount point can be unmounted/nuked when done
			luc_beMntpt="${luc_beTmpMntpt}"
			luc_okToUnmount="yes"
		fi

		# Check to see if enough of the BE is complete to update the 
		# compare database; if not, skip updating this BE.
		if [ -d "${luc_beMntpt}/etc/lu" ] ; then
			# remove existing compare database
			/bin/rm -rf "${luc_beMntpt}${LU_COMPARE_DATABASE_DIR}" 2>/dev/null

			# replicate compare database on specified mount point
			/bin/cp -rp "${LU_COMPARE_DATABASE_DIR}" "${luc_beMntpt}${LU_COMPARE_DATABASE_DIR}"
		fi

		# If root slice was mounted, unmount it now
		if [ "${luc_okToUnmount}" = "yes" ] ; then
			# sync data to storage medium before unmounting
			/bin/sync
			# force log to be flushed before unmounting
			if [ -x "/usr/sbin/lockfs" ] ; then
				/usr/sbin/lockfs -f "${luc_beTmpMntpt}" 1>/dev/null 2>&1
			fi
			# unmount the root slice
			lulib_unmount_pathname "${luc_beTmpMntpt}"
			ret=$?
			if [ $ret -ne 0 ] ; then
			  lulib_unmount_pathname -f "${luc_beTmpMntpt}"
			  ret=$?
			fi

			[ $ret -eq 0 ] && /bin/rmdir "${luc_beTmpMntpt}"
		fi
	done < ${luc_beNamesFile}

	# Remove temporary files and directories used
	/bin/rm -f ${luc_beNamesFile}
	/bin/rm -rf ${luc_beTmpMntpt}
}

#################################################################################################
# Name:		lulib_discover_sds_installation
# Description:	determine if the solaris metadisk software (Solstice DiskSuite, 
#		Solaris Logical Volume Manager, etc.) is installed on this system,
#		and if so set certain environment variables to indicate what was found
# Local Prefix:	SCS_
# Arguments:	<none>
# Returns:	0	- SDS is NOT installed
#		1	- SDS is installed
#
# The following environment variables will be set:
#
# SDS_FOUND:	indicates if SDS is installed (-z if not installed, -n if installed).
# SDS_PACKAGE:	name of package containing main SDS software.
# SDS_METADB:	full path name to the "metadb" command.
# SDS_METASTAT:	full path name to the "metastat" command.
# SDS_MD_CF:	full path name to the "md.cf" file.
# SDS_DEVROOT:	full path name to the root for metadevices (typically /dev/md).
# SDS_DESCRIPTION:	package "name" text description of which SDS installation was found.
#			-> This is meant for debugging only to know what packages are in use.
# SDS_TEXTDESCRIPTION: internationalizable description of which SDS installation was found.
# SDS_VERSION:	readable localized text description of the version of SDS installed.
#################################################################################################

lulib_discover_sds_installation()
{
  # If this discovery has already been run for another lulib call, dont do it again.
  if [ -n "${_S_D_S__D_I_S_C__D_O_N_E_}" -a -n "${SDS_ARCH}" ] ; then
    if [ -z "${SDS_FOUND}" ] ; then
      return 0
    fi
    return 1
  fi

  SDS_ARCH="`uname -r`"; export SDS_ARCH
  SDS_FOUND=""; export SDS_FOUND
  SDS_PACKAGE=""; export SDS_PACKAGE
  SDS_METADB=""; export SDS_METADB
  SDS_METASTAT=""; export SDS_METASTAT
  SDS_METAROOT=""; export SDS_METAROOT
  SDS_MD_CF=""; export SDS_MD_CF
  SDS_MDDB_CF=""; export SDS_MDDB_CF
  SDS_DESCRIPTION=""; export SDS_DESCRIPTION
  SDS_TEXTDESCRIPTION="`gettext 'Solstice DiskSuite'`"; export SDS_TEXTDESCRIPTION
  SDS_DEVROOT=""; export SDS_DEVROOT
  SDS_VERSION=""; export SDS_VERSION

  # The following variants of SDS must be recognized:
  # SUNWmd (SDS <= 4.2) - Solstice DiskSuite (can be used on Solaris 2.6, Solaris 2.7 and Solaris 2.8)
  # SUNWmd[r,u,x] (SDS >= 4.2.1) - Solstice DiskSuite (can be used on Solaris 2.7 and Solaris 2.8)
  # SUNWmd[r,u,x] Solaris 9 - Solaris Logical Volume Manager (Integrated into OS)
  
  if [ "${SDS_ARCH}" != "5.6" ] ; then
    pkginfo -q 'SUNWmdr.*'
    if [ $? = 0 ] ; then
      pkginfo -q 'SUNWmdu.*'
      if [ $? = 0 ] ; then
	SDS_FOUND="yes"
	SDS_PACKAGE="SUNWmdr"
	SDS_METADB="/usr/sbin/metadb"
	SDS_METASTAT="/usr/sbin/metastat"
	SDS_METAROOT="/usr/sbin/metaroot"
	SDS_MD_CF="/etc/lvm/md.cf"
	SDS_MDDB_CF="/etc/lvm/mddb.cf"
	SDS_DEVROOT="/dev/md"
	if [ "${SDS_ARCH}" != "5.8" ] ; then
	  SDS_TEXTDESCRIPTION="`gettext 'Solaris Volume Manager'`"
	fi
      else
	${LUPRINTF} -Eelp2 "`gettext 'Disk Suite/Logical Volume Manager Problem: SUNWmdr package found but SUNWmdu package missing.'`"
      fi
    fi
  fi
  
  # If SDS 4.2.1/Solaris 9 not yet found then look for SDS 4.2 or before
  if [ -z "${SDS_FOUND}" ] ; then
    pkginfo -q 'SUNWmd.*'
    if [ $? = 0 ] ; then
      SDS_FOUND="yes"
      SDS_PACKAGE="SUNWmd"
      SDS_METADB="/usr/opt/SUNWmd/sbin/metadb"
      SDS_METASTAT="/usr/opt/SUNWmd/sbin/metastat"
      SDS_METAROOT="/usr/opt/SUNWmd/sbin/metaroot"
      SDS_MD_CF="/etc/opt/SUNWmd/md.cf"
      SDS_MDDB_CF="/etc/opt/SUNWmd/mddb.cf"
      SDS_DEVROOT="/dev/md"
    fi
  fi

  # If a variant of SDS has been found:
  # - determine the latest instance of the software that is installed
  # - make sure that the files / procedures used by this script are 
  #   actually installed where we think they should be.
  # - output log messages describing what software was discovered
  
  if [ -n "${SDS_FOUND}" ] ; then

    # Determine the latest instance of the software that is installed
    installedPkgs=`pkginfo "${SDS_PACKAGE}.*" | awk '{print $2}'`
    ${LUPRINTF} -lp2D - "`gettext 'Disk Suite/Logical Volume Manager instances installed: <%s>.'`" "${installedPkgs}"
    SDS_PACKAGE="`echo ${installedPkgs} | tail -1`"

    # Get software description
    SDS_DESCRIPTION="`pkgparam ${SDS_PACKAGE} NAME`"
    SDS_VERSION="`pkgparam ${SDS_PACKAGE} VERSION`"

    # Make sure all commands live upgrade depends on are available
    for THEFILE in ${SDS_METADB} ${SDS_METASTAT} ${SDS_METAROOT} ${SDS_MD_CF} ${SDS_DEVROOT}; do
      if [ ! -r ${THEFILE} ] ; then
	${LUPRINTF} -Eelp2 "`gettext '%s file missing: <%s>.'`" "${SDS_DESCRIPTION}" "${THEFILE}"
	SDS_FOUND=""
      fi
    done 

    # Log what software was discovered
    ${LUPRINTF} -lp2D - "`gettext 'Found SDS <%s> version <%s>.'`" "${SDS_DESCRIPTION}" "${SDS_VERSION}"
    if [ -n "${LU_DEBUG}" -a "${LU_DEBUG}" -ge "2" ] ; then
      ${SDS_METASTAT} 2>&1 | ${LUPRINTF} -lp2D 2 "`gettext 'metastat summary:\n****************************************\n%R\n****************************************'`"
      ${SDS_METADB} 2>&1 | ${LUPRINTF} -lp2D 2 "`gettext 'metadb summary:\n****************************************\n%R\n****************************************'`"
    fi
  fi
  
  # See if any metadevices exist - if not then dont configure for use with SDS

  # For SUNWmdr, use the "metastat -i" command to verify that the meta disk 
  # software is installed properly and that the metadisk configuration is
  # consistent. The -i option checks the status of all active metadevices
  # and hot spares.  The inquiry causes all components of each metadevice
  # to be checked for accessibility, starting at the top level metadevice.
  # When problems are discovered, the metadevice state databases are
  # updated as if an error had occurred.
  #
  # For SUNWmd, use the "metadb" command to see if at least the metadevice database
  # has been initialized. This is because "metastat" does not have a "-i" option
  # in SUNWmd.

  if [ -n "${SDS_FOUND}" ] ; then
    if [ "${SDS_PACKAGE}" = "SUNWmd" ] ; then
      ${SDS_METADB} 1>/dev/null 2>&1
      status=$?
    else
      ${SDS_METASTAT} -i 1>/dev/null 2>&1
      status=$?
    fi
    if [ ${status} != 0 ] ; then
      SDS_FOUND=""
      ${LUPRINTF} -lp2D - "`gettext '%s: not initialized or having problems: ignored.'`" "${SDS_DESCRIPTION}"
    else
      ${LUPRINTF} -lp2D - "`gettext '%s: operational and available.'`" "${SDS_DESCRIPTION}"
    fi
  fi
  
  # Set the optimization flag so we dont execute this discovery again if its already been done
  _S_D_S__D_I_S_C__D_O_N_E_="yes" ; export _S_D_S__D_I_S_C__D_O_N_E_

  # Return results of discovery
  if [ -z "${SDS_FOUND}" ] ; then
    return 0
  fi
  return 1
}

#################################################################################################
# Name:		lulib_validate_is_directory_not_empty
# Description:	Verify that a string argument is a directory and is not empty.
# Local Prefix:	vde_
# Arguments:	$1 = name of directory to validate
# Returns:	0 - $1 is a directory
#		1 - $1 is not a directory
#		2 - $1 does not exist
#		3 - $1 was not specified (is the null string)
#		4 - $1 is a directory but is empty
#################################################################################################

lulib_validate_is_directory_not_empty()
{
  vde_location="$1"
  lulib_validate_is_directory "${vde_location}"
  if [ "$?" -ne "0" ] ; then
    return 1
  fi
  if [ "`/bin/ls \"${vde_location}\" | /bin/wc -c`" -eq "0" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The path <%s> is an empty directory.'`" "${vde_location}"
    return 4
  fi	
  return 0
}

#################################################################################################
# Name:		lulib_validate_is_directory
# Description:	Verify that a string argument is a directory, output error messages if it is not
# Local Prefix:	vid_
# Arguments:	$1 = name of directory to validate
# Returns:	0 - $1 is a directory
#		1 - $1 is not a directory
#		2 - $1 does not exist
#		3 - $1 was not specified (is the null string)
#################################################################################################

lulib_validate_is_directory()
{
  vid_location="$1"

  # Assure path specified
  if [ -z "${vid_location}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'No path specified.'`"
    return 3
  fi

  # Check to see if path object exists at all
  /bin/ls -d "${vid_location}" 1>/dev/null 2>&1
  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The path <%s> does not exist.'`" "${vid_location}"
    return 2
  fi

  # Check to see if path object is a file (just to give unique message about it being a "file")
  if [ -f "${vid_location}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The path <%s> is an ordinary file (not a directory).'`" "${vid_location}"
    return 1
  fi

  # Make sure the path object is a directory
  if [ ! -d "${vid_location}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The path <%s> is not a directory.'`" "${vid_location}"
    return 1
  fi

  # Success...
  return 0
}

#################################################################################################
# Name:		lulib_fixup_startup_settings
# Description:	When each script starts, it should do a few boilerplate things:
#		  . /etc/default/lu
#		  LUBIN=${LUBIN:=/usr/lib/lu}
#		  . ${LUBIN}/lulib
#		  LUPRINTF=${LUPRINTF:=echo}; export LUPRINTF
#		  << parse all command line options >>
#		  lulib_fixup_startup_settings
#		This function allows the command line arguments -x debuglevel, -l errlog, -o sesslog
#		to be processed in each script, which should set the appropriate LU_*_OVERRIDE global.
#		This function then checks to see if any overrides are set and if so it overrides
#		the default LU_* settings from the /etc/default/lu file. This allows a script to
#		override what is in the /etc/default/lu file and have it propagated to all other
#		scripts.
# Local Prefix:	<none>
# Arguments:	<none>
# Globals:	LU_DEBUG, LU_DEBUG_OVERRIDE, LU_SESSION_LOG_FILE, LU_SESSION_LOG_FILE_OVERRIDE,
#		LU_ERROR_LOG_FILE, LU_ERROR_LOG_FILE_OVERRIDE
# Returns:	<none>
# Side Effects:	IF LU_DEBUG is set to '10' then 'set -x' to all scripts

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

lulib_fixup_startup_settings()
{
  # Propagate LU_DEBUG.
  if [ -n "${LU_DEBUG_OVERRIDE}" ] ; then
    LU_DEBUG="${LU_DEBUG_OVERRIDE}"
  fi
  export LU_DEBUG_OVERRIDE
  export LU_DEBUG

  # If LU_DEBUG is set to '10' or greater, then 'set -x'
  if [ -n "${LU_DEBUG}" -a "${LU_DEBUG}" -ge '10' ] ; then
    set -x
  fi

  # Set scheduling priorities.
  if [ -z "${_LU__SCHEDULING_PRIORITY_SET_}" ] ; then
    # If default value not set, assume minimum system priority.
    if [ -z "${LU_SCHEDULING_PRIORITY}" ] ; then
      LU_SCHEDULING_PRIORITY="-n +19"
    fi
    # Use renice to change this processes priority; it will cause
    # this and all child processes to have run at the new priority.
    ERRMSG="`/bin/renice ${LU_SCHEDULING_PRIORITY} -p $$`"
    if [ "$?" -ne "0" ] ; then
      ${LUPRINTF} -Ielp2 "`gettext 'Unable to set scheduling priority to <%s> from <%s>.'`" \
	"${LU_SCHEDULING_PRIORITY}" 'LU_SCHEDULING_PRIORITY'
    else
      ${LUPRINTF} -lp2D - "`gettext 'Set scheduling priority to <%s>.'`" "${LU_SCHEDULING_PRIORITY}"
    fi
    # Set global flag to indicate the priority has already been altered.
    _LU__SCHEDULING_PRIORITY_SET_="yes"; export _LU__SCHEDULING_PRIORITY_SET_
  fi

  # Propagate LU_SESSION_LOG_FILE.
  if [ -n "${LU_SESSION_LOG_FILE_OVERRIDE}" ] ; then
    LU_SESSION_LOG_FILE="${LU_SESSION_LOG_FILE_OVERRIDE}"
  fi
  export LU_SESSION_LOG_FILE_OVERRIDE
  export LU_SESSION_LOG_FILE

  # Verify that the session log can be written to.
  if [ -n "${LU_SESSION_LOG_FILE}" ] ; then
    ERRMSG=`${LUPRINTF} -c "${LU_SESSION_LOG_FILE}" 2>&1`
    if [ $? -ne 0 ] ; then
      ${LUPRINTF} -Elp2 "`gettext 'Unable to write to log file <%s> - no session logging done.'`" "${LU_SESSION_LOG_FILE}"
      LU_SESSION_LOG_FILE=""
      LU_SESSION_LOG_FILE_OVERRIDE=""
    fi
  fi

  # Propagate LU_ERROR_LOG_FILE.
  if [ -n "${LU_ERROR_LOG_FILE_OVERRIDE}" ] ; then
    LU_ERROR_LOG_FILE="${LU_ERROR_LOG_FILE_OVERRIDE}"
  fi
  export LU_ERROR_LOG_FILE_OVERRIDE
  export LU_ERROR_LOG_FILE

  # Verify that the error log can be written to.
  if [ -n "${LU_ERROR_LOG_FILE}" ] ; then
    ERRMSG=`${LUPRINTF} -c "${LU_ERROR_LOG_FILE}" 2>&1`
    if [ $? -ne 0 ] ; then
      ${LUPRINTF} -Eep2 "`gettext 'Unable to write to log file <%s> - no error logging done.'`" "${LU_ERROR_LOG_FILE}"
      LU_ERROR_LOG_FILE=""
      LU_ERROR_LOG_FILE_OVERRIDE=""
    fi
  fi

  # Propagate LU_OUTPUT_FORMAT.
  if [ -n "${LU_OUTPUT_FORMAT_OVERRIDE}" ] ; then
    LU_OUTPUT_FORMAT="${LU_OUTPUT_FORMAT_OVERRIDE}"
  fi
  export LU_OUTPUT_FORMAT_OVERRIDE
  export LU_OUTPUT_FORMAT

  # The "_LU_OUTPUT_XML_" variable is set to null if XML is not enabled;
  # it is set to "yes" if XML is enabled.
  _LU_OUTPUT_XML_=''
  [ "${LU_OUTPUT_FORMAT}" = 'xml' ] && _LU_OUTPUT_XML_=yes
  export _LU_OUTPUT_XML_
}

#################################################################################################
# Name:		lulib_set_error_log_file
# Description:	Set the error log file name - called during initial options processing.
# Local Prefix:	<none>
# Arguments:	$1 = name of the error log file to set.
# Globals:	LU_ERROR_LOG_FILE_OVERRIDE
#		LU_ERROR_LOG_FILE
# Side Effects:	LU_ERROR_LOG_FILE_OVERRIDE - set to "$1"
#		LU_ERROR_LOG_FILE - set to "$1"
# Returns:	<none>
#################################################################################################

lulib_set_error_log_file()
{
  LU_ERROR_LOG_FILE_OVERRIDE="$1"
  export LU_ERROR_LOG_FILE_OVERRIDE
  LU_ERROR_LOG_FILE="$1"
  export LU_ERROR_LOG_FILE
}

#################################################################################################
# Name:		lulib_set_session_log_file
# Description:	Set the session log file name - called during initial options processing.
# Local Prefix:	<none>
# Arguments:	$1 = name of the session log file to set.
# Globals:	LU_SESSION_LOG_FILE_OVERRIDE
#		LU_SESSION_LOG_FILE
# Side Effects:	LU_SESSION_LOG_FILE_OVERRIDE - set to "$1"
#		LU_SESSION_LOG_FILE - set to "$1"
# Returns:	<none>
#################################################################################################

lulib_set_session_log_file()
{
  LU_SESSION_LOG_FILE_OVERRIDE="$1"
  export LU_SESSION_LOG_FILE_OVERRIDE
  LU_SESSION_LOG_FILE="$1"
  export LU_SESSION_LOG_FILE
}

#################################################################################################
# Name:		lulib_set_debug
# Description:	Set the debug flag - called during initial options processing.
# Local Prefix:	<none>
# Arguments:	$1 = name of the error log file to set.
# Globals:	LU_DEBUG_OVERRIDE
#		LU_DEBUG
# Side Effects:	LU_DEBUG_OVERRIDE - set to "$1"
#		LU_DEBUG - set to "$1"
# Returns:	<none>
#################################################################################################

lulib_set_debug()
{
  LU_DEBUG_OVERRIDE="$1"
  export LU_DEBUG_OVERRIDE
  LU_DEBUG="$1"
  export LU_DEBUG
}

#################################################################################################
# Name:		lulib_set_output_format
# Description:	Set the output format setting - called during initial options processing.
# Local Prefix:	<none>
# Arguments:	$1 = name of the error log file to set.
# Globals:	LU_OUTPUT_FORMAT_OVERRIDE
#		LU_OUTPUT_FORMAT
# Side Effects:	LU_OUTPUT_FORMAT_OVERRIDE - set to "$1"
#		LU_OUTPUT_FORMAT - set to "$1"
# Returns:	<none>
#################################################################################################

lulib_set_output_format()
{

  LU_OUTPUT_FORMAT_OVERRIDE="$1"
  export LU_OUTPUT_FORMAT_OVERRIDE
  LU_OUTPUT_FORMAT="$1"
  export LU_OUTPUT_FORMAT
}

#################################################################################################
# Name:		lulib_icf_validate
# Description:	Validate an ICF file contents
# Local Prefix:	ivl_
# Arguments:	$1 = name of the icf file to validate
# Returns:	0 - icf file exists, has contents, and is valid.
#		1 - icf file is not valid.
#################################################################################################

lulib_icf_validate()
{
  ivl_name="$1"

  if [ -z "${ivl_name}" ]; then
    ${LUPRINTF} -Eelp2 "`gettext 'Internal Configuration File path was not specified.'`"
    return 1
  fi

  if [ ! -f "${ivl_name}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'Internal Configuration File <%s> is not a file.'`" "${ivl_name}"
    return 1
  fi

  if [ ! -s "${ivl_name}" ]; then
    ${LUPRINTF} -Eelp2 "`gettext 'Internal Configuration File <%s> exists but has no contents.'`" "${ivl_name}"
    return 1
  fi

  if [ ! -r "${ivl_name}" ]; then
    ${LUPRINTF} -Eelp2 "`gettext 'Internal Configuration File <%s> exists but cannot be read.'`" "${ivl_name}"
    return 1
  fi

  nawk -F: ' { if (NF < 5 || NF > 6) exit 1 }' "${ivl_name}"
  if [ "$?" -eq "1" ]; then
    ${LUPRINTF} -Eelp2 "`gettext 'Internal Configuration File <%s> has unrecognized contents.'`" "${ivl_name}"
    return 1
  fi

  return 0
}

#################################################################################################
# Name:		lulib_validate_bemntpt
# Description:	Validate a BE mount point
# Local Prefix:	vbmp_
# Arguments:	$1 = mount point to be verified.
# Returns:	0 - mount point exists and is valid.
#		1 - mount point is not valid.
#################################################################################################

lulib_validate_bemntpt()
{
  vbmp_beName="$1"

  if [ -z "${vbmp_beName}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The mount point was not specified.'`"
   return 0
  fi

  if [ ! -r "${vbmp_beName}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The mount point <%s> is not a valid ABE (not mounted, not readable).'`" "${vbmp_beName}"
    return 1
  fi

  if [ ! -d "${vbmp_beName}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The mount point <%s> is not a valid (not a directory).'`" "${vbmp_beName}"
    return 1
  fi

  if [ ! -d "${vbmp_beName}/etc" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The mount point <%s> is not a valid ABE mount point (no /etc directory found).'`" "${vbmp_beName}"
    return 1
  fi

  return 0
}

#################################################################################################
# Name:		lulib_normalize_os_version
# Description:	Given an OS version string, normalize it to a single numeric value according
#		to this formula: (major * 10000) + (minor * 100) + patch
#		For example: 5.5 = 50500, 5.5.1 = 50501, 5.9 = 50900, 5.10 = 51000
# Local Prefix:	llnov_
# Arguments:	$1 = release of SunOS to normalize
# Returns:	<none>
# Outputs:	Numeric OS version string.
# NOTE:		When SunOS 5.11 becomes real, add an entry for 5.14. Etc.
#################################################################################################

lulib_normalize_os_version()
{
  llnov_release="$1"
  if [ "${llnov_release}" = "2.5" -o "${llnov_release}" = "5.5" ] ; then
    llnov_major="5"
    llnov_minor="5"
    llnov_patch="1"
  elif [ "${llnov_release}" = "2.5.1" -o "${llnov_release}" = "5.5.1" ] ; then
    llnov_major="5"
    llnov_minor="5"
    llnov_patch="1"
  elif [ "${llnov_release}" = "2.6" -o "${llnov_release}" = "5.6" ] ; then
    llnov_major="5"
    llnov_minor="6"
    llnov_patch="0"
  elif [ "${llnov_release}" = "2.7" -o "${llnov_release}" = "5.7" -o "${llnov_release}" = "7" ] ; then
    llnov_major="5"
    llnov_minor="7"
    llnov_patch="0"
  elif [ "${llnov_release}" = "2.8" -o "${llnov_release}" = "5.8" -o "${llnov_release}" = "8" ] ; then
    llnov_major="5"
    llnov_minor="8"
    llnov_patch="0"
  elif [ "${llnov_release}" = "2.9" -o "${llnov_release}" = "5.9" -o "${llnov_release}" = "9" ] ; then
    llnov_major="5"
    llnov_minor="9"
    llnov_patch="0"
  elif [ "${llnov_release}" = "2.10" -o "${llnov_release}" = "5.10" -o "${llnov_release}" = "10" ] ; then
    llnov_major="5"
    llnov_minor="10"
    llnov_patch="0"
  elif [ "${llnov_release}" = "2.11" -o "${llnov_release}" = "5.11" -o "${llnov_release}" = "11" ] ; then
    llnov_major="5"
    llnov_minor="11"
    llnov_patch="0"
  elif [ "${llnov_release}" = "2.12" -o "${llnov_release}" = "5.12" -o "${llnov_release}" = "12" ] ; then
    llnov_major="5"
    llnov_minor="12"
    llnov_patch="0"
  elif [ "${llnov_release}" = "2.13" -o "${llnov_release}" = "5.13" -o "${llnov_release}" = "13" ] ; then
    llnov_major="5"
    llnov_minor="13"
    llnov_patch="0"
  else
    llnov_major="`echo ${llnov_release} | /bin/awk -F'.' '{print $1}'`"
    if [ -z "${llnov_major}" ] ; then
      llnov_major="0"
    fi
    llnov_minor="`echo ${llnov_release} | /bin/awk -F'.' '{print $2}'`"
    if [ -z "${llnov_minor}" ] ; then
      llnov_minor="0"
    fi
    llnov_patch="`echo ${llnov_release} | /bin/awk -F'.' '{print $3}'`"
    if [ -z "${llnov_patch}" ] ; then
      llnov_patch="0"
    fi
    if [ "${llnov_major}" -eq "2" ] ; then
      llnov_major="5"
    elif [ "${llnov_minor}" -eq "0" -a "${llnov_patch}" -eq "0" ] ; then
      llnov_patch="${llnov_minor}"
      llnov_minor="${llnov_major}"
      llnov_major="5"
    elif [ "${llnov_patch}" -eq "0" -a "${llnov_major}" -ne "5" ] ; then
      llnov_patch="${llnov_minor}"
      llnov_minor="${llnov_major}"
      llnov_major="5"
    fi
  fi
  echo "`expr $llnov_major '*' 10000 '+' $llnov_minor '*' 100 '+' $llnov_patch`"
}
  
#################################################################################################
# Name:		lulib_is_platform_supported
# Description:	Validate the current hardware architecture is supported by a particular SunOS release.
# Local Prefix:	llips_
# Arguments:	$1 = release of SunOS to check against current platform.
# Returns:	0 - platform is supported.
#		1 - platform is not supported.
#################################################################################################

lulib_is_platform_supported()
{
  llips_release="$1"
  llips_eolAfterRelease=`/bin/grep -s "^LU_PLATFORM_${LU_HARDWARE_ARCH}_UNSUPPORTED_AFTER=" "/etc/default/lu" 2>/dev/null | /bin/head -1 | /bin/cut -d'=' -f2`
  if [ -z "${llips_eolAfterRelease}" ] ; then
    return 0
  fi
  llips_targetRelease="`lulib_normalize_os_version \"${llips_release}\""
  llips_eolRelease="`lulib_normalize_os_version \"${llips_eolAfterRelease}\""
  if [ "${llips_targetRelease}" -le "${llips_eolRelease}" ] ; then
    # Supported - return success.
    ${LUPRINTF} -lp2D - "`gettext 'Platform <%s> is supported on Solaris release <%s>.'`" "${LU_HARDWARE_ARCH}" "${llips_release}"
    return 0
  fi

  # Not supported - return error.
  ${LUPRINTF} -lp2D - "`gettext 'Platform <%s> is no longer supported on Solaris release <%s> (after release <%s>).'`" "${LU_HARDWARE_ARCH}" "${llips_release}" "${llips_eolAfterRelease}"
  return 1
}

#################################################################################################
# Name:		lulib_is_upgrade_supported
# Description:	Validate that an OS of a particular version can be upgraded with this version
#		of Live Upgrade.
# Local Prefix:	llius_
# Arguments:	$1 = release of SunOS to check against current version of Live Upgrade.
# Returns:	0 - OS to be upgraded to is supported.
#		1 - OS to be upgraded to is NOT supported.
#################################################################################################

lulib_is_upgrade_supported()
{
  llius_release="$1"
  llius_targetRelease="`lulib_normalize_os_version \"${llius_release}\""
  llius_supportedRelease="`lulib_normalize_os_version \"${LU_BUILT_FOR_SOLARIS_VERSION}\""
  if [ "${llius_targetRelease}" -eq "${llius_supportedRelease}" ] ; then
    # Supported - return success.
    ${LUPRINTF} -lp2D - "`gettext 'Upgrade supported to Solaris version <%s>.'`" "${llius_release}"
    return 0
  fi

  # Not supported - see if override flag LU_ALLOW_ANY_SOLARIS_VERSION_UPGRADE set in /etc/default/lu.
  if [ "${LU_ALLOW_ANY_SOLARIS_VERSION_UPGRADE}" = "YES" -o "${LU_ALLOW_ANY_SOLARIS_VERSION_UPGRADE}" = "yes" ] ; then
    # Not supported but overridden - return success.
    ${LUPRINTF} -lp2D - "`gettext 'Upgrade not supported to Solaris version <%s> (only to Solaris version <%s>) but allowed because LU_ALLOW_ANY_SOLARIS_VERSION_UPGRADE set in /etc/default/lu.'`" "${llius_release}" "${LU_BUILT_FOR_SOLARIS_VERSION}"
    return 0
  fi

  # Not supported - return error.
  ${LUPRINTF} -lp2D - "`gettext 'Upgrade is not supported to Solaris version <%s> (only to Solaris version <%s>).'`" "${llius_release}" "${LU_BUILT_FOR_SOLARIS_VERSION}"
  return 1
}

#################################################################################################
# Name:		lulib_lucurr
# Description:	Return name of the currently active BE. This call is an optimization replacement
#		for calling 'lucurr' directly - it is much faster but it can only be used when
#		no arguments would be passed to lucurr (such as an alternative mount point -m)
#		and can not be used in single user mode.
# Local Prefix:	llluc
# Arguments:	None.
# Returns:	0 - BE name has been returned as a string value.
#		1 - BE name coult not be determined.
# Outputs:	Name of currently active BE.
#################################################################################################

lulib_lucurr()
{
  # If BE name not already cached, see if local BE configuration file is available; if so,
  # use the information stored in that file to determine the name of the current BE.

  if [ -z "${LU_CURRENT_BE_NAME}" ] ; then
    LU_BE_CONFIG_FILE="/etc/lu/.BE_CONFIG"
    # Do it the easy way first: see if this BE contains a BE configuration
    # file and if so look for the BE_NAME entry.
    if [ -f "${LU_BE_CONFIG_FILE}" ] ; then
      LUBECF_BE_NAME=""
      . "${LU_BE_CONFIG_FILE}"
      if [ -n "${LUBECF_BE_NAME}" ] ; then
        LU_CURRENT_BE_NAME="${LUBECF_BE_NAME}"
	export LU_CURRENT_BE_NAME
      fi
    fi
  fi

  # If BE name not already cached, call lucurr to determine the currently active BE name.

  if [ -z "${LU_CURRENT_BE_NAME}" ] ; then
    LU_CURRENT_BE_NAME="`${LUBIN}/lucurr`"
    if [ "$?" -ne "0" ] ; then
      LU_CURRENT_BE_NAME=""
      return 1
    fi
    if [ -z "${LU_CURRENT_BE_NAME}" ] ; then
      ${LUPRINTF} -Eelp2 "`gettext 'Unable to determine the name of the current active boot environment.'`"
      return 1
    fi
    export LU_CURRENT_BE_NAME
  fi

  # Return the cached name of the currently active BE.
  echo "${LU_CURRENT_BE_NAME}"
  return 0
}

###############################################################################
# Name:		lulib_zone_check
# Description:	Check if Zones tools are needed to process the contents of the
#		indicated boot environment.  If Zones tools are needed, then
#		check whether the tools are present and up-to-date.
# Arguments:	<be-root> [exit script]
#		<be_root> is the path to the boot environment root.
#		[exit script] is an optional exit script to run
# Returns:	1 if there are non-global zones, 0 if not
#		Exits on error.
# Outputs:	None (save for errors)
###############################################################################
lulib_zone_check()
{
    zone_check_rootdir="$1"
    zone_check_exit="$2"

    zone_check_index="$zone_check_rootdir/etc/zones/index"

    if [ -z "$zone_check_exit" ]; then
	zone_check_exit="exit 1"
    fi

    # If the index file doesn't exist, then there are no non-global zones.
    [ -f "$zone_check_index" ] || return 0

    # Check for non-global zones without using the tools.  If there are
    # any, then this negated (-v) pattern will match.  Otherwise, if
    # no matches, then no zones, so ignore the tools.
    egrep -v '^(#|global:)' "$zone_check_index" >/dev/null || return 0

    # Check if the Zones tools are installed.  If not, we have a problem.
    if [ ! -x /usr/sbin/zonecfg -o ! -x /usr/sbin/zoneadm ]; then
	$LUPRINTF -Eelp2 "`gettext '\
The boot environment at <%s> requires Zones tools to manipulate it,\n\
but none are installed on this system.'`" "$zone_check_rootdir"
	eval $zone_check_exit
    fi

    # Check if the zonecfg tool includes the -R option.  If it does, then
    # it is new enough to run this version of the Live Upgrade tools.
    /usr/sbin/zonecfg -R "$zone_check_rootdir" -z test exit >/dev/null 2>&1
    if [ $? -ne 0 ]; then
	$LUPRINTF -Eelp2 "`gettext '\
You must install the Zones tool patches to use this set of Live Upgrade\n\
packages to manipulate the boot environment at <%s>.'`" "$zone_check_rootdir"
	eval $zone_check_exit
    fi
    return 1
}

###############################################################################
# Name:		all_nonglobal_zones
# Description:	Get a list of the native non-global zones installed on the
#		running system. "cluster" branded zones will be treated as
#		native non-global zones.
# Arguments:	[-c] [mount_point]
# Returns:	None
# Outputs:	List of nonglobal zone names on stdout.
###############################################################################
all_nonglobal_zones()
{
    if [ "$1" = "-c" ]; then
	nonglobal_zones_flags="-c"
	shift
    else
	nonglobal_zones_flags="-i"
    fi
    if [ $# -eq 1 ]; then
	nonglobal_zones_root="$1"
    else
	nonglobal_zones_root=/
    fi
    if [ -r "$nonglobal_zones_root/etc/zones/index" -a -x /usr/sbin/zoneadm ]
    then
	# Filter the output of zoneadm and fill in a blank uuid
	# field with a dash so that read parses out the line correctly
	/usr/sbin/zoneadm -R "$nonglobal_zones_root" list \
	  $nonglobal_zones_flags -p | sed 's/\([^\]\)::/\1:-:/' |
	while IFS=: read zoneid zonename state path uuid zonebrand junk; do
	    # if zonebrand is blank, it means brands are not
	    # supported, set it to native
	    [ -z "$zonebrand" ] && zonebrand=native
	    [ $zonename != global ] && [ $zonebrand = native \
	        -o $zonebrand = cluster ] &&
	      echo $zonename
	done
    fi
}

###############################################################################
# Name:		lulib_list_zones
# Description:	Get a parseable list of the native zones installed in a given
#		boot environment. "cluster" branded zones will be treated as
#		native non-global zones.
# Arguments:	[flags] <be-root>
#		Flags are those accepted for "zoneadm list"; documented as
#		[list_options] in zoneadm(1M).  The expected options here are
#		"-i", "-c" or no option at all.
#		<be_root> is the path to the boot environment root.
# Returns:	None
# Outputs:	List zone data in "zoneadm list -p" (parseable) format.
###############################################################################
lulib_list_zones()
{
    list_zones_flags=
    case "$1" in
	-*)
	    list_zones_flags="$list_zones_flags $1"
	    shift
	    ;;
    esac
    list_zones_rootdir="$1"
    if [ -z "$1" ]; then
	list_zones_rootdir=/
    fi
    if [ -r "$list_zones_rootdir/etc/zones/index" ]; then
	# Filter the output of zoneadm and fill in a blank uuid
	# field with a dash so that read parses out the line correctly
	zoneadm -R "$list_zones_rootdir" list $list_zones_flags -p |
	sed 's/\([^\]\)::/\1:-:/' |
	while IFS=: read zoneid zonename state path uuid zonebrand junk; do
	    # if zonebrand is blank, it means brands are not
	    # supported, set it to native
	    [ -z "$zonebrand" ] && zonebrand=native
	    [ $zonebrand = native -o $zonebrand = cluster ] &&
	      zoneadm -R "$list_zones_rootdir" -z $zonename list -p
	done
    else
	echo "0:global:installed:$list_zones_rootdir:"
    fi
}

###############################################################################
# Name:		lulib_list_branded_zones
# Description:	Get a parseable list of the branded zones installed in a given
#		boot environment. "cluster" branded zones will be treated as
#		native non-global zones.
# Arguments:	[flags] <be-root>
#		Flags are those accepted for "zoneadm list"; documented as
#		[list_options] in zoneadm(1M).  The expected options here are
#		"-i", "-c" or no option at all.
#		<be_root> is the path to the boot environment root.
# Returns:	None
# Outputs:	List zone data in "zoneadm list -p" (parseable) format.
###############################################################################
lulib_list_branded_zones()
{
    list_zones_flags=
    case "$1" in
	-*)
	    list_zones_flags="$list_zones_flags $1"
	    shift
	    ;;
    esac
    list_zones_rootdir="$1"
    if [ -z "$1" ]; then
	list_zones_rootdir=/
    fi
    if [ -r "$list_zones_rootdir/etc/zones/index" ]; then
	# Filter the output of zoneadm and fill in a blank uuid
	# field with a dash so that read parses out the line correctly
	zoneadm -R "$list_zones_rootdir" list $list_zones_flags -p |
	sed 's/\([^\]\)::/\1:-:/' |
	while IFS=: read zoneid zonename state path uuid zonebrand junk; do
	    # if zonebrand is blank, it means brands are not
	    # supported, set it to native
	    [ -z "$zonebrand" ] && zonebrand=native
	    [ $zonebrand != native -a $zonebrand != cluster ] &&
	      zoneadm -R "$list_zones_rootdir" -z $zonename list -p
	done
    fi
}

###############################################################################
# Name:		lulib_list_nonshared_branded_zones
# Description:	Get a parseable list of the branded zones installed in a given
#		boot environment with root on filesystem not shared between BEs.
# Arguments:	[flags] <be-root> <pbe_icf> <abe_icf>
#		Flags are those accepted for "zoneadm list"; documented as
#		[list_options] in zoneadm(1M).  The expected options here are
#		"-i", "-c" or no option at all.
#		<be_root> is the path to the boot environment root.
#               <pbe_icf> is path to source BE ICF file 
#               <abe_icf> is path to alternate BE ICF file 
# Returns:	None
# Outputs:	List zone data in "zoneadm list -p" (parseable) format.
###############################################################################
lulib_list_nonshared_branded_zones()
{
    list_zones_flags=
    case "$1" in
	-*)
	    list_zones_flags="$list_zones_flags $1"
	    shift
	    ;;
    esac
    list_zones_rootdir="$1"
    if [ -z "$1" ]; then
	list_zones_rootdir=/
    fi

    pbe_icf="$2"
    abe_icf="$3"

    SAVEIFS_NBZ="$IFS"

    # Parsing list of branded zones which are in
    # state "running" or "ready"
    lulib_list_branded_zones $list_zones_flags $list_zones_rootdir |
    while IFS=: read zoneid zonename state path junk; do
	IFS="$SAVEIFS_NBZ"

	# get mountpoint for zone root filesystem
	zone_mp=`df $path | nawk '{ print $1 }'`

	# Parse list of mount points shared between
	# source and alternate BEs and compare them
	# to mountpoint of zone root filesystem
	$LUETCBIN/ludo filter_shared $pbe_icf $abe_icf |
	    egrep -s "^[^:]+:$zone_mp:"

	if [ $? -eq 0 ] ; then
	    $LUPRINTF -lp2D - "`gettext \
	      'Root of zone <%s> is on non-shared fs'`" $zonename
	    echo $zonename
	fi
    done
}

###############################################################################
# Name:		lulib_get_zone_fs
# Description:	With a given BE mount point and non-global zone name, print
#		the configured zone file systems on standard output in
#		vfstab(4) format.
# Arguments:	$1 - BE mount point.
#		$2 - zone name.
# Returns:	None
# Outputs:	zone file system list in vfstab format
###############################################################################
lulib_get_zone_fs()
{
    get_zone_fs_root="$1"
    get_zone_fs_zone="$2"

    /usr/sbin/zonecfg -R "$get_zone_fs_root" -z "$get_zone_fs_zone" info fs |
    nawk '
	function dump() {
		if (rawdev == "") {
			rawdev = "-";
		}
		if (fstype != "" && fstype != "lofs") {
			if (opts == "")
				opts = "-";
			printf "%s\t%s\t%s\t%s\t-\tyes\t%s\n", blockdev, \
			    rawdev, mntpnt, fstype, opts;
			fstype = "";
		}
	}
	$1 == "fs:"		{ dump(); }
	$1 == "dir:"		{ mntpnt = $2; }
	$1 == "special:"	{ blockdev = $2; }
	$1 == "raw:"		{ rawdev = $2; }
	$1 == "type:"		{ fstype = $2; }
	$1 == "options:"	{ gsub(/^\[|\]$/,"", $2); opts = $2 }
	END { dump(); }
	'
}

###############################################################################
# Name:		lulib_get_zone_icffs
# Description:	With a given ICF file and zone name, print the configured zone
#		file systems on standard output in vfstab(4) format.
# Arguments:	$1 - ICF file
#		$2 - zone name.
# Returns:	None
# Outputs:	zone file system list in vfstab format
###############################################################################
lulib_get_zone_icffs()
{
    get_zone_icffs_icf="$1"
    get_zone_icffs_zone="$2"

    if [ "$get_zone_icffs_zone" = global ]; then
	get_zone_icffs_zone=
    fi

    (
    while IFS=: read bename mntpnt blockdev fstype size zonename junk; do
	IFS=" 	
"
	if [ "$zonename" = "$get_zone_icffs_zone" ]; then
	    if [ "$fstype" = lofs ]; then
		rawdev=-
	    else
		rawdev=`echo "$blockdev" | sed -e '/^\/dev\//s:/dsk/:/rdsk/:'`
		if [ "$rawdev" = "$blockdev" ]; then
		    rawdev=-
		fi
	    fi
	    echo "$blockdev	$rawdev	$mntpnt	$fstype	-	yes	-"
	fi
    done < "$get_zone_icffs_icf"
    )
}

###############################################################################
# Name:		lulib_update_vfstab
# Description:	Update the dataset name in the vfstab entry of a BE.
# Arguments:	$1 - BE mount point.
#		$2 - old dataset name in vfstab which needs updating
#		$3 - new dataset name to which it needs to be updated
#		$4 - new mount point
# Returns:	None
# Outputs:	None
###############################################################################
lulib_update_vfstab()
{
	be_mntpt=$1
	olddataset=$2
	newdataset=$3
	newmountpt=$4

	vfstab_path="${be_mntpt}/etc/vfstab"
	tmp_vfstab="/tmp/.upd.vfstab.$$"
	touch $tmp_vfstab

        nawk -v DEV1="$olddataset" -v DEV2="$newdataset" \
	    -v MNT="$newmountpt" \
            'BEGIN {
	            found=0;
	     }

            $0 ~ "^#" {
	            print; next;
	    }

            {
	        if ($1 == DEV1) {
                     print DEV2,$2,MNT,$4,$5,$6,$7;
                     found=1;
	        }
                else {
	            print;
	        }
	    }

            END {
	        if (found==1) {
	            exit 0;
	        }
                else {
	            exit 1;
	        }
            }'  "$vfstab_path" >"$tmp_vfstab"

	mv ${tmp_vfstab} ${vfstab_path}
} 
		
	    
##############################################################################
# Name:		lulib_change_zone_paths
# Description:	Scan through the zones on the indicated BE.  Find the renamed
#		zone paths, and update them to the new suffix.
# Arguments:	$1 - BE mount point.
#		$2 - zone path suffix
# Returns:	None
# Outputs:	None
###############################################################################
lulib_change_zone_paths()
{
	change_zone_paths_root="$1"
	change_zone_paths_suffix="$2"

	(
	if [ -n "$change_zone_paths_suffix" ]; then
		newsuffix="-$2"
		ZFSBE="$2"
	else
		newsuffix=
		ZFSBE="`lulib_lucurr`"
	fi

	[ -x /sbin/zfs ] && \
	    /sbin/zfs list -Ho name,zpdata:rbe,zpdata:zn -t filesystem |
	    nawk -v BE="$ZFSBE" '$2 == BE {print $3 ":" $1}' > /tmp/.czpaths.$$

	SAVEIFS="$IFS"
	lulib_list_zones -c "$change_zone_paths_root" |
	while IFS=: read zoneid zonename state path uuid junk; do
		IFS="$SAVEIFS"
		if [ "$zonename" = global ]; then
			continue
		fi
		oldsuffix=
		olddataset=

		if [ -s /tmp/.czpaths.$$ ]; then
			olddataset=`grep "^${zonename}:" /tmp/.czpaths.$$ |
			    cut -d: -f2-`
		fi

		if [ -n "$olddataset" ]; then
			mount_prop=`/sbin/zfs get -Ho value mountpoint "$olddataset"`

			if [ "$change_zone_paths_root" = "/" -a \
			    -z "$newsuffix" ]; then
			    ###################################################
			    # BE is starting for the first time.  We need to
			    # ensure the dataset is mounted before the zones
			    # try to start up, and also ensure that the dataset
			    # gets mounted every subsequent reboot.
			    ###################################################

			    if [ "$state" = running ]; then
				zoneadm -z $zonename halt
			    elif [ "$state" = mounted ]; then
				zoneadm -z $zonename unmount
			    fi

			    cmx=`/sbin/zfs get -Ho value canmount "$olddataset"`
			    [ $? != 0 ] && continue
			    if [ $mount_prop = "legacy" ]; then
				lulib_dataset_mounted "$olddataset"
			        if [ $? -eq 0 ]; then
			            /sbin/mount -F zfs "$olddataset" "$path"
			            [ $? != 0 ]	 && continue
			        fi
			    elif [ "$cmx" = "off" ]; then
				/sbin/zfs set canmount=on "$olddataset"
				[ $? != 0 ] && continue
				/sbin/zfs mount "$olddataset"
				[ $? != 0 ] && continue
			    elif [ "$cmx" = "noauto" ]; then
				/sbin/zfs mount "$olddataset"
				# no error check here, as dataset may already
				# be mounted
			    fi

			    if [ -f "$path/lu_moved" ]; then
				oldsuffix=`cat "$path/lu_moved"`
			    fi
		 	    if [ $mount_prop = "legacy" ]; then
			        /sbin/umount -f "$path"
			    else
			        /sbin/zfs unmount -f "$path"
			    fi
			    [ $? != 0 ] && continue

			    newpath=`echo $path | sed "s/-$oldsuffix"'$//'`
			    newdataset=`echo $olddataset | \
				sed "s/-$oldsuffix"'$//'`

			    # if a dataset already exists in the wrong 
			    # location, move it out of the way
			    prevbe=`zfs list -Ho zpdata:rbe "$newdataset"`
			    if [ -n "$prevbe" -a "$prevbe" != "$ZFSBE" ]; then
				#get the root device for prev be
				prevbe_root=`${LUETCBIN}/ludo get_root_slice_from_be_name "$prevbe"`
				[ -z "$prevbe_root" ] && continue
				
				prevpt=`zfs list -Ho mountpoint "$newdataset"`
				[ $? != 0 ] && continue
				/sbin/zfs set canmount=off "$newdataset"
				[ $? != 0 ] && continue
				if [ $prevpt != "legacy" ] ; then
				    /sbin/zfs set mountpoint="$prevpt-$prevbe" "$newdataset"
				fi
				[ $? != 0 ] && continue
				/sbin/zfs rename "$newdataset" "$newdataset-$prevbe"
				[ $? != 0 ] && continue
		 	        if [ $mount_prop = "legacy" ] ; then
				    #in this case we need to update vfstab entry for the renamed dataset.
				    #get mount point of root device for prev BE, if already mounted
				    prevbe_mntpt=`nawk -v DEV="$prevbe_root" '$1==DEV {print $2}' < /etc/mnttab`
				    if [ -z "$prevbe_mntpt" ] ; then
				        prevbe_mntpt="/tmp/prevbe.mnt.$$"
				        /usr/bin/mkdir ${prevbe_mntpt}
					lulib_mount_pathname "$prevbe_root" "$prevbe_mntpt"
				        [ $? != 0 ] && continue
					prevbe_mounted_now="yes"
				    fi
				    ds_mountpt=`/usr/bin/nawk -v DEV="$newdataset" '$1==DEV {print $3}' < ${prevbe_mntpt}/etc/vfstab`
				    lulib_update_vfstab "${prevbe_mntpt}" "${newdataset}" "${newdataset}-${prevbe}" \
				        "${ds_mountpt}-${prevbe}"
				    if [ $prevbe_mounted_now = "yes" ] ; then
				        lulib_unmount_pathname "${prevbe_root}"
					rm -f ${prevbe_mntpt}
				    fi
				fi
			    fi
			    /sbin/zfs rename "$olddataset" "$newdataset"
			    [ $? != 0 ] && continue
		 	    if [ $mount_prop = "legacy" ] ; then
				lulib_update_vfstab "/" "$olddataset" "$newdataset" "$newpath"
			    fi

			    if [ -d "$path" ]; then
				chmod 700 "$path"
			    else
				mkdir -pm 700 "$path"
			    fi
			    [ -d "$newpath" ] && rmdir "$newpath"
			    [ -d "$newpath" ] && continue # rmdir failed
			    zoneadm -z $zonename move "$newpath"
			    rmdir "$newpath"

			    # set up the mountpoint, and mount it
			    /usr/bin/mkdir -p "$newpath"	
			    lulib_mount_pathname "$newdataset" "$newpath"
			    [ $? -ne 0 ] && continue

			    # zone directories must be -rwx------
			    /usr/bin/chmod 700 "$newpath"

			    rm -f "$newpath/lu_moved"

			elif [ "$change_zone_paths_root" != "/" ]; then
			    ###################################################
			    # Previous BE was not shut down properly, so
			    # we need to clean it up.  In particular, we need
			    # to unmount the dataset for the previous BE's
			    # zone, and we ensure it isn't remounted on
			    # subsequent reboots.
			    ###################################################

                            cmx=`/sbin/zfs list -Ho canmount "$olddataset"`
                            loc=`/sbin/zfs list -Ho mountpoint "$olddataset"`
                            mounted=`/sbin/zfs get -Ho value mounted "$olddataset"`
                            if [ $loc = "legacy" ]; then
                                loc=`lulib_resolve_lofs "$change_zone_paths_root" "$path"`
                            fi
                            if [ $mounted = "no" ]; then
                               lulib_mount_pathname "$olddataset" "$loc"
                               [ $? -ne 0 ] && continue
                            fi
                            [ -f $loc/lu_moved ] && oldsuffix=`cat $loc/lu_moved"`
                            [ "$oldsuffix" = "$change_zone_paths_suffix" ] && continue
                            echo "$change_zone_paths_suffix" > "$loc"/lu_moved
                            lulib_unmount_pathname "$loc"
                            [ $? != 0 ] && continue
                            if [ "$cmx" = "on" ]; then
                                /sbin/zfs set canmount=off "$olddataset"
                            fi

                            # by changing the mountpoint, we ensure that
                            # there's no name collision when the zone
                            # is mounted as an ABE
                            newpath=`echo $path |
                                sed "s/-$oldsuffix"'$//;s/$/'"$newsuffix/"`

                            # see if the old dataset was already moved
                            tmpds=`echo $olddataset | sed "s/$newsuffix"'$//'`
                            if [ "$tmpds" = "$olddataset" ]; then
			        #if the zone dataset is at the top of a pool,
			        #we don't rename it
			        echo $olddataset | grep "/" > /dev/null
			        if [ $? -ne 0 ]; then
			            newdataset="$olddataset"
			        else	
                                    newdataset=`echo $olddataset |
                                        sed "s/-$oldsuffix"'$//;s/$/'"$newsuffix/"`
			        fi	
                                if [ $mount_prop != "legacy" ] ; then
                                    /sbin/zfs set mountpoint="$newpath" "$olddataset"
                                    [ $? != 0 ] && continue
                                fi
                                /sbin/zfs rename "$olddataset" "$newdataset"
                                [ $? != 0 ] && continue
                                if [ $mount_prop = "legacy" ] ; then
                                    newmountpt=`echo "$newpath" |
                                        sed "s:^${change_zone_paths_root}/:/:"`
                                    lulib_update_vfstab "$change_zone_paths_root" \
                                        "$olddataset" "$newdataset" "$newmountpt"

                                    newrawpath=`lulib_resolve_lofs "$change_zone_paths_root" "$newpath"`
                                    /usr/bin/mkdir -pm 700 $newrawpath
                                    /usr/bin/rmdir $loc
                                fi
                            fi
                            zonecfg -R "$change_zone_paths_root" \
                                -z "$zonename" set -F zonepath="$newpath"

			else
			    ###################################################
			    # BE is shutting down.  We need to shut down the
			    # zone, unmount the dataset, and ensure that
			    # the dataset will not automatically be mounted
			    # again on a restart.
			    ###################################################

			    if [ "$state" = running ]; then
				zoneadm -z $zonename halt
			    elif [ "$state" = mounted ]; then
				zoneadm -z $zonename unmount
			    fi
			    if [ -n "$change_zone_paths_suffix" ]; then
				echo "$change_zone_paths_suffix" > "$path/lu_moved"
			    fi

			    # Now we need to do a little dance in order to
			    # rewrite the zone path.  A simple 'zoneadm move'
			    # command won't work, as the mountpoint is
			    # managed by zfs and a behind-the-scenes 'mv'
			    # command won't do the trick.
			    cmx=`/sbin/zfs get -Ho value canmount "$olddataset"`
			    if [ "$cmx" = "on" ]; then
				/sbin/zfs set canmount=off "$olddataset"
				[ $? != 0 ] && continue
			    elif [ "$cmx" = "noauto" ]; then
				lulib_unmount_pathname "$olddataset"
				[ $? != 0 ] && continue
			    fi
			    newpath="$path$newsuffix"

			    #If the zone dataset is at the top of a pool,
			    #we don't rename it
			    echo $olddataset | grep "/" > /dev/null
			    if [ $? -ne 0 ]; then
			        newdataset="$olddataset"
			    else	
			        newdataset="$olddataset$newsuffix"
			    fi

			    zfs rename "$olddataset" "$newdataset"
			    [ $? != 0 ] && continue
			    if [ $mount_prop = "legacy" ] ; then
			        lulib_update_vfstab "/" "$olddataset" "$newdataset" "$newpath"
			    else
			        zfs set mountpoint="$newpath" "$newdataset"
			    fi
			    [ $? != 0 ] && continue
			    if [ -d "$path" ]; then
				chmod 700 "$path"
			    else
			        mkdir -pm 700 "$path"
			    fi
			    [ -d "$newpath" ] && rmdir "$newpath"
			    [ -d "$newpath" ] && continue # rmdir failed
			    zoneadm -z $zonename move "$newpath"
			    rmdir "$newpath"
			    if [ $mount_prop = "legacy" ]; then
				/usr/bin/mkdir -pm 700 "$newpath"
			    fi
			fi

			# that's all we need to do
			continue
		fi

		if [ -f "$path/lu_moved" ]; then
			oldsuffix=`cat "$path/lu_moved"`
		elif [ "$change_zone_paths_root" = / ]; then
			# If we're looking at the PBE, then check if the zone
			# path is a mount point.  Assume unshared if it is.
			mountpt=`df -k $path | nawk '
			    { mnt=$NF } END { print mnt }'`
			[ "$mountpt" = "$path" ] && continue
		else
			# If we're looking at an ABE, then rename if the path
			# isn't writable (meaning that it's shared).
			lulib_path_writable "$path" && continue
		fi
		if [ "$oldsuffix" = "$change_zone_paths_suffix" ]; then
			continue
		fi
		rawpath=`lulib_resolve_lofs "$change_zone_paths_root" "$path"`
		newpath=`echo $path | \
		    sed "s/-$oldsuffix"'$//;s/$/'"$newsuffix/"`
		newrawpath=`echo $rawpath | \
		    sed "s/-$oldsuffix"'$//;s/$/'"$newsuffix/"`
		if [ -d "$newrawpath" ]; then
			$LUPRINTF -Eelp2 "`gettext \
			    'unable to move zone <%s>; <%s> exists'`" \
			    $zonename "$newrawpath"
			continue
		fi
		if [ "$change_zone_paths_root" = / ]; then
			if [ "$state" = running ]; then
				zoneadm -z $zonename halt
			elif [ "$state" = mounted ]; then
				zoneadm -z $zonename unmount
			fi
			zoneadm -z $zonename move "$newpath"
		else
			mv $rawpath $newrawpath
			zonecfg -R "$change_zone_paths_root" -z $zonename \
			    set -F zonepath="$newpath"
		fi
		# If we're renaming back to normal, then remove the lu_moved
		# file, because it's not moved.  Otherwise, add the file both
		# as a flag and as a record of the suffix used.
		if [ -n "$change_zone_paths_suffix" ]; then
			echo "$change_zone_paths_suffix" > \
			    "$newrawpath/lu_moved"
		else
			rm -f "$newrawpath/lu_moved"
		fi
	done
	rm -f /tmp/.czpaths.$$
	)

	# When the suffix is empty, we're activating the zones for the running
	# system.  This means that we should remove the lu_suffix file, because
	# our zones are no longer renamed here.
	if [ -n "$change_zone_paths_suffix" ]; then
		echo "$change_zone_paths_suffix" > \
		    "$change_zone_paths_root/etc/zones/lu_suffix"
	else
		rm -f "$change_zone_paths_root/etc/zones/lu_suffix"
	fi
}

###############################################################################
# Name:		lulib_resolve_lofs
# Description:	Climb up a chain of nested lofs mounts to reach past a
#		specified root directory.  This is used to create read-write
#		access to unshared subdirectories within an otherwise shared
#		file system.  (It's similar in operation to the internal
#		zoneadmd function of the same name.)
# Arguments:	$1 - root reference directory; usually ABE mount point.
#		$2 - path to resolve; usually zone path.
# Returns:	None
# Outputs:	new (modified) path on standard output.
###############################################################################
lulib_resolve_lofs()
{
    resolve_lofs_root="$1"
    resolve_lofs_path="$2"

    (
	echo "$resolve_lofs_path"
	/usr/sbin/mount -p | /usr/bin/sort -r -k 3,3 -t' ' |
	while read special raw mountpoint fstype fsckpass atboot mountopt more
	do
	    if [ -n $mountpoint -a $fstype = lofs -a \
		`expr "$resolve_lofs_path/" : $mountpoint/` -gt 0 ]; then
		resolve_lofs_path="`echo \"$resolve_lofs_path\" |
		    sed \"s|^$mountpoint|$special|\"`"
		echo "$resolve_lofs_path"
		if [ `expr "$resolve_lofs_path/" : "$resolve_lofs_root/"` -eq \
		    0 ]; then
		    break
		fi
	    fi
	done
    ) | /usr/bin/tail -1
}

###############################################################################
# Name:		lulib_is_subdir
# Description:	Assuming a given path represents a directory (that exists or
#		is yet to be created), determine if it is or would be a
#		subdirectory of a given parent.
# Arguments:	$1 - parent
#		$2 - path to test
# Returns:	0 (true) - path given is subdirectory of parent
#		1 (false) - path given is not a subdirectory
###############################################################################
lulib_is_subdir()
{

    subdir=`echo $1|sed 's:[/]*$:/:'`
    parent=`echo $2|sed 's:[/]*$:/:'`
    # work around known expr flaw
    [ -z "$parent" -o "$parent" = / ] && return 0
    [ "$subdir" = / ] && return 1
    [ `/bin/expr "$subdir" : "$parent"` -gt 0 ]
}

###############################################################################
# Name:		lulib_subdir_list
# Description:	Check if a given directory is (or would be) a subdirectory of
#		any element on a list.
# Arguments:	$1 - path to test
#		$2...$N - parent(s)
# Returns:	0 (true) - path given is subdirectory of some parent
#		1 (false) - path given is not a subdirectory of any parent
###############################################################################
# Check if a given directory is a subdirectory of any element in a list.
lulib_subdir_list()
{
    subdir_list_dir="$1"
    shift
    for subdir_list_element
    do
	if lulib_is_subdir "$subdir_list_dir" $subdir_list_element; then
	    return 0
	fi
    done
    return 1
}

#################################################################################################
# Name:		lulib_fix_name
# Description:	Change any characters special to egrep and awk, so that
#		the string can be safely grepped (egrep) and changed (awk)
#	        For example, awk chokes if the pattern contains unescaped
#	        parenthesis
# Local Prefix:	lcs
# Arguments:	$1 - string to be changed
# Returns:	0 - Successfully processed string
#		1 - An error occurred
# Outputs:	Changed string on STDOUT
#################################################################################################

lulib_fix_name()
{
   lcs_str="$1"
   if [ -z "$lcs_str" ]; then
      echo ""
      return 1
   fi

   #
   # NOTE: sed doesn't support the + metacharacter
   #
   echo "$lcs_str" | /bin/sed 's:\([^a-zA-Z0-9]\):\\\1:g'

   return 0
}

#################################################################################################
# Name:		lulib_get_logical_boot_slice
# Description:	Given a physical slice, finds the metadevice/mirror that encapsulates it.
# Local Prefix:	GLB
# Arguments:	$1 - the physical slice
# Returns:	Sets the variable LU_BOOT_LOGICAL.
#		Returns 0 on success, 1 on failure
#################################################################################################

lulib_get_logical_boot_slice()
{
  GLB_TMP="/tmp/.lulib.glb.1.$$"

  LU_BOOT_LOGICAL=""

  if [ "${LU_SYSTEM_ARCH}" != "i386" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_get_logical_boot_slice() only supported on x86 '`"
     return 1
  fi

  if [ "$#" -ne 1 -o -z "$1" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_get_logical_boot_slice <phys-slice>'`"
     return 1
  fi

  boot_raw_slice="$1"
  ${LUPRINTF} -lp2D - "`gettext 'Physical boot slice is: <%s>'`" "$boot_raw_slice"

  lulib_discover_sds_installation
  if [ -z "${SDS_FOUND}" ]; then
     ${LUPRINTF} -lp2D - "`gettext 'SVM is not configured'`"
     ${LUPRINTF} -lp2D - "`gettext 'Logical slice = physical slice'`"
     LU_BOOT_LOGICAL="$boot_raw_slice"
     return 0
  fi

  ${SDS_METASTAT} -p > "$GLB_TMP"
  if [ "$?" -ne 0 ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Cannot run: <%s>'`" "${SDS_METASTAT}"
     /bin/rm -f "$GLB_TMP"
     return 1
  fi

  # 
  # we need not parse boot_raw_slice, since the
  # component of a metadevice is of the form
  # /dev/rdsk/c?t?d?s?
  #

  if [ -z "$boot_raw_slice" ]; then
        ${LUPRINTF} -Eelp2 "`gettext 'Boot slice: cannot be determined.'`"
        /bin/rm -f "$GLB_TMP"
        return 1
  fi
  ctd=`/bin/echo "$boot_raw_slice" | /bin/sed 's:/dev/rdsk/::g'`
  if [ -z "$ctd" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Cannot parse: <%s>'`" "${boot_raw_slice}"
     /bin/rm -f "$GLB_TMP"
     return 1
  fi

 # Check if component of a metadevice
  metadev=`/bin/nawk -v phys="$boot_raw_slice" ' {if ($4 == phys) {printf("%s\n", $1);exit 12;}}' "$GLB_TMP"`
  if [ "$?" -ne 12 ]; then
     ${LUPRINTF} -lp2D - "`gettext 'Not a metadevice: <%s>'`" "$boot_raw_slice"
     LU_BOOT_LOGICAL="$boot_raw_slice"
     /bin/rm -f "$GLB_TMP"
     return 0
  elif [ -z "$metadev" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Cannot find metadevice for <%s>'`" "$ctd" 
     /bin/rm -f "$GLB_TMP"
     return 1
  fi
  
  ${LUPRINTF} -lp2D - "`gettext 'Is a metadevice: <%s>'`" "$metadev"
 
  #
  # Check if component of a mirror
  # SVM supports a maximum of 4 way mirror
  #
  mirror=`/bin/nawk -v meta="/dev/md/rdsk/$metadev" ' { if ( $3 == meta || $4 == meta || $5 == meta || $6 == meta ) {printf("%s\n", $1); exit 13;}}' "$GLB_TMP"`
  mir_ret="$?"

  /bin/rm -f "$GLB_TMP"

  if [ "$mir_ret" -ne 13 ]; then
     ${LUPRINTF} -lp2D - "`gettext 'Not a mirror: <%s>'`" "$boot_raw_slice"
     LU_BOOT_LOGICAL="${SDS_DEVROOT}/rdsk/${metadev}"
     ${LUPRINTF} -lp2D - "`gettext 'Logical slice is: <%s>'`" "$LU_BOOT_LOGICAL"
     return 0
  elif [ -z "$mirror" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Cannot find mirror for <%s>'`" "$metadev" 
     return 1
  fi
  ${LUPRINTF} -lp2D - "`gettext 'Is a mirror: <%s>'`" "$mirror"

  LU_BOOT_LOGICAL="${SDS_DEVROOT}/rdsk/${mirror}"
  ${LUPRINTF} -lp2D - "`gettext 'Logical slice is: <%s>'`" "$LU_BOOT_LOGICAL"
  return 0
}

#################################################################################################
# Name:		lulib_devices_to_dev_dsk
# Description:	Translates a char/block /devices name to a char/block /dev/[r]dsk name
# Local Prefix:	ludd
# Arguments:   
#	 	$1 - A /devices pathname
#		$2 - The name of the results file
#
# NOTE:		Works only with /dev/dsk and /dev/rdsk names.
#		Does *not* work with fdisk slices i.e. c-t-d-pN
#
# Returns:	The corresponding /dev name in the results file
#		0 on success
#		1 on failure
#################################################################################################
lulib_devices_to_dev_dsk()
{
    if [ "${LU_SYSTEM_ARCH}" != "i386" ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'lulib_devices_to_dev_dsk() only supported on x86'`"
       return 1
    fi

    if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_devices_to_dev_dsk(): Invalid arguments'`"
       return 1
    fi

    ludd_devices="$1"
    ludd_resFile="$2"

    /bin/rm -f "$ludd_resFile"

    /bin/echo "$ludd_devices" | /bin/egrep "^/devices/" > /dev/null 2>&1
    if [ "$?" -ne 0 ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'Invalid /devices pathname <%s>'`" "$ludd_devices"
       return 1
    fi

    if [ -b "$ludd_devices" ]; then
       ludd_disk=`/bin/echo "$ludd_devices" | /bin/sed 's/\(.*\):.$/\1/g'`
       ludd_slchar=`/bin/echo "$ludd_devices" | /bin/sed 's/.*:\(.\)$/\1/g'`
       ludd_devices_p0="../..${ludd_disk}:q"
       ludd_blk="yes"
    elif [ -c "$ludd_devices" ]; then
       ludd_disk=`/bin/echo "$ludd_devices" | /bin/sed 's/\(.*\):.,raw$/\1/g'`
       ludd_slchar=`/bin/echo "$ludd_devices" | /bin/sed 's/.*:\(.\),raw$/\1/g'`
       ludd_devices_p0="../..${ludd_disk}:q,raw"
       ludd_blk=""
    else
       ${LUPRINTF} -Eelp2 "`gettext 'Neither char nor block device: <%s>'`" "$ludd_devices"
       return 1
    fi

    ludd_slnum=""
    case "$ludd_slchar" in
	   a) ludd_slnum=0;;
	   b) ludd_slnum=1;;
	   c) ludd_slnum=2;;
	   d) ludd_slnum=3;;
	   e) ludd_slnum=4;;
	   f) ludd_slnum=5;;
	   g) ludd_slnum=6;;
	   h) ludd_slnum=7;;
	   i) ludd_slnum=8;;
	   j) ludd_slnum=9;;
    esac

    if [ -n "$ludd_blk" ]; then
       ludd_dev_p0=`/bin/ls -l /dev/dsk/*p0 | /bin/nawk -v dev="$ludd_devices_p0" '{ if ($11 == dev) {printf("%s\n", $9); exit 12;}}'`
    else
       ludd_dev_p0=`/bin/ls -l /dev/rdsk/*p0 | /bin/nawk -v dev="$ludd_devices_p0" '{ if ($11 == dev) {printf("%s\n", $9); exit 12;}}'`
    fi
    if [ "$?" -eq 12 -a -n "$ludd_dev_p0" -a -n "$ludd_slnum" ]; then
       /bin/echo "$ludd_dev_p0" | /bin/sed "s/p0$/s${ludd_slnum}/g" > "$ludd_resFile"
       ret=0
    else
       ${LUPRINTF} -Eelp2 "`gettext 'Cannot derive /dev/[r]dsk name <%s>'`" "$ludd_devices"
       ret=1
    fi

    return "$ret"
}

# Given a boot partition in c-t-d-p0:boot form,
# get the real partition number c-t-d-p<N> where <N> is between
# 1 and 4.
# This routine only accepts a char device
# It is a part of lulib and may not be called during OOS
#
# Arguments:
#	$1 - A char boot partition in c-t-d-p0:boot format
#	$2 - The name of a results file
# Returns:
#	The actual fdisk boot partition in the results file
#	0 on success
#	1 on failure
#
lulib_get_real_boot_partition()
{
   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
	${LUPRINTF} -Eelp2 "`gettext 'lulib_get_real_boot_partition(): invalid arguments'`"
	return 1
   fi

   gbp_p0Boot="$1"
   gbp_resFile="$2"

   gbp_tmp1="/tmp/.lulib.gbp.1.$$"
   gbp_tmp2="/tmp/.lulib.gbp.2.$$"

   /bin/rm -f "$gbp_tmp1" "$gbp_tmp2" "$gbp_resFile"


   /bin/echo "$gbp_p0Boot" | /bin/egrep "p0:boot$" > /dev/null 2>&1
   if [ "$?" -ne 0 ]; then
	${LUPRINTF} -Eelp2 "`gettext 'Not a boot partition name: <%s>'`" "${gbp_p0Boot}"
	return 1
   fi

   #
   # Translate /dev/rdsk/c-t-d-p0:boot to p0
   #
   gbp_p0=`/bin/echo "$gbp_p0Boot" | /bin/sed 's/p0:boot$/p0/g'`
   if [ -z "$gbp_p0" -o ! -c "$gbp_p0" ]; then
	${LUPRINTF} -Eelp2 "`gettext 'No such partition or not a char device: <%s>'`" "${gbp_p0}"
	return 1
   fi

   /usr/sbin/fdisk -W "$gbp_tmp1" "$gbp_p0" > /dev/null 2>&1
   /usr/bin/grep -v \* "$gbp_tmp1" | /usr/bin/grep -v '^[ 	]*$' > "$gbp_tmp2"
   #
   # Note: while executed in a subshell
   #
   /bin/rm -f "$gbp_tmp1"
   num=1
   while read id act bhead bcycl ehead ecycl rsect numsect
   do
	if [ -z "$id" ]; then
	   continue
	fi

        if [ "$id" -eq 190 ]; then
	   /bin/echo "$num" > "$gbp_tmp1" 
	   break;
	fi
	num=`/bin/expr "$num" + 1`

   done < "$gbp_tmp2"

   if [ -f "$gbp_tmp1" -a -s "$gbp_tmp1" ]; then
      part=`/usr/bin/cat "$gbp_tmp1"`
      if [ "$part" -lt 1 -o "$part" -gt 4 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'partition number derived is invalid: <%s>'`" "${part}"
         retval=1
      else
         disk=`/bin/echo "$gbp_p0" | /bin/sed 's/p0$//g'`
         echo "${disk}p${part}" > "$gbp_resFile"
         retval=0
      fi
     
   else
      ${LUPRINTF} -Eelp2 "`gettext 'No Solaris boot partition on device: <%s>'`" "${gbp_p0}"
      retval=1
   fi

   /bin/rm -f "$gbp_tmp1"
   /bin/rm -f "$gbp_tmp2"

   return "$retval"
}

#
# Given a BE name, delete the corresponding entry from the GRUB
# menu. Also adjust the default setting in the menu if required.
# It is a part of lulib and may not be called during OOS
#
# Arguments:
#	$1 - A BE name
# Returns:
#	0 on success
#	1 on failure
#
# Local Prefix:  ldme
#
lulib_delete_menu_entry()
{

   if [ "$#" -lt 1 -o -z "$1" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'lulib_delete_menu_entry(): invalid arguments'`"
      return 1
   fi

   BE_NAME="$1"

   if [ "${LU_SYSTEM_ARCH}" = sparc -a -x /sbin/zpool ]; then
	if [ "$#" -ne 2 -o -z "$2" ]; then
           ${LUPRINTF} -Eelp2 "`gettext 'lulib_delete_menu_entry(): invalid arguments'`"
	   return 1
	fi
        ICF_ID="$2"
	rdataset=`lulib_get_root_dataset_from_icf "/etc/lu/ICF.$ICF_ID"`
	rpool="`echo $rdataset | cut -d/ -f1`"
	if [ -z "$rpool" ]; then
		# not a pool, nothing to do
		return 0
	fi
	/sbin/zpool list -H "$rpool" > /dev/null 2>&1
	if [ "$?" -eq "0" ]; then
		old=/$rpool/boot/menu.lst
		new=/$rpool/boot/menu.new
		# found the boot pool for the ABE.  Update the menu.lst
		if [ -f "$old" ]; then
			nawk -v BE="$BE_NAME" -v DS="$rdataset" \
			    '{ if (!(/^title / && $2 == BE) &&
			           !(/^bootfs / && $2 == DS)) { print }
			     }' < "$old" > "$new"
			rm -f "$old"
			mv "$new" "$old"
		fi
	fi
	return 0
   fi

   ldme_tmp="/tmp/.lulib.ldme.tmp.$$"
   ldme_menu="/tmp/.lulib.ldme.menu.$$"
   ldme_state="/tmp/.lulib.ldme.state.$$"

   /bin/rm -f "$ldme_tmp"
   /bin/rm -f "$ldme_menu"
   /bin/rm -f "$ldme_state"

   if [ "${LU_SYSTEM_ARCH}" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'lulib_delete_menu_entry(): only supported on x86 systems'`"
      return 1
   fi

   if [ -f "$GRUB_slice" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'lulib_delete_menu_entry(): Internal error: GRUB slice file still present'`"
      return 1
   fi

   # With the new multi-menu model, the same GRUB menu should be in every ZFS BE
   # Just copy it from the current BE
   ZFS_BE=""
   lulib_copy_from_top_dataset `/usr/sbin/lucurr` "$ldme_menu" "/${BOOT_MENU}"
   ret="$?"
   if [ "$ret" -eq 1 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to copy file <%s> from top level dataset for current BE <%s>'`" "/${BOOT_MENU}" `/usr/sbin/lucurr`
      return 1
   elif [ "$ret" -eq 0 ]; then
      ZFS_BE=yes
   else
      # UFS. On DCA BEs it is normal for GRUB menu to be absent
      if [ ! -f "/${BOOT_MENU}" -o ! -s "/${BOOT_MENU}" ]; then
         ${LUPRINTF} -lp1 "`gettext 'Skipping menu entry delete: Non existent GRUB menu <%s>'`" "/${BOOT_MENU}"
         return 0
      fi

      /bin/cp -p "/${BOOT_MENU}" "$ldme_menu"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Cannot copy UFS GRUB menu <%s>'`" "/${BOOT_MENU}"
         return 1
      fi
   fi

   BE_FIXED=`lulib_fix_name $BE_NAME`
   ldme_hdr="${BOOT_MENU_PREFIX}${BE_FIXED}${BOOT_MENU_HDR_SUFFIX}"
   ldme_ftr="${BOOT_MENU_PREFIX}${BE_FIXED}${BOOT_MENU_FTR_SUFFIX}"

   /usr/bin/grep "$ldme_hdr" "$ldme_menu" > /dev/null 2>&1
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -lp1 "`gettext 'No entry for BE <%s> in GRUB menu'`" "${BE_NAME}"
      return 0
   fi

   ${LUPRINTF} -lp1 "`gettext 'Updating GRUB menu default setting'`"

   lulib_save_default "$ldme_menu" "$ldme_state"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot save default. Cannot delete menu entry from <%s>'`" "${ldme_menu}"
      /bin/rm -f "$ldme_tmp"
      /bin/rm -f "$ldme_menu"
      /bin/rm -f "$ldme_state"
      return 1
   fi
     
   #
   # All special characters in the LU entry header were escaped
   # above (via lulib_fix_name()).
   # This is so that awk doesn't choke on the pattern below
   #
   /bin/rm -f "$ldme_tmp"
   /bin/cp -p "$ldme_menu" "$ldme_tmp"

   start=`/usr/bin/awk "/^$ldme_hdr\$/ { print NR }" "$ldme_tmp"`
   if [ -z "$start" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot delete menu entry from <%s>'`" "${ldme_menu}"
      /bin/rm -f "$ldme_tmp"
      /bin/rm -f "$ldme_menu"
      /bin/rm -f "$ldme_state"
      return 1
   fi

   stop=`/usr/bin/awk "/^$ldme_ftr\$/ { print NR }" "$ldme_tmp"`
   if [ -z "$stop" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot delete menu entry from <%s>'`" "${ldme_menu}"
      /bin/rm -f "$ldme_tmp"
      /bin/rm -f "$ldme_menu"
      /bin/rm -f "$ldme_state"
      return 1
   fi

   #
   # Delete the menu entry for this BE 
   #
   /bin/nawk -v "hdr=$start" -v "ftr=$stop" "NR < hdr || NR > ftr {print}" "$ldme_tmp" > "$ldme_menu"

   /bin/rm -f "$ldme_tmp"

   lulib_restore_default "$ldme_menu" "$ldme_state"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot restore default. Cannot delete menu entry from <%s>'`" "/${BOOT_MENU}"
      /bin/rm -f "$ldme_menu"
      /bin/rm -f "$ldme_state"
      return 1
   fi

   /bin/rm -f "$ldme_state"

   # Copy back the menu
   if [ -z "$ZFS_BE" ]; then
      /bin/cp -p "$ldme_menu" "/${BOOT_MENU}"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Cannot save UFS GRUB menu <%s>'`" "/${BOOT_MENU}"
	 return 1
      fi
   else
      lulib_copy_to_top_dataset `/usr/sbin/lucurr` "$ldme_menu" "/${BOOT_MENU}"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Failed to copy file <%s> to top level dataset for BE <%s>'`" "/${BOOT_MENU}" "$BE_NAME"
         return 1
      fi
   fi

   /bin/rm -f "$ldme_menu"

   # For now, only on x86
   if [ "${LU_SYSTEM_ARCH}" != i386 ]; then
      return 0
   fi

   if [ -z "$LU_BIOSDEV" -o ! -f "$LU_BIOSDEV" -o ! -x "$LU_BIOSDEV" -o ! -s "$LU_BIOSDEV" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot find or is not executable: <%s>.'`" "${LU_BIOSDEV}"
      ${LUPRINTF} -Eelp2 "`gettext 'One or more patches required by Live Upgrade has not been installed.'`"
      ${LUPRINTF} -lp1 "`gettext 'Search for the technical instruction (info doc) 206844 at http://sunsolve.sun.com for the latest patch list'`"
      return 1
   fi

   #
   # Update the backup menu
   #
   /bin/cp -p "/${BOOT_MENU}" "${GRUB_backup_menu}"
   lulib_propagate_file ${GRUB_backup_menu} ""
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Unable to propagate GRUB backup menu  <%s> to all boot environments.'`" "${GRUB_backup_menu}"
      return 1
   fi

   ${LUPRINTF} -lp1 "`gettext 'Successfully deleted entry from GRUB menu'`"

   return 0
}

#
# Given a "logical" (i.e. possibly a metadevice) slice containing the
# GRUB menu, mount it (if not already mounted) and return its mountpoint.
#
# Arguments:
#	$1 - CHR "logical" GRUB slice
#	$2 - The name of the results file
# Returns:
#	In the results file a tuple containing the following:
#		- A flag indicating if a mount was performed
#       	- The mountpoint of the logical slice
#		- The filesystem type of the logical slice
#	- 0 on success
#	- 1 on failure
# Local prefix: lmlg
#
lulib_mount_logical_grub_slice()
{
    LMLG_MNTPT="/tmp/.lulib.lmlg.0.$$"
    LMLG_TMP="/tmp/.lulib.lmlg.1.$$"

    if [ "${LU_SYSTEM_ARCH}" != "i386" ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'lulib_mount_logical_grub_slice() only supported on x86 '`"
       return 1
    fi

    if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_mount_logical_grub_slice(): Invalid arguments'`"
       return 1
    fi

    lmlg_resFile="$2"

    /bin/rm -f "$lmlg_resFile"

    /bin/echo "$1" | /bin/egrep "^/dev/" > /dev/null 2>&1
    if [ "$?" -ne 0 ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'lulib_mount_logical_grub_slice: argument is not a /dev path: <%s>'`" "$1"
       return 1
    fi

    #
    # Note that we cannot test for a char device directly via the
    # "test" -c operator since we may be operating on device aliases
    # like p0:boot which don't exist in the file system.
    #
    /bin/echo "$1" | /bin/grep "/rdsk/" > /dev/null 2>&1
    if [ "$?" -ne 0 ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'lulib_mount_logical_grub_slice: argument must be a char slice: <%s>'`" "$1"
       return 1
    fi

    lmlg_log_slice_chr="$1"
    lmlg_log_slice_blk=`/bin/echo "$lmlg_log_slice_chr" | /bin/sed 's/\/rdsk\//\/dsk\//g'`

    /bin/echo "$lmlg_log_slice_blk" | /bin/grep "/dsk/" > /dev/null 2>&1
    if [ "$?" -ne 0 ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'Cannot derive block slice: <%s>'`" "$lmlg_log_slice_chr"
       return 1
    fi

    lmlg_boot_real_slice=""
    /bin/echo "$lmlg_log_slice_chr" | /bin/egrep "p0:boot$" > /dev/null 2>&1
    if [ "$?" -eq 0 ]; then
       lulib_get_real_boot_partition "$lmlg_log_slice_chr" "$LMLG_TMP"
       if [ "$?" -eq 0 ]; then
          lmlg_boot_real_slice=`/bin/cat "$LMLG_TMP"`
       fi
       /bin/rm -f "$LMLG_TMP"
    else
       lmlg_boot_real_slice="$lmlg_log_slice_chr"
    fi

    if [ -z "$lmlg_boot_real_slice" ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'Cannot derive real boot partition name: <%s>'`" "$lmlg_log_slice_chr"
       return 1
    fi

    lmlg_fstype=`lulib_fstyp $lmlg_boot_real_slice`
    if [ "$?" -ne 0 -o -z "$lmlg_fstype" ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine fstype: <%s>'`" "$lmlg_boot_real_slice"
       return 1
    fi

    lmlg_mntpt=`/usr/sbin/mount | /bin/nawk -v dev=$lmlg_log_slice_blk ' { if ($3 == dev) {printf("%s\n", $1); exit 8;}}'`
    if [ "$?" -ne 8 ]; then
       lmlg_mntpt=""
       /bin/mkdir -p "$LMLG_MNTPT"
       /sbin/mount -F "$lmlg_fstype" "$lmlg_log_slice_blk" "$LMLG_MNTPT"
       if [ "$?" -ne 0 ]; then
          ${LUPRINTF} -Eelp2 "`gettext 'Cannot mount block slice: <%s>'`" "$lmlg_log_slice_blk"
          /bin/rmdir "$LMLG_MNTPT"
          return 1
       fi
       lmlg_mntpt="$LMLG_MNTPT"
       lmlg_mnted=1
     else
       lmlg_mnted=""
     fi

     /bin/echo "${lmlg_mnted}:${lmlg_mntpt}:${lmlg_fstype}" > "$lmlg_resFile"

     return 0
}

#
# Given the state returned by a call to lulib_mount_logical_grub_slice()
# unmount the GRUB slice if it was mounted() in the abovementioned call.
#
# Arguments:
#	$1 - state returned by lulib_mount_logical_grub_slice()
# Returns:
#	0 on success
#	1 on failure
# Local prefix: lumlg
#
lulib_unmount_logical_grub_slice()
{
    if [ "${LU_SYSTEM_ARCH}" != "i386" ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'lulib_unmount_logical_grub_slice() only supported on x86 '`"
       return 1
    fi

    if [ "$#" -ne 1 ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_unmount_logical_grub_slice <state>'`"
       return 1
    fi

    lumlg_state="$1"

    lumlg_mnted=`/bin/echo "$lumlg_state" | /bin/cut -d ':' -f1`
    lumlg_mntpt=`/bin/echo "$lumlg_state" | /bin/cut -d ':' -f2`

    if [ -z "$lumlg_mnted" ]; then
       return 0
    fi

    lulib_unmount_pathname "$lumlg_mntpt"
    if [ "$?" -ne 0 ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'Failed to unmount GRUB slice'`"
       return 1
    fi

    /bin/rmdir "$lumlg_mntpt"

    return 0
}

#
# Mount a device or a dataset at a specific pathname mountpoint.  If zfs,
# returns the previous value of the mountpoint.
# Args: $1 = device or dataset; $2 = mountpoint
#
lulib_mount_pathname()
{
    lmp_ret=0
    # is it a dataset?
    if [ -x /sbin/zfs ]; then
        lmp_path=`/sbin/zfs list -Ho mountpoint "$1" 2> /dev/null`
        if [ $? = 0 -a -n "$lmp_path" ]; then
            if [ $lmp_path != "legacy" ]; then
                /sbin/zfs set mountpoint="$2" "$1"
                lmp_cmx=`/sbin/zfs list -Ho canmount "$1"`
                lmp_mtd=`/sbin/zfs list -Ho mounted "$1"`
                if [ "$lmp_cmx" = "off" ]; then
                    /sbin/zfs set canmount=on "$1"
                fi
                if [ "$lmp_mtd" = "no" ]; then
                    /sbin/zfs mount "$1"
                    lmp_ret=$?
                fi
            else
                mount -F zfs "$1" "$2"
                lmp_ret=$?
            fi
            [ $lmp_ret -eq 0 ] && echo "$2"
            return $lmp_ret
        fi
    fi

    # not a dataset
    mount "$1" "$2"
    lmp_ret=$?
    [ $? -eq 0 ] && echo $2

}

#
# Unmount a pathname or a dataset; if the argument is a pathname to a zfs
# dataset, unmount the pathname via the dataset instead, in case
# canmount=noauto
#

lulib_unmount_pathname()
{
	if [ "x$1" = "x-f" ]; then
	    lup_force="-f"
	    lup_path="$2"
	else
	    lup_force=""
	    lup_path="$1"
	fi

	dataset=`lulib_get_zfs_dataset_from_mntpt "$lup_path"`
	if [ -n "$dataset" ]; then
		mountprop=`/sbin/zfs get -Ho value mountpoint "$dataset"`
		if [ $mountprop = "legacy" ] ; then
			/sbin/umount $lup_force "$lup_path"
		else
			/sbin/zfs umount $lup_force "$dataset"
		fi
	else
		/sbin/umount $lup_force "$lup_path"
	fi
}

#
# If there is an "active" Solaris fdisk partition and an inactive x86 boot
# partition make the boot partition active
#
# Arguments
#	$1 - /dev/rdsk name of x86 boot partition
#
# This function is called to determine all the slices in a ZFS pool
# given a slice in the pool. The result is returned in the result file.
#
# Arguments:
#	$1	Slice that belongs to a ZFS pool
#	$2	Name of tempfile for results
#
# Returns:
#	0	slices found
#	1	An error occurred
# Local Prefix:  lzd
#
lulib_get_zfs_devs_from_slice()
{
   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_get_zfs_devs_from_slice <ZFS slice> <temp-file-for-results>'`"
      return 1
   fi

   luzd_slice="$1"
   luzd_res="$2"

   /bin/rm -f "$luzd_res"

   # First find the pool name
   luzd_pool=`lulib_get_pool_from_slice "$luzd_slice"`
   if [ "$?" -ne 0 -o -z "$luzd_pool" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to determine pool for ZFS slice <%s>'`" "$luzd_slice"
      return 1
   fi

   # Now get ZFS devices in pool
   lulib_get_zfs_devs "$luzd_pool" "" > "$luzd_res"
   if [ "$?" -ne 0 -o ! -f "$luzd_res" -o ! -s "$luzd_res" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to determine devices in ZFS pool <%s>'`" "$luzd_pool"
      return 1
   fi

   return 0
}

#
# This function is called to determine the boot disk(s) for a BE
# given the BE mountpoint
#
# Arguments:
#	$1	Mountpoint of BE as returned by lumount
#	$2	Name of tempfile for results - contains space separated list of submirrors
#
# Returns:
#	0	boot disk(s) found
#	1	An error occurred
# Local Prefix:  lupb
#
lulib_get_be_phys_boot_slices()
{
   lupb_tmp="/tmp/.lulib.lupb.0.$$"

   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_get_be_phys_boot_slices() only supported on x86'`"
      return 1
   fi

   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_get_be_phys_boot_slice <BE-mount-point> <temp-file-for-results>'`"
      return 1
   fi

   lupb_mntpt="$1"
   lupb_res="$2"

   /bin/rm -f "$lupb_res"

   # Check if this is a ZFS BE
   lupb_rootdev_blk=`${LUETCBIN}/lubootdevice -m "$lupb_mntpt"`
   if [ "$?" -ne 0 -o -z "$lupb_rootdev_blk" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine physical root device for BE mountpoint <%s>'`" "$lupb_mntpt"
      return 1
   fi

   lupb_fstyp=`lulib_fstyp $lupb_rootdev_blk 2>/dev/null`
   if [ "$?" -ne 0 -o -z "$lupb_fstyp" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine filesystem type for BE mountpoint <%s>'`" "$lupb_mntpt"
      return 1
   fi

   if [ "$lupb_fstyp" = zfs ]; then
      lulib_get_zfs_devs_from_slice "$lupb_rootdev_blk" "$lupb_res"
      return "$?"
   fi
   
   # Get the logical (i.e. may contain "md" metadevices) root for the BE
   lupb_log_rootdev_blk=`${LUETCBIN}/lurootspec -m $lupb_mntpt`
   if [ "$?" -ne 0 -o -z "$lupb_log_rootdev_blk" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine logical root device for BE mountpoint <%s>'`" "$lupb_mntpt"
      return 1
   fi

   # Check if SVM is present
   lulib_discover_sds_installation
   if [ -z "$SDS_FOUND" ]; then
      ${LUPRINTF} -lp2D - "`gettext 'SVM is not configured'`"
      ${LUPRINTF} -lp2D - "`gettext 'Logical slice = physical slice'`"
      /bin/echo "$lupb_log_rootdev_blk" > "$lupb_res"
      return 0
   fi

   if /bin/echo "$lupb_log_rootdev_blk" | /bin/grep md; then
      :
   else
      ${LUPRINTF} -lp2D - "`gettext 'Logical slice = physical slice'`"
      /bin/echo "$lupb_log_rootdev_blk" > "$lupb_res"
      return 0
   fi

   # Get the "short" metadevice name
   lupb_short_mdname=`echo $lupb_log_rootdev_blk  | /bin/sed 's:/dev/md/dsk/::g'`
   ${SDS_METASTAT} -p $lupb_log_rootdev_blk > $lupb_tmp
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot run: <%s>'`" "${SDS_METASTAT}"
      # Keep the tmp file for debugging
      return 1
   fi

   # Check if mirror
   lupb_mirror=`/bin/nawk -v metadev="$lupb_short_mdname" ' {if ($1 == metadev) {printf("%s\n", $2);exit 14;}}' "$lupb_tmp"`
   if [ "$?" -ne 14 -o -z "$lupb_mirror" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot parse device-type in <%s> output'`" "${SDS_METASTAT}"
      return 1
   fi

   if [ "$lupb_mirror" != "-m" ]; then
      /bin/echo `/bin/nawk -v metadev="$lupb_short_mdname" ' {if ($1 == metadev)
{printf("%s\n", $3);exit 15;}}' "$lupb_tmp"` > $lupb_res
      if [ "$?" -ne 15 -o ! -s "$lupb_res" ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Cannot parse phys-device in <%s> output'`" "${SDS_METASTAT}"
         /bin/rm -f "$lupb_res"
         return 1
      fi
      /bin/rm -f "$lupb_tmp"
      return 0
   fi

   # Ok, we have a mirror. Walk the list of submirrors.
   lupb_mirror=`/bin/nawk -v metadev="$lupb_short_mdname" ' {if ($1 == metadev) {printf("%s\n", $0);exit 16;}}' "$lupb_tmp"`
   if [ "$?" -ne 16 -o -z "$lupb_mirror" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot parse mirror in <%s> output'`" "${SDS_METASTAT}"
      return 1
   fi

   # Done with tmp file
   /bin/rm -f "$lupb_tmp"

   lupb_first=0
   for i in $lupb_mirror
   do
        if [ "$i" = "$lupb_short_mdname" ]; then
           continue
        fi

        if [ "$i" = "-m" ]; then
           continue
        fi

	lupb_submirror=`"${SDS_METASTAT}" -p "$i" 2> /dev/null | /bin/nawk '{print $4; exit 17;}'` 
        if  [ "$?" -ne 17 ]; then
            ${LUPRINTF} -lp1 "`gettext 'Skipping parse of <%s> in <%s> output'`" "$i" "${SDS_METASTAT}"
	    continue
	fi

	if [ "$lupb_first" -eq 0 ]; then
	   lupb_first=1
	   /bin/echo "/dev/rdsk/${lupb_submirror}" > "$lupb_res"
	else
	   /bin/echo "/dev/rdsk/${lupb_submirror}" >> "$lupb_res"
	fi
	   
   done

   return 0
}

#
# This function is called to convert the root command in a BE's GRUB entry 
# to the findroot command 
#
# Arguments:
#	$1	The GRUB menu to be updated
#	$2	Name of BE
#	$3	The BE boot signature
#
# Returns:
#	0	Conversion successful
#	1	An error occurred
#
# Local Prefix:  lucvt
#
lulib_convert_root()
{

   lucvt_tmp1="/tmp/.lulib.cvt.1.$$"
   lucvt_tmp2="/tmp/.lulib.cvt.2.$$"

   /bin/rm -f "$lucvt_tmp1"
   /bin/rm -f "$lucvt_tmp2"

   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_convert_root() only supported on x86'`"
      return 1
   fi

   if [ "$#" -ne 3 -o -z "$1" -o -z "$2" -o -z "$3" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_convert_root <menu> <BE-name> <BE-boot-signature>'`"
      return 1
   fi

   lucvt_menu="$1"
   lucvt_bename="$2"
   lucvt_besign="$3"

   lucvt_fixed=`lulib_fix_name "$lucvt_bename"`
   lucvt_hdr="${BOOT_MENU_PREFIX}${lucvt_fixed}${BOOT_MENU_HDR_SUFFIX}"
   lucvt_ftr="${BOOT_MENU_PREFIX}${lucvt_fixed}${BOOT_MENU_FTR_SUFFIX}"

   # Check if the BE is present in the GRUB menu. It is not an error if it is
   # absent as it may be oldboot BE
   /bin/grep "$lucvt_hdr" "$lucvt_menu" > /dev/null 2>&1
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -lp2D - "`gettext 'No GRUB menu entry for BE <%s>'`" "${lucvt_bename}"
      return 0
   fi

   ${LUPRINTF} -lp1 "`gettext 'Converting GRUB menu entry for BE <%s>'`" "$lucvt_bename"

   start=`/usr/bin/awk "/^$lucvt_hdr\$/ { print NR }" "$lucvt_menu"`
   if [ -z "$start" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Missing header. Cannot convert menu entry for BE <%s>'`" "${lucvt_bename}"
      return 1
   fi
  
   stop=`/usr/bin/awk "/^$lucvt_ftr\$/ { print NR }" "$lucvt_menu"`
   if [ -z "$stop" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Missing footer. Cannot convert menu entry for BE <%s>'`" "${lucvt_bename}"
      return 1
   fi

   # Copy the entry to be modified to a temp menu
   /bin/nawk -v "hdr=$start" -v "ftr=$stop" "NR > hdr && NR < ftr {print}" "$lucvt_menu" > "$lucvt_tmp1"


   # Change each instance of the root command to findroot
   /bin/cat "$lucvt_tmp1" | /bin/egrep -v "^#"| /bin/sed 's/^[        ]*root[         ]*/findroot /g' > "$lucvt_tmp2"

   # Replace hd? notation with bootsign
   /bin/cat "$lucvt_tmp2" | /bin/egrep -v "^#" | /bin/sed "s;(hd.,;(${lucvt_besign},;g" > "$lucvt_tmp1"

   # We replace in place so no need to update the default command
   /bin/nawk -v "hdr=$start" "NR <= hdr {print}" "$lucvt_menu" > "$lucvt_tmp2"
   /bin/cat "$lucvt_tmp1" >> "$lucvt_tmp2"
   /bin/nawk -v "ftr=$stop" "NR >= ftr {print}" "$lucvt_menu" >> "$lucvt_tmp2"

   /bin/rm -f "$lucvt_tmp1"

   /bin/cp "$lucvt_tmp2" "$lucvt_menu"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to update menu. Cannot convert menu entry for BE <%s>'`" "${lucvt_bename}"
      return 1
   fi

   /bin/rm -f "$lucvt_tmp2"

   ${LUPRINTF} -lp2D - "`gettext 'Converted GRUB menu entry for BE <%s>'`" "$lucvt_bename"

   return 0
}

#
# This function is called to mount a legacy top dataset in a pool
#
# Arguments:
#	$1	pool name
#	$2	State file
#
# Returns:
#	0	Legacy top dataset mounted
#	1	A fatal error occurred
#
# Local Prefix:  luld
#
lulib_mount_legacy_top_dataset()
{
   luld_tmpmnt="/tmp/.lulib.luld.tmp.$$"

   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_mount_legacy_top_dataset() only supported on x86'`"
      return 1
   fi
   
   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_mount_legacy_top_dataset <pool> <state-file>'`"
      return 1
   fi

   luld_pool="$1"
   luld_state="$2"

   /bin/rm -f "$luld_state"

   # Is a legacy dataset
   /bin/echo "LEGACY=YES" > "$luld_state"

   # First check if mounted
   luld_mounted=`/sbin/zfs get -Ho value mounted "$luld_pool"`
   if [ "$?" -ne 0 -o -z "$luld_mounted" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'cannot determine if top legacy dataset <%s> is mounted'`" "$luld_pool"
      /bin/rm -f "$luld_state"
      return 1
   fi

   # Mount the dataset if not already mounted
   if [ "$luld_mounted" = no ]; then
      /bin/mkdir -p "$luld_tmpmnt"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'unable to create mountpoint for legacy top dataset in pool <%s>'`" "$luld_pool"
         /bin/rm -f "$luld_state"
	 return 1
      fi
      /sbin/mount -F zfs "$luld_pool" "$luld_tmpmnt"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'unable to mount legacy top dataset in pool <%s>'`" "$luld_pool"
         /bin/rm -f "$luld_state"
	 /bin/rmdir "$luld_tmpmnt"
	 return 1
      fi
      /bin/echo "MOUNTED=YES" >> "$luld_state"
      /bin/echo "MOUNTPOINT=$luld_tmpmnt" >> "$luld_state"
      return 0
   fi

   /bin/echo "MOUNTED=NO" >> "$luld_state"

   # Legacy dataset already mounted. Get mountpoint
   luld_mntpt=`/bin/cat /etc/mnttab | /bin/nawk -v POOL=$luld_pool '$1 == POOL && $3 == "zfs" {print $2; exit 20}'`
   if [ "$?" -ne 20 -o -z "$luld_mntpt" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'unable to get mountpoint for legacy top dataset in pool <%s>'`" "$luld_pool"
      /bin/rm -f "$luld_state"
      return 1
   fi

   /bin/echo "MOUNTPOINT=$luld_mntpt" >> "$luld_state"

   return 0
}

#
# This function is called to mount the top dataset in a pool
#
# Arguments:
#	$1	pool name
#	$2	State file
#
# Returns:
#	0	Top dataset mounted
#	1	A fatal error occurred
#
# Local Prefix:  lumd
#
lulib_mount_top_dataset()
{
   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_mount_top_dataset() only supported on x86'`"
      return 1
   fi
   

   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_mount_top_dataset <pool> <state-file>'`"
      return 1
   fi

   lumd_pool="$1"
   lumd_state="$2"

   /bin/rm -f "$lumd_state"

   # first check if this is a legacy dataset
   lumd_legacy=`/sbin/zfs get -Ho value mountpoint "$lumd_pool"`
   if [ "$?" -ne 0 -o -z "$lumd_legacy" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'cannot check for legacy pool dataset for pool <%s>'`" "$lumd_pool"
      return 1
   fi

   if [ "$lumd_legacy" = legacy ]; then
      lulib_mount_legacy_top_dataset "$lumd_pool" "$lumd_state"
      return "$?"
   fi

   # Not a legacy dataset
   /bin/echo "LEGACY=NO" > "$lumd_state"

   # First check if mounted
   lumd_mounted=`/sbin/zfs get -Ho value mounted "$lumd_pool"`
   if [ "$?" -ne 0 -o -z "$lumd_mounted" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'cannot determine if pool <%s> is mounted'`" "$lumd_pool"
      /bin/rm -f "$lumd_state"
      return 1
   fi

   # Mount the dataset if not already mounted
   if [ "$lumd_mounted" = no ]; then
      /sbin/zfs mount "$lumd_pool"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'unable to mount top dataset in pool <%s>'`" "$lumd_pool"
         /bin/rm -f "$lumd_state"
	 return 1
      fi
      /bin/echo "MOUNTED=YES" >> "$lumd_state"
      lumd_mounted=yes
    else
      /bin/echo "MOUNTED=NO" >> "$lumd_state"
      lumd_mounted=no
    fi

    # Now that dataset is mounted, get the mountpoint
    lumd_mountpoint=`/sbin/zfs get -Ho value mountpoint "$lumd_pool"`
    if [ "$?" -ne 0 -o -z "$lumd_mountpoint" ]; then
       ${LUPRINTF} -Eelp2 "`gettext 'unable to get mountpoint for top dataset in pool <%s>'`" "$lumd_pool"
       if [ "$lumd_mounted" = yes ]; then
          /sbin/zfs unmount "$lumd_pool"
       fi
      /bin/rm -f "$lumd_state"
       return 1
    fi

    /bin/echo "MOUNTPOINT=$lumd_mountpoint" >> "$lumd_state"

   return 0
}

#
# This function is called to unmount the top dataset in a pool
# (if it was mounted by use)
#
# Arguments:
#	$1	pool name
#	$2	State file
#
# Returns:
#	0	Top dataset unmounted
#	1	A fatal error occurred
#
# Local Prefix:  lutd
#
lulib_unmount_top_dataset()
{
   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_unmount_top_dataset() only supported on x86'`"
      return 1
   fi
   
   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_unmount_top_dataset <pool> <state-file>'`"
      return 1
   fi

   lutd_pool="$1"
   lutd_state="$2"

   if [ ! -f "$lutd_state" -o ! -s "$lutd_state" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot unmount dataset for pool <%s>'`" "$lutd_pool"
      return 1
   fi

   # Check if the dataset was mounted by someone else. In that case we have nothing to do
   lutd_mounted=`/bin/awk -F= '$1 == "MOUNTED" {print $2; exit 21}' "$lutd_state"`
   if [ "$?" -ne 21 -o -z "$lutd_mounted" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine if dataset was mounted. Cannot unmount dataset for pool <%s>'`" "$lutd_pool"
      return 1
   fi

   if [ "$lutd_mounted" = NO ]; then
      # Nothing to do
      /bin/rm -f "$lutd_state"
      return 0
   fi

   # Check if a legacy dataset
   lutd_legacy=`/bin/awk -F= '$1 == "LEGACY" {print $2; exit 22}' "$lutd_state"`
   if [ "$?" -ne 22 -o -z "$lutd_legacy" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine if dataset is legacy. Cannot unmount dataset for pool <%s>'`" "$lutd_pool"
      return 1
   fi

   if [ "$lutd_legacy" = NO ]; then
      /sbin/zfs unmount "$lutd_pool"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Failed to unmount dataset for pool <%s>'`" "$lutd_pool"
         return 1
      fi
      /bin/rm -f "$lutd_state"
      return 0
   fi

   # This is a legacy dataset that we mounted. Use the umount command.
   /sbin/umount "$lutd_pool"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to unmount legacy dataset for pool <%s>'`" "$lutd_pool"
      return 1
   fi

   # Remove the mountpoint
   lutd_mntpt=`/bin/awk -F= '$1 == "MOUNTPOINT" {print $2; exit 23}' "$lutd_state"`
   if [ "$?" -ne 23 -o -z "$lutd_mntpt" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine mountpoint for legacy dataset in pool <%s>'`" "$lutd_pool"
      return 1
   fi

   /bin/rmdir "$lutd_mntpt"
   /bin/rm -f "$lutd_state"

   return 0
}

#
# This function is called to copy or delete a file from the top dataset in a pool
#
# Arguments:
#	$1	BE name
#	$2	The file
#	$3	The filepath
#	$4	action to be performed
#
# Returns:
#	0	File operation in top level dataset successful
#	1	A fatal error occurred
#	2	Filesystem is not ZFS
#
# Local Prefix:  lupt
#
lulib_copy_delete_from_top_dataset()
{
   lupt_state="/tmp/.lulib.lupt.state.$$"

   /bin/rm -f "$lupt_state"

   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_copy_delete_from_top_dataset() only supported on x86'`"
      return 1
   fi
   

   if [ "$#" -ne 4 -o -z "$1" -o -z "$2" -o -z "$3" -o -z "$4" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_copy_delete_from_top_dataset <BEname> <file> <filepath> <action>'`"
      return 1
   fi

   if [ "$4" != copyto -a "$4" != copyfrom -a "$4" != delete ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'lulib_copy_delete_from_top_dataset: invalid action'`"
      return 1
   fi

   lupt_bename="$1"
   lupt_file="$2"
   lupt_filepath="$3"
   lupt_action="$4"

   # Get root slice for current BE
   lupt_rslice=`${LUETCBIN}/ludo get_root_slice_from_be_name "$lupt_bename"`
   if [ "$?" -ne 0 -o -z "$lupt_rslice" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to get root slice for current BE <%s>. Cannot operate on file <%s>'`" "$lupt_bename" "$lupt_filepath"
      return 1
   fi

   lupt_fstyp=`lulib_fstyp "$lupt_rslice"`
   if [ "$?" -ne 0 -o -z "$lupt_fstyp" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to get fstype for BE <%s>. Cannot operate on file <%s>'`" "$lupt_bename" "$lupt_filepath"
      return 1
   fi

   if [ "$lupt_fstyp" != zfs ]; then
      return 2
   fi

   # For zfs the root slice will be of the form <pool>/ROOT/<dataset>
   lupt_pool=`/bin/echo "$lupt_rslice" | /bin/awk -F/ '{print $1; exit 25}'`
   if [ "$?" -ne 25 -o -z "$lupt_pool" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'cannot get pool name for rootslice <%s>'`" "$lupt_rslice"
      return 1
   fi


   lulib_mount_top_dataset "$lupt_pool" "$lupt_state"
   if [ "$?" -ne 0 ]; then
      return 1
   fi

   lupt_mntpt=`/bin/awk -F= '$1 == "MOUNTPOINT" {print $2; exit 24}' "$lupt_state"`
   if [ "$?" -ne 24 -o -z "$lupt_mntpt" ]; then
      lulib_unmount_top_dataset "$lupt_pool" "$lupt_state"
      return 1
   fi

   if [ "$lupt_action" = delete ]; then
      /bin/rm -f "${lupt_mntpt}/${lupt_filepath}"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete file <%s> in top level dataset of BE <%s>'`" "${lupt_filepath}" "${lupt_bename}"
         lupt_ret=1
      else
	 lupt_ret=0
      fi
      lulib_unmount_top_dataset "$lupt_pool" "$lupt_state"
      return "$lupt_ret"
   fi


   if [ "$lupt_action" = copyfrom ]; then
      if [ ! -f "${lupt_mntpt}/${lupt_filepath}" ]; then
         ${LUPRINTF} -lp1 "`gettext 'NOTE: File <%s> not found in top level dataset for BE <%s>'`" "${lupt_filepath}" "${lupt_bename}"
         lulib_unmount_top_dataset "$lupt_pool" "$lupt_state"
         return 1
      fi
      lupt_ret=0
      /bin/cp -p "${lupt_mntpt}/${lupt_filepath}" "${lupt_file}"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'cp of file <%s> from top level dataset to BE <%s> failed.'`" "$lupt_filepath" "$lupt_bename"
         lupt_ret=1
      fi
      lulib_unmount_top_dataset "$lupt_pool" "$lupt_state"
      return "$lupt_ret"
   fi

   if [ -f "${lupt_mntpt}/${lupt_filepath}" -a -s "${lupt_mntpt}/${lupt_filepath}" ]; then
      # There is a preexisting file at the specified location. Propagate the file anyway,
      # but save the previous file.
      ${LUPRINTF} -lp1 "`gettext 'Saving existing file <%s> in top level dataset for BE <%s> as <mount-point>/%s.prev.'`" "$lupt_filepath" "$lupt_bename" "$lupt_filepath"
      /bin/mv "${lupt_mntpt}/${lupt_filepath}" "${lupt_mntpt}/${lupt_filepath}.prev"
   fi

   # Now create the directory on the top level dataset
   lupt_dir=`dirname "$lupt_filepath"`
   /bin/mkdir -p "${lupt_mntpt}/${lupt_dir}"

   lupt_ret=0
   /bin/cp -p "${lupt_file}" "${lupt_mntpt}/${lupt_filepath}"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'cp of file <%s> to top level dataset for BE <%s> failed.'`" "$lupt_filepath" "$lupt_bename"
      lupt_ret=1
   fi

   lulib_unmount_top_dataset "$lupt_pool" "$lupt_state"

   return "$lupt_ret"
}

lulib_copy_to_top_dataset()
{
    lulib_copy_delete_from_top_dataset "$1" "$2" "$3" "copyto"
    return "$?"
}

lulib_copy_from_top_dataset()
{
    lulib_copy_delete_from_top_dataset "$1" "$2" "$3" "copyfrom"
    return "$?"
}

lulib_delete_from_top_dataset()
{
    lulib_copy_delete_from_top_dataset "$1" "dummy" "$2" "delete"
    return "$?"
}

#
# This function is called to mount the x86 boot partition on the system (if one exists)
#
# Arguments:
#	$1	The state file to record mount state
#
# Returns:
#	0	x86 boot partition mounted or does not exist
#	1	A fatal error occurred
#	2	One or more non-fatal errors occurred
#	3	No x86 boot partition
#
# Local Prefix:  lmbp
#
lulib_mount_boot_part()
{
   lmbp_mntdir="/tmp/.lulib.lmbp.mntdir.$$"

   if [ "${LU_SYSTEM_ARCH}" != "i386" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'lulib_mount_boot_part() only supported on x86 '`"
      return 1
   fi

   if [ "$#" -ne 1 -o -z "$1" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_mount_boot_part <state-file>'`"
      return 1
   fi

   lmbp_state="$1"

   /bin/rm -f "$lmbp_state"

   # Now check if x86 boot partition is present
   lmbp_bootpart=`/bin/grep -v '^#' /etc/vfstab | /bin/grep "[ 	]/stubboot[ 	]*pcfs[ 	]" | /bin/awk '{print $1}'`
   ret="$?"
   if [ "$ret" -ne 0 -o -z "$lmbp_bootpart" ]; then
      lmbp_bootpart=`/bin/grep -v '^#' /etc/vfstab | /bin/grep "[ 	]/boot[ 	]*pcfs[ 	]" | /bin/awk '{print $1}'`
      ret="$?"
   fi
   if [ "$ret" -ne 0 -o -z "$lmbp_bootpart" ]; then
      ${LUPRINTF} -lp2D - "`gettext 'No x86 boot partition'`"
      return 3
   fi
    
   lmbp_mntpt=`/sbin/mount | /bin/nawk -v dev=$lmbp_bootpart '{ if ($3 == dev) {printf("%s\n", $1); exit 9;}}'`
   if [ "$?" -ne 9 ]; then
      /bin/mkdir -p "$lmbp_mntdir"
      /sbin/mount -F pcfs "$lmbp_bootpart" "$lmbp_mntdir"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Cannot mount x86 boot partition <%s>'`" "$lmbp_bootpart"
          /bin/rmdir "$lmbp_mntdir"
          return 1
      fi
      lmbp_mnted=1
      lmbp_mntpt="$lmbp_mntdir"
  else
      lmbp_mnted=""
  fi

  /bin/echo "${lmbp_mnted}:${lmbp_mntpt}" > "$lmbp_state"

  return 0
}

#
# This function is called to unmount the x86 boot partition mounted by lulib_mount_boot_part()
#
# Arguments:
#	$1	The state file containing mount information
#
# Returns:
#	0	x86 boot partition unmounted
#	1	A fatal error occurred
#
# Local Prefix:  lubp
#
lulib_unmount_boot_part()
{
   if [ "${LU_SYSTEM_ARCH}" != "i386" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'lulib_unmount_boot_part() only supported on x86 '`"
      return 1
   fi

   if [ "$#" -ne 1 -o -z "$1" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_unmount_boot_part <state-file>'`"
      return 1
   fi

   lubp_state="$1"

   lubp_mnted=`/bin/cat "$lubp_state" | /bin/cut -d ':' -f1`
   lubp_mntpt=`/bin/cat "$lubp_state" | /bin/cut -d ':' -f2`

   if [ -z "$lubp_mnted" ]; then
      return 0
   fi

   /sbin/umount "$lubp_mntpt"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to unmount x86 boot partition mounted at <%s>'`" "$lubp_mntpt"
      return 1
   fi

   /bin/rmdir "$lubp_mntpt"

   return 0
}

#
# This function is called to propagate a file from the current BE to all BEs
#
# Arguments:
#	$1	The name of the file
#	$2	copy to pool top dataset
#
# Returns:
#	0	File copied to all BEs successfully
#	1	A fatal error occurred
#	2	One or more non-fatal errors occurred
#
# Local Prefix:  lupf
#
lulib_propagate_file()
{
   lupf_error="/tmp/.lulib.lupf.error.$$"
   lupf_tmp="/tmp/.lulib.lupf.tmp.$$"
   lupf_state="/tmp/.lulib.lupf.state.$$"

   /bin/rm -f "$lupf_error"
   /bin/rm -f "$lupf_tmp"
   /bin/rm -f "$lupf_state"

   if [ "$#" -ne 2 -o -z "$1" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_propagate_file <filepath> <to-top-dataset>'`"
      return 1
   fi

   lupf_filepath="$1"
   lupf_top="$2"

   if /bin/echo "$lupf_filepath" |  /bin/egrep "^/" > /dev/null 2>&1; then
      :
   else
      ${LUPRINTF} -Eelp2 "`gettext 'filepath <%s> is not absolute. Cannot propagate file to all BEs'`" "$lupf_filepath"
      return 1
   fi


   lupf_zfs_top=""
   if [ "$lupf_top" = yes ]; then
      lupf_be_name=`/usr/sbin/lucurr`

      lulib_copy_from_top_dataset "$lupf_be_name" "$lupf_tmp" "$lupf_filepath" 
      ret="$?"
      if [ "$ret" -eq 1 ]; then
	 ${LUPRINTF} -Eelp2 "`gettext 'Failed to copy file <%s> from top level dataset to BE <%s>'`" "$lupf_filepath" "$lupf_be_name"
         return 1
      elif [ "$ret" -eq 0 ]; then
         lupf_zfs_top=yes
      else
	 # UFS
	 : 
      fi
   fi

   if [ -z "$lupf_zfs_top" ]; then
      if [ ! -f "$lupf_filepath" ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'file <%s> does not exist. Cannot propagate file to all BEs'`" "$lupf_filepath"
         return 1
      fi
      /bin/cp -p "$lupf_filepath" "$lupf_tmp"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'copy of <%s> failed. Cannot propagate file to all BEs'`" "$lupf_filepath"
         return 1
      fi
   fi


   ${LUBIN}/lunames_get |
   while read lupf_be_name
   do

	# Nothing to do for current BE
	if [ "$lupf_be_name" = "`/usr/sbin/lucurr`" ]; then 
	   continue
	fi

	status=`${LUETCBIN}/ludo get_be_status_from_be_name "$lupf_be_name"`
	if [ "$?" -ne 0 ]; then
	   ${LUPRINTF} -Eelp2 "`gettext 'Failed to get status for BE <%s>. Cannot propagate file <%s> to BE'`" "$lupf_be_name" "$lupf_filepath"
	   /bin/touch "$lupf_error"
	   continue;
	fi

	# Cannot mount an incomplete BE
	[ "$status" != C ] && continue

	if [ "$lupf_top" = yes ]; then
	   lulib_copy_to_top_dataset "$lupf_be_name" "$lupf_tmp" "$lupf_filepath" 
	   ret="$?"
	   if [ "$ret" -eq 1 ]; then
	      ${LUPRINTF} -Eelp2 "`gettext 'Failed to propagate file <%s> to top level dataset in BE <%s>'`" "$lupf_filepath" "$lupf_be_name"
	      /bin/touch "$lupf_error"
	      continue;
	   elif [ "$ret" -eq 0 ]; then
	      continue;
	   else
	      # UFS
	      :
	   fi
	fi

	lupf_be_mntpt=`lulib_mount -Z "$lupf_be_name" "$lupf_state"`
	if [ "$?" -ne 0 -o  -z "$lupf_be_mntpt" ]; then
	   ${LUPRINTF} -Eelp2 "`gettext 'Failed to mount BE <%s>. Cannot propagate file <%s> to BE'`" "$lupf_be_name" "$lupf_filepath"
	   /bin/touch "$lupf_error"
	   /bin/rm -f "$lupf_state"
	   continue
	fi

	if [ -f "${lupf_be_mntpt}/${lupf_filepath}" -a -s "${lupf_be_mntpt}/${lupf_filepath}" ]; then
	   # There is a preexisting file at the specified location. Propagate the file anyway,
           # but save the previous file.
	   ${LUPRINTF} -lp2D - "`gettext 'Saving existing file <%s> in BE <%s> as <mount-point>/%s.prev.'`" "$lupf_filepath" "$lupf_be_name" "$lupf_filepath"
	   /bin/mv "${lupf_be_mntpt}/${lupf_filepath}" "${lupf_be_mntpt}/${lupf_filepath}.prev"
	fi

	# Now create the directory on the BE
	lupf_dir_name=`dirname "$lupf_filepath"`
	/bin/mkdir -p "${lupf_be_mntpt}/${lupf_dir_name}"

	/bin/cp -p "$lupf_tmp" "${lupf_be_mntpt}/${lupf_filepath}"
	if [ "$?" -ne 0 ]; then
	   ${LUPRINTF} -Eelp2 "`gettext 'Failed to copy file <%s> to BE <%s>. Cannot propagate file to BE'`" "$lupf_filepath" "$lupf_be_name"
	   /bin/touch "$lupf_error"
	fi

	lulib_umount "$lupf_be_name" "$lupf_state"
	if [ "$?" -ne 0 ]; then
	   /bin/touch "$lupf_error"
	else
	   /bin/rm -f "$lupf_state"
	fi
done

# Copy to x86 boot partition
lulib_mount_boot_part "$lupf_state"
ret="$?"
case "$ret" in
   0) # Successful
      ${LUPRINTF} -lp1 "`gettext 'mounted x86 boot partition'`"
      ;;
   1) # Fatal error
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to propagate <%s> to x86 boot partition'`" "$lupf_filepath"
      return 1
      ;;
   2) # Non-fatal error. Drive on
      /bin/touch "$lupf_error"
      ;;
   3) # No x86 boot partition on system - just continue
      ;;
   *) # Unknown error - fatal
      ${LUPRINTF} -Eelp2 "`gettext 'File propagation to x86 boot partition failed with error code <%s>'`" "$ret"
      return 1
      ;;
esac


if [ "$ret" -eq 0 ]; then
   lupf_bootpart_mntpt=`/bin/cat "$lupf_state" | /bin/cut -d: -f 2`
   if [ -f "${lupf_bootpart_mntpt}/${lupf_filepath}" -a -s "${lupf_bootpart_mntpt}/${lupf_filepath}" ]; then
      # There is a preexisting file at the specified location. Propagate the file anyway,
      # but save the previous file.
      ${LUPRINTF} -lp2D - "`gettext 'Saving existing file <%s> in x86 boot partition as %s.prev.'`" "$lupf_filepath" "$lupf_filepath"
      /bin/mv "${lupf_bootpart_mntpt}/${lupf_filepath}" "${lupf_bootpart_mntpt}/${lupf_filepath}.prev"
   fi

   # Now create the directory if necessary
   lupf_dir_name=`dirname "$lupf_filepath"`
   /bin/mkdir -p "${lupf_bootpart_mntpt}/${lupf_dir_name}"

   /bin/cp -p "$lupf_tmp" "${lupf_bootpart_mntpt}/${lupf_filepath}"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to copy file <%s> to x86 boot partition. Cannot propagate file'`" "$lupf_filepath"
      /bin/touch "$lupf_error"
   fi

   lulib_unmount_boot_part "$lupf_state"
   if [ "$?" -ne 0 ]; then
      /bin/touch "$lupf_error"
   else
      /bin/rm -f "$lupf_state"
   fi
fi

/bin/rm -f "$lupf_tmp"

if [ -f "$lupf_error" ]; then
   ${LUPRINTF} -lp1 "`gettext 'File propagation was incomplete'`"
   /bin/rm "$lupf_error"
   return 2
fi

${LUPRINTF} -lp1 "`gettext 'File <%s> propagation successful'`" "$lupf_filepath"

return 0
}

#
# This function is called to delete a file in all BEs
#
# Arguments:
#	$1	The name of the file
#	$2	if "yes", delete from top level dataset
#
# Returns:
#	0	File deleted from all BEs successfully
#	1	A fatal error occurred
#	2	A non-fatal error occurred
#
# Local Prefix:  ludf
#
lulib_delete_file()
{
   ludf_error="/tmp/.lulib.ludf.error.$$"
   ludf_state="/tmp/.lulib.ludf.state.$$"

   /bin/rm -f "$ludf_error"
   /bin/rm -f "$ludf_state"

   if [ "$#" -ne 2 -o -z "$1" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_delete_file <filepath> <from-top-dataset>'`"
      return 1
   fi

   ludf_file="$1"
   ludf_top="$2"

   if /bin/echo "$ludf_file" |  /bin/egrep "^/" > /dev/null 2>&1; then
      :
   else
      ${LUPRINTF} -Eelp2 "`gettext 'filepath <%s> is not absolute. Cannot delete file'`" "$ludf_file"
      return 1
   fi

   ${LUBIN}/lunames_get |
   while read ludf_be_name
   do
        status=`${LUETCBIN}/ludo get_be_status_from_be_name "$ludf_be_name"`
	if [ "$?" -ne 0 ]; then
	   ${LUPRINTF} -Eelp2 "`gettext 'Failed to get status for BE <%s>. Cannot delete file <%s> from BE'`" "$ludf_be_name" "$ludf_file"
	   /bin/touch "$ludf_error"
	   continue;
	fi

	# Cannot mount an incomplete BE
	[ "$status" != C ] && continue

	if [ "$ludf_top" = yes ]; then
	   lulib_delete_from_top_dataset "$ludf_be_name" "$ludf_file" 
	   ret="$?"
	   if [ "$ret" -eq 1 ]; then
	      ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete file <%s> from top level dataset in BE <%s>'`" "$ludf_file" "$ludf_be_name"
	      /bin/touch "$ludf_error"
	      continue;
	   elif [ "$ret" -eq 0 ]; then
	      continue;
	   else
	      # UFS BE
	      :
	   fi
	fi

	# lumount everything except current BE
	if [ "$ludf_be_name" = "`/usr/sbin/lucurr`" ]; then 
	   continue
	fi

	ludf_be_mntpt=`lulib_mount "$ludf_be_name" "$ludf_state"`
	if [ "$?" -ne 0 -o  -z "$ludf_be_mntpt" ]; then
	   ${LUPRINTF} -Eelp2 "`gettext 'Failed to mount BE <%s>. Cannot delete file <%s> in BE'`" "$ludf_be_name" "$ludf_file"
	   /bin/touch "$ludf_error"
	   /bin/rm -f "$ludf_state"
	   continue
	fi

	/bin/rm -f "${ludf_be_mntpt}/${ludf_file}"
	if [ "$?" -ne 0 ]; then
	   ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete file <%s> in BE <%s>'`" "${ludf_file}" "${ludf_be_name}"
	   /bin/touch "$ludf_error"
	fi

	lulib_umount "$ludf_be_name" "$ludf_state"
	if [ "$?" -ne 0 ]; then
	   /bin/touch "$ludf_error"
	else
	   /bin/rm -f "$ludf_state"
	fi
done

# Delete from x86 boot partition
lulib_mount_boot_part "$ludf_state"
ret="$?"
case "$ret" in
   0) # Successful
      ${LUPRINTF} -lp1 "`gettext 'mounted x86 boot partition'`"
      ;;
   1) # Fatal error
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete <%s> from x86 boot partition'`" "$ludf_file"
      return 1
      ;;
   2) # Non-fatal error. Drive on
      /bin/touch "$ludf_error"
      ;;
   3) # No x86 boot partition - just continue
      ;;
   *) # Unknown error - fatal
      ${LUPRINTF} -Eelp2 "`gettext 'File deletion from x86 boot partition failed with error code <%s>'`" "$ret"
      return 1
      ;;
esac

if [ "$ret" -eq 0 ]; then
   ludf_bootpart_mntpt=`/bin/cat "$ludf_state" | /bin/cut -d: -f 2`
   /bin/rm -f "${ludf_bootpart_mntpt}/${ludf_file}"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete file <%s> from x86 boot partition'`" "${ludf_file}"
      /bin/touch "$ludf_error"
   fi

   lulib_unmount_boot_part "$ludf_state"
   if [ "$?" -ne 0 ]; then
      /bin/touch "$ludf_error"
   else
      /bin/rm -f "$ludf_state"
   fi
fi

/bin/rm -f "${ludf_file}"
if [ "$?" -ne 0 ]; then
   ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete file <%s> in current BE'`" "${ludf_file}"
   /bin/touch "$ludf_error"
fi

if [ -f "$ludf_error" ]; then
   ${LUPRINTF} -lp1 "`gettext 'File deletion was incomplete'`"
   /bin/rm "$ludf_error"
   return 2
fi

${LUPRINTF} -lp1 "`gettext 'File <%s> deletion successful'`" "$ludf_file"

return 0
}

#
# This function is called to copy a version of GRUB (which
# supports findroot) to all BEs.
#
# Arguments:
#	None
#
# Returns:
#	0	GRUB that supports findroot propagated to all BEs successfully
#	1	An error occurred
#
# Local Prefix:  lufg
#
lulib_propagate_findroot_GRUB()
{
   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_propagate_findroot_GRUB() only supported on x86'`"
      return 1
   fi

   if [ "$#" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_propagate_findroot_GRUB'`"
      return 1
   fi

   if [ ! -f "${LU_DIR}/installgrub.findroot" -o ! -s "${LU_DIR}/installgrub.findroot" -o ! -x "${LU_DIR}/installgrub.findroot" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'installgrub that supports findroot not installed on current BE'`"
      return 1
   fi
    
   if [ ! -f "${LU_DIR}/stage1.findroot" -o ! -s "${LU_DIR}/stage1.findroot" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'GRUB stage1 that supports findroot not installed on current BE'`"
      return 1
   fi

   if [ ! -f "${LU_DIR}/stage2.findroot" -o ! -s "${LU_DIR}/stage2.findroot" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'GRUB stage2 that supports findroot not installed on current BE'`"
      return 1
   fi

   if [ ! -f "${LU_DIR}/GRUB_capability" -o ! -s "${LU_DIR}/GRUB_capability" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'GRUB capability file not present on current BE'`"
      return 1
   fi

   ${LUPRINTF} -lp1 "`gettext 'Propagating findroot GRUB for menu conversion.'`"

   lulib_propagate_file "${LU_DIR}/installgrub.findroot" ""
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to propagate installgrub'`"
      return 1
   fi
   lulib_propagate_file "${LU_DIR}/stage1.findroot" ""
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to propagate stage1'`"
      return 1
   fi
   lulib_propagate_file "${LU_DIR}/stage2.findroot" ""
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to propagate stage2'`"
      return 1
   fi
   lulib_propagate_file "${LU_DIR}/GRUB_capability" ""
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to propagate GRUB capability file'`"
      return 1
   fi

   ${LUPRINTF} -lp1 "`gettext 'Deleting stale GRUB loader from all BEs.'`"
   lulib_delete_file "${LU_DIR}/installgrub.latest" ""
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete stale installgrub'`"
   fi
   lulib_delete_file "${LU_DIR}/stage1.latest"	""
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete stale GRUB stage1'`"
   fi
   lulib_delete_file "${LU_DIR}/stage2.latest"	""
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete stale GRUB stage2'`"
   fi

   return 0
}

#
# This function is called to create a signature file and the backup
# (if they don't already exist) for a UFS filesystem
#
# Arguments:
#	$1	BE name
#	$2	BE mountpoint
#	$3	Tmpfile for signature return
#
#
# Returns:
#	0	Signature successfully set on UFS root file system
#	1	An error occurred
#
# Local Prefix:  lsus
#
lulib_set_UFS_sign()
{
   lsus_errors=""

   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_set_UFS_sign() only supported on x86'`"
      return 1
   fi

   if [ "$#" -ne 3 -o -z "$1" -o -z "$2" -o -z "$3" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_set_UFS_sign <BE name> <BE mountpoint> <tmpfile> '`"
      return 1
   fi

   lsus_BE="$1"
   lsus_mntpt="$2"
   lsus_res="$3"

   /bin/rm -f "$lsus_tmp"
   /bin/rm -f "$lsus_res"

   lsus_sign="BE_${lsus_BE}"

   # Check the backup first
   /bin/grep "$lsus_sign" "${lsus_mntpt}/${LU_SIGN_BACKUP}" > /dev/null 2>&1
   if [ "$?" -ne 0 ]; then
      /bin/echo "$lsus_sign" >> "${lsus_mntpt}/${LU_SIGN_BACKUP}"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Failed to create boot sign backup for BE <%s> '`" "$lsus_BE"
	 lsus_errors="yes"
      fi
   fi

   if [ ! -f "${lsus_mntpt}/${LU_SIGN_DIR}/${lsus_sign}" ]; then
      /bin/mkdir -p  "${lsus_mntpt}/${LU_SIGN_DIR}"
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Failed to create boot sign directory for UFS BE <%s> '`" "$lsus_BE"
	 lsus_errors="yes"
      else
         /bin/touch "${lsus_mntpt}/${LU_SIGN_DIR}/${lsus_sign}" 
         if [ "$?" -ne 0 ]; then
            ${LUPRINTF} -Eelp2 "`gettext 'Failed to create primary boot signature for UFS BE <%s> '`" "$lsus_BE"
	    lsus_errors="yes"
         fi
      fi
   fi

   if [ -z "$lsus_errors" ]; then
      /bin/echo "$lsus_sign" > "$lsus_res" 
      return 0
   else
      return 1
   fi
}

#
# This function is called to create a signature file and the backup
# (if they don't already exist)
#
# Arguments:
#	$1	BE name
#	$2	BE mountpoint
#	$3	Tmpfile for signature return
#
#
# Returns:
#	0	Signature successfully set on root file system
#	1	An error occurred
#
# Local Prefix:  lusb
#
lulib_set_bootsign()
{
   lusb_errors=""
   lusb_tmp="/tmp/.lulib.lusb.tmp.$$"

   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_set_bootsign() only supported on x86'`"
      return 1
   fi

   if [ "$#" -ne 3 -o -z "$1" -o -z "$2" -o -z "$3" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_set_bootsign <BE name> <BE mountpoint> <tmpfile> '`"
      return 1
   fi

   lusb_BE="$1"
   lusb_mntpt="$2"
   lusb_res="$3"

   /bin/rm -f "$lusb_tmp"
   /bin/rm -f "$lusb_res"

   lusb_sign="BE_${lusb_BE}"

   # Check if ZFS BE
   lulib_copy_from_top_dataset "$lusb_BE" "$lusb_tmp" "${LU_SIGN_BACKUP}" 
   ret="$?"
   if [ "$ret" -eq 2 ]; then
     # UFS BE
     lulib_set_UFS_sign "$lusb_BE" "$lusb_mntpt" "$lusb_res"
     return "$?"
   fi

   # The file may not exist
   if [ "$ret" -eq 1 ]; then
      /bin/echo "$lusb_sign" > "$lusb_tmp"
      lulib_copy_to_top_dataset "$lusb_BE" "$lusb_tmp" "${LU_SIGN_BACKUP}" 
      if [ "$?" -ne 0 ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Failed to create boot sign backup for BE <%s> '`" "$lusb_BE"
         lusb_errors="yes"
      fi
   elif [ "$ret" -eq 0 ]; then
      /bin/grep "$lusb_sign" "${lusb_tmp}" > /dev/null 2>&1
      if [ "$?" -ne 0 ]; then
         /bin/echo "$lusb_sign" >> "${lusb_tmp}"
         if [ "$?" -ne 0 ]; then
            ${LUPRINTF} -Eelp2 "`gettext 'Failed to create boot sign backup for BE <%s> '`" "$lusb_BE"
	    lusb_errors="yes"
	 else
             lulib_copy_to_top_dataset "$lusb_BE" "$lusb_tmp" "${LU_SIGN_BACKUP}" 
             if [ "$?" -ne 0 ]; then
                ${LUPRINTF} -Eelp2 "`gettext 'Failed to create boot sign backup for BE <%s> '`" "$lusb_BE"
                lusb_errors="yes"
             fi
	 fi
      fi
   fi

   /bin/rm -f "$lusb_tmp"
   /bin/touch "$lusb_tmp"

   lulib_copy_to_top_dataset "$lusb_BE" "$lusb_tmp" "${LU_SIGN_DIR}/${lusb_sign}" 
   ret="$?"
   if [ "$ret" -eq 1 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to write boot signature <%s> to top level dataset in BE <%s>'`" "${LU_SIGN_DIR}/${lusb_sign}" "$lusb_BE"
      return 1
   elif [ "$ret" -eq 0 ]; then
      if [ -z "$lusb_errors" ]; then
         /bin/echo "$lusb_sign" > "$lusb_res" 
         return 0
      else
         return 1
      fi
   else
        ${LUPRINTF} -Eelp2 "`gettext 'lulib_set_bootsign(): Internal error ZFS/UFS mismatch'`"
	return 1
    fi
}

#
# This function is called to delete a signature file and the backup
# (if they exist) from a UFS BE
#
# Arguments:
#	$1	BE name
#	$2	BE mountpoint
#
#
# Returns:
#	0	Signature successfully deleted
#	1	An error occurred
#
# Local Prefix:  ludus
#
lulib_delete_UFS_sign()
{
   ludus_tmp="/tmp/.lulib.ludus.tmp.$$"

   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_delete_UFS_sign() only supported on x86'`"
      return 1
   fi

   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_delete_UFS_sign <BE name> <BE mountpoint>'`"
      return 1
   fi

   ludus_BE="$1"
   ludus_mntpt="$2"

   ludus_sign="BE_${ludus_BE}"

   /bin/cp -p "${ludus_mntpt}/${LU_SIGN_BACKUP}" "$ludus_tmp" > /dev/null 2>&1
   if [ "$?" -eq 0 ]; then
      # file may not exist so failure above is ok
      /bin/grep -v "$ludus_sign" "$ludus_tmp" > "${ludus_mntpt}/${LU_SIGN_BACKUP}"
   fi

   /bin/rm -f "${ludus_mntpt}/${LU_SIGN_DIR}/${ludus_sign}"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete boot signature file <%s> for UFS BE <%s>'`" "${LU_SIGN_DIR}/${ludus_sign}" "$ludus_BE"
      return 1
   else 
      return 0
   fi
}

#
# This function is called to delete a signature file and the backup
# (if they exist)
#
# Arguments:
#	$1	BE name
#	$2	BE mountpoint
#
#
# Returns:
#	0	Signature successfully deleted
#	1	An error occurred
#
# Local Prefix:  ludb
#
lulib_delete_bootsign()
{
   ludb_errors=""
   ludb_tmp="/tmp/.lulib.ludb.tmp.$$"
   ludb_tmp1="/tmp/.lulib.ludb.tmp1.$$"

   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_delete_bootsign() only supported on x86'`"
      return 1
   fi

   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_delete_bootsign <BE name> <BE mountpoint>'`"
      return 1
   fi

   ludb_BE="$1"
   ludb_mntpt="$2"

   ludb_sign="BE_${ludb_BE}"

   /bin/rm -f "$ludb_tmp"
   /bin/rm -f "$ludb_tmp1"
   # Fix the backup first
   lulib_copy_from_top_dataset "$ludb_BE" "$ludb_tmp" "${LU_SIGN_BACKUP}" 
   ret="$?"
   if [ "$ret" -eq 1 ]; then
      # File may not exist. Nothing to do
      :
   elif [ "$ret" -eq 2 ]; then
      # UFS
      lulib_delete_UFS_sign "$ludb_BE" "$ludb_mntpt"
      return "$?"
   else
     /bin/grep -v "$ludb_sign" "$ludb_tmp" > "$ludb_tmp1"
     lulib_copy_to_top_dataset "$ludb_BE" "$ludb_tmp1" "${LU_SIGN_BACKUP}" 
     if [ "$?" -ne 0 ]; then
        ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete backup sign from <%s> in top level dataset for ZFS BE <%s>'`" "${LU_SIGN_BACKUP}" "$ludb_BE"
        ludb_errors=yes
     fi
   fi

   /bin/rm -f "$ludb_tmp"
   /bin/rm -f "$ludb_tmp1"

   # Now delete the primary
   lulib_delete_from_top_dataset "$ludb_BE" "${LU_SIGN_DIR}/${ludb_sign}" 
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to delete boot signature file <%s> from top level dataset for ZFS BE <%s>'`" "${LU_SIGN_DIR}/${ludb_sign}" "$ludb_BE"
      return 1
   fi

  if [ -z "$ludb_errors" ]; then
     return 0
  else
     return 1
  fi
}

#
# This function is called to install GRUB on the x86 boot partition
#
# Arguments:
#	$1	yes -	Use temp GRUB files in /etc/lu
#		no  -	Use *.findroot GRUB files in /etc/lu
#	$2	yes -   install for both /boot and /stubboot
#		no  -   install only for /stubboot
#
# Returns:
#	0	GRUB sucessfully installed GRUB x86 boot partition
#	1	A fatal error occurred
#
# Local Prefix:  libg
#
lulib_install_boot_GRUB()
{
   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_install_boot_GRUB() only supported on x86'`"
      return 1
   fi

   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: Usage: lulib_install_boot_GRUB yes|no yes|no'`"
      return 1
   fi

   libg_use_tmp="$1"
   libg_dca_boot="$2"

   # Check if the system uses stubboot (GRUB based x86 boot partition)
   libg_bootpart=`/bin/grep -v '^#' /etc/vfstab | /bin/grep "[ 	]/stubboot[ 	]*pcfs[ 	]" | /bin/awk '{print $1}'`
   ret="$?"
   # If we can install to a DCA x86 boot partition, check if it exists
   if [ \( "$ret" -ne 0 -o -z "$libg_bootpart" \) -a "$libg_dca_boot" = yes ]; then
      libg_bootpart=`/bin/grep -v '^#' /etc/vfstab | /bin/grep "[ 	]/boot[ 	]*pcfs[ 	]" | /bin/awk '{print $1}'`
      ret="$?"
   fi
  
   if [ "$ret" -ne 0 -o -z "$libg_bootpart" ]; then
      ${LUPRINTF} -lp1 "`gettext 'System does not have an applicable x86 boot partition'`"
      return 0
   fi

   ${LUPRINTF} -lp1 "`gettext 'Installing GRUB bootloader to x86 boot partition <%s>'`" "$libg_bootpart"

   oldpwd=`/bin/pwd`
   cd "${LU_DIR}"

   libg_bootchr=`/bin/echo "$libg_bootpart" | /bin/sed 's:/dsk/:/rdsk/:g'` 
   if [ "$libg_use_tmp" = yes ]; then
      ./installgrub.tmp.findroot ./stage1.tmp.findroot ./stage2.tmp.findroot "$libg_bootchr"
   else
      ./installgrub.findroot ./stage1.findroot ./stage2.findroot "$libg_bootchr"
   fi
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'installgrub failed for x86 boot partition <%s>'`" "$libg_bootpart"
      cd "$oldpwd"
      return 1
   fi

   cd "$oldpwd"

   return 0
}

#
# This function is called to install GRUB to all BEs
#
# Arguments:
#	$1	yes  - 	Use temp GRUB files in /etc/lu
#		no   -	Use *.findroot GRUB files in /etc/lu
#
#	$2	yes - install to all BEs
#		no  - install only to GRUB BEs
# Returns:
#	0	GRUB sucessfully installed to BEs
#	1	A fatal error occurred
#	2	A non-fatal error occurred
#
# Local Prefix:  luig
#
lulib_install_GRUB()
{

   luig_error="/tmp/.lulib.luig.error.$$"
   luig_tmp="/tmp/.lulib.luig.tmp.$$"
   luig_state="/tmp/.lulib.luig.state.$$"
   luig_resfile="/tmp/.lulib.luig.resfile.$$"

   /bin/rm -f "$luig_error"
   /bin/rm -f "$luig_tmp"
   /bin/rm -f "$luig_state"
   /bin/rm -f "$luig_resfile"

   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_install_GRUB() only supported on x86'`"
      return 1
   fi

   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: Usage: lulib_install_GRUB yes|no'`"
      return 1
   fi

   luig_use_tmp=$1
   luig_all_be=$2

   if [ "$luig_use_tmp" = yes ]; then
      if [ ! -f "${LU_DIR}/installgrub.tmp.findroot" -o ! -f "${LU_DIR}/stage1.tmp.findroot" -o ! -f "${LU_DIR}/stage2.tmp.findroot" ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_install_GRUB: missing binaries '`"
         return 1
      fi
   elif [ "$luig_use_tmp" = no ]; then
      if [ ! -f "${LU_DIR}/installgrub.findroot" -o ! -f "${LU_DIR}/stage1.findroot" -o ! -f "${LU_DIR}/stage2.findroot" ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_install_GRUB: missing binaries '`"
         return 1
      fi
   else
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: Usage: lulib_install_GRUB yes|no'`"
      return 1
   fi

   if [ "$luig_all_be" = no ]; then
      ${LUPRINTF} -lp1 "`gettext 'Installing GRUB bootloader to all GRUB based BEs'`"
   else
      ${LUPRINTF} -lp1 "`gettext 'Installing GRUB bootloader to all BEs'`"
   fi

   ${LUBIN}/lunames_get |
   while read luig_be_name
   do

        status=`${LUETCBIN}/ludo get_be_status_from_be_name "$luig_be_name"`
	if [ "$?" -ne 0 ]; then
	   ${LUPRINTF} -Eelp2 "`gettext 'Failed to get status for BE <%s>. Cannot install GRUB to BE'`" "$luig_be_name"
	   /bin/touch "$luig_error"
	   continue;
	fi

	# Cannot mount an incomplete BE
	[ "$status" != C ] && continue

	# lumount everything except current BE
	if [ "$luig_be_name" != "`/usr/sbin/lucurr`" ]; then 
	   luig_be_mntpt=`lulib_mount -Z "$luig_be_name" "$luig_state"`
	   if [ "$?" -ne 0 -o  -z "$luig_be_mntpt" ]; then
	      ${LUPRINTF} -Eelp2 "`gettext 'Failed to mount BE <%s>. Cannot install GRUB on BE'`" "$luig_be_name"
	      /bin/touch $luig_error
	      /bin/rm -f "$luig_state"
	      continue
	   fi
	else
	   luig_be_mntpt="/"
        fi

	# If not installing to all BEs, don't install GRUB on non-GRUB BEs
	if [ "$luig_all_be" = no ]; then
	   if [ ! -f "/$MULTI_BOOT" -o ! -s "/$MULTI_BOOT" ]; then
	      if [ "$luig_be_mntpt" != / ]; then
	         lulib_umount "$luig_be_name" "$luig_state"
	         if [ "$?" -ne 0 ]; then
	            /bin/touch "$luig_error"
	         else
	            /bin/rm -f "$luig_state"
	         fi
	      fi
	      continue
           fi
	fi

	# Find the physical boot slices for this BE
        lulib_get_be_phys_boot_slices "$luig_be_mntpt" "$luig_tmp"
	if [ "$?" -ne 0 -o ! -f "$luig_tmp" -o ! -s "$luig_tmp" ]; then
	   ${LUPRINTF} -Eelp2 "`gettext 'Cannot find boot slice(s) for BE <%s>. Skipping BE'`" "$luig_be_name"
	   if [ "$luig_be_mntpt" != / ]; then
	      lulib_umount "$luig_be_name" "$luig_state"
           fi
	   /bin/touch $luig_error
	   continue
	fi

        luig_boot_slice_list=`/bin/cat "$luig_tmp"`
	/bin/rm -f "$luig_tmp"

	for i in $luig_boot_slice_list
	do
	    j=`/bin/echo $i | /bin/sed 's:/dsk/:/rdsk/:g'`
	    oldpwd=`/bin/pwd`
	    cd "${LU_DIR}"
	    if [ "$luig_use_tmp" = yes ]; then
	       ./installgrub.tmp.findroot ./stage1.tmp.findroot ./stage2.tmp.findroot $j
	    else
	       ./installgrub.findroot ./stage1.findroot ./stage2.findroot $j
	    fi
	    if [ "$?" -ne 0 ]; then
	       ${LUPRINTF} -Eelp2 "`gettext 'installgrub failed for <%s>'`" "$j"
	       /bin/touch $luig_error
	    fi
	    cd "$oldpwd"
	done

	if [ "$luig_be_mntpt" != / ]; then
	   lulib_umount "$luig_be_name" "$luig_state"
	   if [ "$?" -ne 0 ]; then
	      /bin/touch "$luig_error"
	   else
	      /bin/rm -f "$luig_state"
	   fi
        fi
   done

   lulib_install_boot_GRUB "$luig_use_tmp" "$luig_all_be"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Install GRUB to x86 boot partition failed'`"
      /bin/touch "$luig_error"
   fi
   
   if [ -f "$luig_error" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Install GRUB to all BEs is incomplete'`"
      /bin/rm -f "$luig_error"
      return 2
   fi

   return 0
}

#
# This function gives directions to users to run the one time GRUB menu
# conversion script: /usr/lib/lu/lux86menu_propagate
#
# Arguments:
#	None
#
# Returns:
#	0	No conversion needed
#	1	A conversion needs to be done
#
# Local Prefix:  none
#
lulib_ask_for_menu_propagate()
{

   # This script should only run on x86.

   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'lulib_ask_for_menu_propagate(): This function can only run on x86 systems.'`"
      return 1
   fi

   # If no BEs, nothing to convert
   if [ ! -f ${LU_LUTAB_FILE} -o ! -s ${LU_LUTAB_FILE} ] ; then
      return 0
   fi

   if [ -f "$FINDROOT_INSTALLGRUB" -a -x "$FINDROOT_INSTALLGRUB" -a -f "$FINDROOT_STAGE1" -a -s "$FINDROOT_STAGE1" -a -f "$FINDROOT_STAGE2" -a -s "$FINDROOT_STAGE2" -a -f "${LU_DIR}/GRUB_capability" -a -s "${LU_DIR}/GRUB_capability" ]; then
      ${LUPRINTF} -lp1 "`gettext 'System has findroot enabled GRUB'`"
      return 0
   fi

   if [ -f "$GRUB_CAP" -a -s "$GRUB_CAP" ]; then
      if [ ! -f "$GRUB_slice" ]; then
         /bin/egrep "^findroot$" "$GRUB_CAP" > /dev/null 2>&1
         if [ "$?" -eq 0 ]; then
	    /bin/cp /sbin/installgrub "$FINDROOT_INSTALLGRUB"
	    if [ "$?" -ne 0 ]; then
	       ${LUPRINTF} -Eelp2 "`gettext 'Copy of findroot enabled installgrub failed'`"
	       return 1
	    fi
	    /bin/cp /boot/grub/stage1 "$FINDROOT_STAGE1"
	    if [ "$?" -ne 0 ]; then
	       ${LUPRINTF} -Eelp2 "`gettext 'Copy of findroot enabled stage1 failed'`"
	       /bin/rm -f "$FINDROOT_INSTALLGRUB"
	       return 1
	    fi
	    /bin/cp /boot/grub/stage2 "$FINDROOT_STAGE2"
	    if [ "$?" -ne 0 ]; then
	       ${LUPRINTF} -Eelp2 "`gettext 'Copy of findroot enabled stage2 failed'`"
	       /bin/rm -f "$FINDROOT_INSTALLGRUB"
	       /bin/rm -f "$FINDROOT_STAGE1"
	       return 1
	    fi
	    /bin/cp /boot/grub/capability "${LU_DIR}/GRUB_capability"
	    if [ "$?" -ne 0 ]; then
	       ${LUPRINTF} -Eelp2 "`gettext 'Copy of GRUB capability file failed'`"
	       /bin/rm -f "$FINDROOT_INSTALLGRUB"
	       /bin/rm -f "$FINDROOT_STAGE1"
	       /bin/rm -f "$FINDROOT_STAGE2"
	       return 1
	    fi
	    return 0
         fi
      fi
   fi

   ${LUPRINTF} -f1 "`gettext ' \\nThis system contains only a single GRUB menu for all boot environments. To enhance reliability and improve the user experience, live upgrade requires you to run a one time conversion script to migrate the system to multiple redundant GRUB menus. This is a one time procedure and you will not be required to run this script on subsequent invocations of Live Upgrade commands. To run this script invoke:\\n\\n   /usr/lib/lu/lux86menu_propagate \/path/to/new/Solaris/install/image OR /path/to/LiveUpgrade/patch\\n\\n		where /path/to/new/Solaris/install/image is an absolute path to the Solaris media or netinstall image from which you installed the Live Upgrade packages and /path/to/LiveUpgrade/patch is an absolute path to the Live Upgrade patch from which this Live Upgrade script was patched into the system.\\n '`"

   return 1
}

#
# This function is called to determine if the specified BE is the last BE on a disk
#
# Arguments:
#	$1 	- Name of BE
#
# Returns:
#	0	Not last BE on disk
#	1	Last BE on disk or fatal error occurred.
#
# Local Prefix:  luclb
#
lulib_check_last_BE()
{

   luclb_bootslices="/tmp/.lulib.luclb.bs.$$"
   luclb_disks="/tmp/.lulib.luclb.dsk.$$"
   luclb_found="/tmp/.lulib.luclb.found.$$"
   luclb_error="/tmp/.lulib.luclb.error.$$"
   luclb_state="/tmp/.lulib.luclb.state.$$"

   /bin/rm -f "$luclb_found"
   /bin/rm -f "$luclb_error"
   /bin/rm -f "$luclb_state"

   # This function should only run on x86.
   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_check_last_BE() only supported on x86'`"
      return 1
   fi

   if [ "$#" -ne 1 -o -z "$1" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Usage: lulib_check_last_BE <be-name>'`"
      return 1
   fi

   luclb_del_bename="$1" 

   if [ "$luclb_del_bename" = "`/usr/sbin/lucurr`" ]; then
      # Current BE can never be deleted. As an optimization, proceed no further
      # and pretend this is the last BE on the disk. This is safe because we should
      # never get here - ludelete will bail out before the call to this function
      # takes place.
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: invalid check of current BE <%s>, cannot delete current BE'`" "$luclb_del_bename"
      return 1
   fi

   ${LUBIN}/lunames_get |
   while read luclb_be_name
   do
        status=`${LUETCBIN}/ludo get_be_status_from_be_name "$luclb_be_name"`
	if [ "$?" -ne 0 ]; then
	   ${LUPRINTF} -Eelp2 "`gettext 'Failed to get status for BE <%s>.'`" "$luclb_be_name"
	   /bin/touch "$luclb_error"
	   continue;
	fi

	# Cannot mount an incomplete BE
	[ "$status" != C ] && continue

	# lumount everything except current BE
	if [ "$luclb_be_name" != "`/usr/sbin/lucurr`" ]; then 

	   luclb_be_mntpt=`lulib_mount "$luclb_be_name" "$luclb_state"`
	   if [ "$?" -ne 0 -o  -z "$luclb_be_mntpt" ]; then
	      ${LUPRINTF} -Eelp2 "`gettext 'Failed to mount BE <%s>.'`" "$luclb_be_name"
	      /bin/touch "$luclb_error"
	      /bin/rm -f "$luclb_state"
	      continue
	   fi
	else
	   luclb_be_mntpt="/"
	fi

	luclb_tmp="${luclb_bootslices}.${luclb_be_name}"

	# Find the physical boot slices for this BE
	luclb_boot_error=""
	lulib_get_be_phys_boot_slices "$luclb_be_mntpt" "$luclb_tmp"
	if [ "$?" -ne 0 -o ! -f "$luclb_tmp" -o ! -s "$luclb_tmp" ]; then
	   ${LUPRINTF} -Eelp2 "`gettext 'Cannot find boot slice(s) for BE <%s>.'`" "$luclb_be_name"
	   luclb_boot_error="yes"
	fi

	if [ "$luclb_be_mntpt" != / ]; then
	   lulib_umount "$luclb_be_name" "$luclb_state"
	   if [ "$?" -ne 0 ]; then
	      /bin/touch "$luclb_error"
	   else
	      /bin/rm -f "$luclb_state"
	   fi
	fi

	[ "$luclb_boot_error" = yes ] && continue

	luclb_phys_boot_slice_list=`/bin/cat "$luclb_tmp"`

	/bin/rm -f "$luclb_tmp"

	luclb_tmp="${luclb_bootslices}.${luclb_be_name}"

	for i in $luclb_phys_boot_slice_list
	do
	    /bin/ls -l $i | /bin/sed 's/.*\/devices\//\//g' | sed 's/:.*$//g' >> "$luclb_tmp"
	done

	/usr/bin/sort -u "$luclb_tmp" > "${luclb_disks}.${luclb_be_name}"

	/bin/rm -f "$luclb_tmp"
   done

   luclb_del_list=`/bin/cat "${luclb_disks}.${luclb_del_bename}"`

   for i in $luclb_del_list
   do

	/bin/rm -f "$luclb_found"

	${LUBIN}/lunames_get |
	while read luclb_be_name
	do

	    if [ "$luclb_be_name" = "$luclb_del_bename" ]; then
	       continue;
	    fi

	    /bin/grep "$i" "${luclb_disks}.${luclb_be_name}" > /dev/null 2>&1
	    if [ "$?" -eq 0 ]; then
	       /bin/touch "$luclb_found"
	       break
	    fi
	done

	if [ -f "$luclb_found" ]; then
	   /bin/rm -f "$luclb_found"
	   continue
	fi

	/bin/touch "$luclb_error"

	luclb_devices_p0="../../devices${i}:q"
	luclb_dev_p0=`/bin/ls -l /dev/dsk/*p0 | /bin/nawk -v dev="$luclb_devices_p0" '{ if ($11 == dev) {printf("%s\n", $9); exit 18;}}'`
	if [ "$?" -eq 18 -a -n "$luclb_dev_p0" ]; then
	   luclb_last=`/bin/echo "$luclb_dev_p0" | /bin/sed 's:p0$::g'`
	   ${LUPRINTF} -Eelp2 "`gettext 'Last BE on disk <%s>'`" "$luclb_last"
	else
	   ${LUPRINTF} -Eelp2 "`gettext 'Last BE on disk <%s>'`" "/devices${i}"
	fi
   done


   ${LUBIN}/lunames_get |
   while read luclb_be_name
   do
	/bin/rm -f "${luclb_disks}.${luclb_be_name}"
   done

   /bin/rm -f "$luclb_found"

   if [ -f "$luclb_error" ]; then
      /bin/rm -f "$luclb_error"
      return 1
   fi

   return 0
}

################################################################################
# Name:		lulib_mount
# Description:	Wrapper around lumount that sets up state for cleaning
#		mount-point after unmount of BE
# Local Prefix:	lmt
# Arguments:	$1 = BE name
# Arguments:	$2 = state file
# Returns: 
#		The mountpoint of the BE
#		0 = success.
#		1 = fatal error.
################################################################################
lulib_mount()
{
   lmt_zonefree=
   if [ "x$1" = "x-Z" ]; then
	lmt_zonefree=-Z
	shift
   fi

   if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_mount: Usage: lulib_mount <BEname> <state-file>.'`"
      /bin/echo ""
      return 1
   fi

   lmt_bename="$1"
   lmt_state="$2"

   /bin/rm -f "$lmt_state"

   lmt_bemntpt=`${LUBIN}/lumount $lmt_zonefree "$lmt_bename"`
   if [ "$?" -ne 0 -o  -z "$lmt_bemntpt" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Failed to mount BE <%s>.'`" "$lmt_bename"
      /bin/echo ""
      return 1
   fi

   lmt_log_bdev=`${LUETCBIN}/lurootspec -m "$lmt_bemntpt"`
   if [ "$?" -ne 0 -o -z "$lmt_log_bdev" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine logical block dev for BE<%s>. Cannot reset zfs mountpoint'`" "$lmt_bename"
      ${LUBIN}/luumount -f "$lmt_bename"
      /bin/echo ""
      return 1
   fi

   /bin/echo "$lmt_log_bdev" > "$lmt_state"

   /bin/echo "$lmt_bemntpt"

   return 0
}

################################################################################
# Name:		lulib_umount
# Description:	Wrapper around luumount that cleans up the mountpoint after
#		lumount/luumount of a ZFS BE
# Local Prefix:	lum
# Arguments:	$1 = BE name
# Arguments:	$2 = state file from a lumount
# Returns: 
#		0 = success.
#		1 = fatal error.
################################################################################
lulib_umount()
{
  if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_umount: Usage: lulib_umount <BEname> <state-file>.'`"
     return 1
  fi

  lum_bename="$1"
  lum_state="$2"

  if [ ! -f "$lum_state" -o ! -s "$lum_state" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_umount: missing state file.'`"
     return 1
  fi

  ${LUBIN}/luumount "$lum_bename"
  if [ "$?" -ne 0 ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'lulib_umount: failed to umount BE: <%s>.'`" "$lum_bename"
     return 1
  fi

  # Get root slice for BE
  RSLICE=`${LUETCBIN}/ludo get_root_slice_from_be_name "$lum_bename"`
  if [ "$?" -ne 0 -o -z "$RSLICE" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine root slice for BE<%s>. Cannot reset zfs mountpoint'`" "$lum_bename"
     return 1
  fi

  # Get fstyp for BE
  RFSTYP=`lulib_fstyp "$RSLICE"`
  if [ "$?" -ne 0 -o -z "$RFSTYP" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Cannot determine root fstyp for BE<%s>. Cannot reset zfs mountpoint'`" "$lum_bename"
     return 1
  fi

  if [ "$RFSTYP" != zfs ]; then
     return 0
  fi

  lum_log_bdev=`/bin/cat "$lum_state"`
  zfs list -t filesystem -Ho name,mountpoint -r $lum_log_bdev|awk '$2!="legacy" {print $1}'|
      while read ds_name; do
          zfs inherit mountpoint "$ds_name"
      done
  /sbin/zfs set mountpoint=/ $lum_log_bdev

  return 0
}

################################################################################
# Name:		lulib_validate_media
# Description:	Validate the Solaris media passed in by user
# Local Prefix:	vmd_
# Arguments:	$1 = Path to Solaris install media
# Returns: 
#		0 = success.
#		1 = invalid Solaris media or other fatal error.
################################################################################
lulib_validate_media()
{
  if [ "$LU_SYSTEM_ARCH" != i386 ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_validate_media: This function can only run on x86 systems.'`"
     return 1
  fi

  if [ "$#" -ne 1 -o -z "$1" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_validate_media: invalid arguments.'`"
     return 1
  fi

  vmd_media="$1"
     
  ${LUPRINTF} -lp1 "`gettext 'Validating the contents of the media <%s>.'`" "${vmd_media}"

  lulib_validate_is_directory_not_empty "${vmd_media}"
  if [ "$?" -ne 0 ] ; then
    ${LUPRINTF} -Eelp2 "`gettext '<%s> is not a valid directory.'`" "${vmd_media}"
    return 1
  fi

  # find the media cd table of contents: if not found, not valid media

  vmd_media_cdtoc="${vmd_media}/.cdtoc"
  if [ ! -f "${vmd_media_cdtoc}" -o ! -s "${vmd_media_cdtoc}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The media <%s> is not a recognized installation media.'`" "${vmd_media}"
    return 1
  fi

  ${LUPRINTF} -lp1 "`gettext 'The media is a standard Solaris media.'`"

  # Looks like standard format media with a table of contents;
  # Locate the various subdirectories in the media we expect of a Solaris distribution.

  vmd_errorsFound=""
  vmd_cdtoc_prodname="`/bin/grep '^PRODNAME=' ${vmd_media_cdtoc} | /bin/head -1 | /bin/sed 's/PRODNAME=//'`"
  vmd_cdtoc_prodvers="`/bin/grep '^PRODVERS=' ${vmd_media_cdtoc} | /bin/head -1 | /bin/sed 's/PRODVERS=//'`"
  vmd_cdtoc_proddir="`/bin/grep '^PRODDIR=' ${vmd_media_cdtoc} | /bin/head -1 | /bin/sed 's/PRODDIR=//'`"
  vmd_media_proddir="${vmd_media}/${vmd_cdtoc_proddir}"
  vmd_media_installConfig="${vmd_media}/.install_config"
  vmd_media_toolsDir="`dirname ${vmd_media_proddir}`/Tools"
  vmd_media_bootDir="${vmd_media}/boot"
  vmd_media_grubDir="${vmd_media_bootDir}/grub"
  vmd_media_miniroot="${vmd_media_bootDir}/x86.miniroot"
  vmd_media_multiboot="${vmd_media_bootDir}/multiboot"
  vmd_media_basedir="`dirname ${vmd_media}/${vmd_cdtoc_proddir}`"
  vmd_media_patchdir="${vmd_media_basedir}/Patches"

  ${LUPRINTF} -lp2D - "`gettext 'Product Name <%s> Version <%s>.'`" "${vmd_cdtoc_prodname}" "${vmd_cdtoc_prodvers}"
  ${LUPRINTF} -lp2D - "`gettext 'Product Base Directory <%s>.'`" "${vmd_media_basedir}"
  ${LUPRINTF} -lp2D - "`gettext 'Product Packages Directory <%s>.'`" "${vmd_media_proddir}"
  ${LUPRINTF} -lp2D - "`gettext 'Product Patches Directory <%s>.'`" "${vmd_media_patchdir}"
  ${LUPRINTF} -lp2D - "`gettext 'Install Configuration Directory <%s>'`" "${vmd_media_installConfig}"
  ${LUPRINTF} -lp2D - "`gettext 'Install Tools Directory <%s>.'`" "${vmd_media_toolsDir}" 
  ${LUPRINTF} -lp2D - "`gettext 'Media Boot Directory <%s>.'`" "${vmd_media_bootDir}"
  ${LUPRINTF} -lp2D - "`gettext 'Media GRUB Directory <%s>.'`" "${vmd_media_grubDir}"

  if [ -z "${vmd_cdtoc_prodname}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The media table of contents does not define a product name.'`"
    vmd_errorsFound=1
  fi
  if [ -z "${vmd_cdtoc_prodvers}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The media table of contents does not define a product version.'`"
    vmd_errorsFound=1
  fi
  if [ -z "${vmd_cdtoc_proddir}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The media table of contents does not define a product top-level directory.'`"
    vmd_errorsFound=1
  fi
  if [ ! -d "${vmd_media_installConfig}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The media product install configuration directory <%s> is missing.'`" "${vmd_media_installConfig}"
    vmd_errorsFound="1"
  fi
  if [ -n "${vmd_cdtoc_proddir}" ] ; then
    if [ ! -d "${vmd_media_proddir}" ] ; then
      ${LUPRINTF} -Eelp2 "`gettext 'The media product directory <%s> does not exist.'`" "${vmd_media_proddir}"
      vmd_errorsFound="1"
    fi
    if [ ! -d "${vmd_media_toolsDir}" ] ; then
      ${LUPRINTF} -Eelp2 "`gettext 'The media product tools directory <%s> does not exist.'`" "${vmd_media_toolsDir}"
      vmd_errorsFound="1"
    fi

     if [ "${LU_SYSTEM_ARCH}" = "i386" ]; then
	vmd_media_bootDir="${vmd_media}/boot"

        if [ ! -d "${vmd_media_bootDir}" ] ; then
           ${LUPRINTF} -Eelp2 "`gettext 'The media boot directory <%s> does not exist.'`" "${vmd_media_bootDir}"
           vmd_errorsFound="1"
        fi

        if [ ! -d "${vmd_media_grubDir}" ] ; then
           ${LUPRINTF} -Eelp2 "`gettext 'The media grub directory <%s> does not exist.'`" "${vmd_media_grubDir}"
           vmd_errorsFound="1"
        fi

        if [ ! -f "${vmd_media_miniroot}" -o ! -s "${vmd_media_miniroot}" ] ; then
           ${LUPRINTF} -Eelp2 "`gettext 'The media miniroot <%s> does not exist.'`" "${vmd_media_miniroot}"
           vmd_errorsFound="1"
        fi

        if [ ! -f "${vmd_media_multiboot}" -o ! -s "${vmd_media_multiboot}" ] ; then
           ${LUPRINTF} -Eelp2 "`gettext 'The media multiboot <%s> does not exist.'`" "${vmd_media_multiboot}"
           vmd_errorsFound="1"
        fi
     fi
  fi

  if [ -n "${vmd_errorsFound}" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The media <%s> does not contain a Solaris operating system image.'`" "${vmd_media}"
    return 1
  fi

  ${LUPRINTF} -lp1 "`gettext 'The media contains a Solaris operating system image.'`"

  ${LUPRINTF} -lp1 "`gettext 'The media contains <%s> version <%s>.'`" "${vmd_cdtoc_prodname}" "${vmd_cdtoc_prodvers}"

  return 0
}

###############################################################################
# Name:		lulib_path_writable
# Description:	Check if a given path is a writable directory.
# Arguments:	<path> [mode]
#		<path> is the directory to check
#		[mode] is an optional mode to use in creating the directory
# Returns:	0 - target is writable
#		1 - target is not writable
#		2 - target does not exist and no mode given to create it
# Outputs:	None (save for errors)
###############################################################################
lulib_path_writable()
{
    path_writable_path="$1"
    path_writable_mode="$2"

    # Unfortunately, 'test -w' knows nothing about read-only file
    # systems (only read-only objects), so the only way to check
    # that a path is writable is to write to it.
    if [ -d "$path_writable_path" ]; then
	if touch "$path_writable_path/.lulib" 2>/dev/null; then
	    rm -f "$path_writable_path/.lulib"
	    return 0
	else
	    return 1
	fi
    elif [ -z "$path_writable_mode" ]; then
	return 2
    elif mkdir -p "$path_writable_path" 2>/dev/null; then
	chmod $path_writable_mode "$path_writable_path"
	return 0
    else
	return 1
    fi
}

################################################################################
# lulib_get_root_fstyp_from_icf 
#       returns the file system type of the root file system from the ICF
#       file specified
# Input: $1 = ICF file to check
# RETURN VALUES: Returns fstyp found or "" if failure
################################################################################

lulib_get_root_fstyp_from_icf()
{
	/bin/nawk -F: '$2 == "/" && $6 == "" { printf("%s\n", $4) }' "$1"
}

################################################################################
# lulib_get_root_dataset_from_icf 
#       returns the dataset of the root file system from the ICF
#       file specified
# Input: $1 = ICF file to check
# RETURN VALUES: Returns dataset found or "" if failure
################################################################################

lulib_get_root_dataset_from_icf()
{
	/bin/nawk -F: '$2 == "/" && $6 == "" { printf("%s\n", $3) }' "$1"
}

################################################################################
# lulib_get_root_pool_name_from_icf 
#       returns the pool name of the root file system from the ICF
#       file specified
# Input: $1 = ICF file to check
# RETURN VALUES: Returns pool name found or "" if failure
################################################################################

lulib_get_root_pool_name_from_icf()
{
	path=`/bin/nawk -F: '$2 == "/" && $6 == "" { printf("%s\n", $3) }' "$1"`
	
	#strip off the dataset information and return just the pool name
	echo "$path" | /bin/nawk -F/ '$1 != "" { print $1 }'

}

################################################################################
# Name:		lulib_get_zfs_root_boot_device
# Description:	Given a pool name, return the boot device for that pool.
# Arguments:	$1 = root pool to check (e.g. rpool)
# Example:	lulib_get_zfs_root_boot_device 'rpool'
# Returns:	0 - successful (stdout has name of boot device)
#		1 - unsuccessful (stderr has error message)
################################################################################

lulib_get_zfs_root_boot_device()
{
	if [ ! -x /sbin/zpool ]; then
	   return 1
	fi
	rslt=`get_first_zfs_dev "$1"`
	echo "$rslt"
	return 0
}

################################################################################
# Name:		lulib_get_zfs_filesystem_origin
# Description:	Given a zfs file system return the origin (snapshot from which
#		it was created) if it exists
# Arguments:	$1 = zfs file system to check (e.g. rpool/ROOT/newBE)
# Example:	lulib_get_zfs_filesystem_origin 'rpool/ROOT/newBE'
# Returns:	0 - successful (stdout has name of origin)
#		1 - unsuccessful (stderr has error message)
################################################################################

lulib_get_zfs_filesystem_origin()
{
	[ -x /sbin/zfs ] && /sbin/zfs get -Ho value origin "$1"
}

################################################################################
# Name:		lulib_promote_BE_to_top
# Description:	Given a clone dataset name, promotes it and its children
#		to the top of the pool.  A failure will abort the promotion
#		process.
# Arguments:	$1 = dataset name of clone
# Example:	lulib_promote_BE_to_top 'rpool/ROOT/newBE'
# Returns:	0 - success
#		1 - promotion failed
################################################################################

lulib_promote_BE_to_top()
{
    # find the origin of the clone
    origin="`[ -x /sbin/zfs ] && /sbin/zfs get -Ho value origin \"$1\"`"
    if [ $? != 0 ] || [ "x$origin" = "x-" ]; then
	return 1
    fi

    retval=0	# assume success

    while [ "x$origin" != "x-" ]; do
        # get a list of datasets to promote
        list="`/sbin/zfs get -Hro value name \"$1\"`"
        if [ $? != 0 ]; then
            return 1
        fi
        for dsname in $list; do
            /sbin/zfs promote $dsname 2> /dev/null
	    if [ $? != 0 ]; then
	        retval=1
	    fi
        done
	origin="`/sbin/zfs get -Ho value origin \"$1\"`"
	if [ $? != 0 ] || [ $retval = 1 ]; then
	    retval=1
	    break
        fi
    done

    return $retval
}

################################################################################
# Name:		lulib_demote_and_destroy_dataset
# Description:	Given a dataset, promote any of its dependents and then
#		destroy it.
# Arguments:	$1 = dataset to destroy
# Example:	lulib_demote_and_destroy_dataset 'rpoo/ROOT/oldBE'
# Returns:	0 - success
#		1 - failure
################################################################################

lulib_demote_and_destroy_dataset()
{
	dataset="$1"

	# First, find out if there are any dependents.
	/sbin/zfs list -Ho name -t snapshot -r "$dataset" |
	    while read snapshot; do
		/sbin/zfs destroy "$snapshot" 2>&1 | tail +3 | grep -v '@' |
			xargs -l /sbin/zfs promote
	    done

	# If the dataset was demoted, it's now got an origin
	origin=`lulib_get_zfs_filesystem_origin "$dataset"`

	# We can now destroy the dataset
	/sbin/zfs destroy -r "$dataset"

	# And we can destroy the snapshot the dataset was based off of as well
	if [ "x$origin" != "x-" -a -n "$origin" ]; then
		/sbin/zfs destroy -r "$origin"
	fi
}

################################################################################
# Name:		lulib_get_dataset_type
# Description:	Determines whether the dataset is a snapshot, a filesystem,
#		or a clone of a snapshot.
# Arguments:	$1 = dataset name
# Example:	lulib_get_dataset_type 'rpool/ROOT/newBE'
# Output:	"snapshot" - dataset is a snapshot of another dataset
#		"clone" - dataset is a clone of a snapshot
#		"filesystem" - dataset is neither a clone nor a snapshot
# Returns:	0 - success (result on stdout)
#		1 - failure (result on stderr)
################################################################################

lulib_get_dataset_type()
{
    if [ -x /sbin/zfs ]; then
	    type=`/sbin/zfs get -Ho value type "$1"`
	    if [ $? != 0 ]; then
		return 1
	    fi
	    if [ "$type" = "filesystem" ]; then
		ctype=`/sbin/zfs get -Ho value origin "$1"`
		if [ $? != 0 ]; then
		    return 1
		fi
		if [ "x$ctype" = "x-" ]; then
		    echo "filesystem"
		else
		    echo "clone"
		fi
	    else
		echo "$type"
	    fi
	    return 0
    fi
}

################################################################################
# Name:		lulib_create_be_config_file
# Description:	Create the .BE_CONFIG file for a newly created BE
# Arguments:	$1 = BE name
#		$2 = BE mountpoint
#		$3 = Error String
# Example:	lulib_create_be_config_file newBE /alt.newBE "error"
# Returns:	none
#		If it fails then it will do an exit_script
################################################################################

lulib_create_be_config_file()
{
	BE_NAME=$1
	LU_ALT=$2
	ERR_STRING=$3

	# Determine the ID of the BE we are configuring.
	BE_ID=`${LUETCBIN}/ludo get_be_id "${BE_NAME}" 2>&1`
	if [ "$?" -ne "0" -o -z "${BE_ID}" ] ; then
		${LUPRINTF} -Eelp2 '%s' "${BE_ID}"
		${LUPRINTF} -Eelp2 "`gettext 'Unable to determine BE ID for BE \<%s>: %s.'`" "${BE_NAME}" "${ERR_STR}"
		exit_script 1
	fi

	# Determine the root device for this BE.
	ROOTDEV=`${LUETCBIN}/ludo get_boot_device_from_be_name \
	    "${BE_NAME}" 2>&1`

	# Validate the root device.
	if [ "$?" -ne '0' -o -z "${ROOTDEV}" ] ; then
	    [ -n "${ROOTDEV}" ] && ${LUPRINTF} -Eelp2 '%s' "${ROOTDEV}"
	    ${LUPRINTF} -Eelp2 "`gettext 'Root slice device <%s> for BE <%s> \
was not found: %s.'`" "${ROOTDEV}" "${BE_NAME}" "${ERR_STR}"
	elif [ ! -b "${ROOTDEV}" ] ; then
	    ${LUPRINTF} -Eelp2 "`gettext 'Root slice device <%s> for BE <%s> \
is not a block device: %s.'`" "${ROOTDEV}" "${BE_NAME}" "${ERR_STR}"
	    exit_script 1
	fi

	# Set the BE definition file for the BE just created.
	/bin/rm -f "${LU_ALT}/${LU_BE_CONFIG_FILE}" 2>/dev/null
	${LUPRINTF} +X -a "${LU_ALT}/${LU_BE_CONFIG_FILE}" 'LUBECF_BE_ID=%d\nLUBECF_BE_NAME=%s\nLUBECF_BE_BOOT_DEVICE=%s' "${BE_ID}" "${BE_NAME}" "${ROOTDEV}"
	if [ "$?" -ne "0" ] ; then
	    ${LUPRINTF} -Eelp2 "`gettext 'Unable to configure BE definition on \
ABE <%s>: %s.'`" "${BE_NAME}" "${ERR_STR}"
	   exit_script 1
	fi

	/bin/chmod 444 "${LU_ALT}/${LU_BE_CONFIG_FILE}" 2>/dev/null
}

################################################################################
# Name:		lulib_swap_zvol_defined
# Description:	Determine if the swap zvol is defined for the specified pool
# Arguments:	$1 = ZFS pool name
# Example:	lulib_swap_zvol_defined rpool
# Returns:
#		0 - if the swap zvol doesn't exist
#		1 - otherwise
################################################################################

lulib_swap_zvol_defined()
{
	POOL=$1

	[ -b "/dev/zvol/dsk/${POOL}/swap" ] && return 1
	return 0
}

################################################################################
# Name:		lulib_dump_zvol_defined
# Description:	Determine if the dump zvol is defined for the specified pool
# Arguments:	$1 = ZFS pool name
# Example:	lulib_dump_zvol_defined rpool
# Returns:
#		0 - if the dump zvol doesn't exist
#		1 - otherwise
################################################################################

lulib_dump_zvol_defined()
{
	POOL=$1

	[ -b "/dev/zvol/dsk/${POOL}/dump" ] && return 1
	return 0
}

################################################################################
# Name:		lulib_get_dump_zvol
# Description:	Return the dump zvol name for the specified pool
# Arguments:	$1 = ZFS pool name
# Example:	lulib_get_dump_zvol rpool
# Returns:
#		Name of the dump zvol
################################################################################

lulib_get_dump_zvol()
{
	POOL=$1

	echo "/dev/zvol/dsk/${POOL}/dump"
}

################################################################################
# Name:		lulib_create_swap_zvol
# Description:	Determine if the size required for the swap zvol and create it
# Arguments:	$1 = PBE name
#		$2 = ZFS pool name 
# Example:	lulib_create_swap_zvol currBE rpool
# Returns:
################################################################################

lulib_create_swap_zvol()
{
	PBE_ICF=$1
	POOL=$2
	
	# Get all of the swap entries from the PBE ICF file
	SWAP_SIZE_BLKS=`lulib_get_total_swap_size $PBE_ICF`

	# Determine the swap device size in megabytes
	# The block size is 512 bytes so the computation can be simplified to:
	SWAP_SIZE_MB=`expr $SWAP_SIZE_BLKS '/' 2048`
	SWAP_SIZE_REM=`expr $SWAP_SIZE_BLKS '%' 2048`
	if [ "$SWAP_SIZE_REM" -ne 0 ] ; then
		SWAP_SIZE_MB=`expr $SWAP_SIZE_MB '+' 1`
	fi

	# Create the swap device
	/sbin/zfs create -V "${SWAP_SIZE_MB}m" "${POOL}/swap" 2>${TMP_RESULT_FILE}
	if [ "$?" -ne "0" ] ; then
		[ -s "${TMP_RESULT_FILE}" ] && \
		    ${LUPRINTF} -elp2 '%R' < "${TMP_RESULT_FILE}"
		${LUPRINTF} -Eelp2 "`gettext 'Unable to create swap zvol for \
pool <%s>.'`" "${POOL}"
		exit_script 1
	fi
}

################################################################################
# Name:		lulib_create_dump_zvol
# Description:	Determine if the size required for the dump zvol and create it
# Arguments:	$1 = PBE name
#		$2 = ZFS pool name 
# Example:	lulib_create_dump_zvol currBE rpool
# Returns:
#		0 - if the dump zvol doesn't exist
#		1 - otherwise
################################################################################

lulib_create_dump_zvol()
{
	PBE_NAME=$1
	POOL=$2
	
	CURR_BE="`lulib_lucurr`"

	# Mount the PBE if it's not current
	if [ "$PBE_NAME" = "$CURR_BE" ] ; then
		ROOT_DIR="/"
	else
		ROOT_DIR=`LU_OUTPUT_FORMAT=text $LUBIN/lumount -Z \
		    "${PBE_NAME}" 2>${TMP_RESULT_FILE}`
		if [ "$?" -ne "0" -o -z "${ROOT_DIR}" ] ; then
			[ -s "${TMP_RESULT_FILE}" ] && \
			    ${LUPRINTF} -elp2 '%R' < "${TMP_RESULT_FILE}"
			${LUPRINTF} -Eelp2 "`gettext 'Unable to mount boot \
environment <%s>.'`" "${PBE_NAME}"
			exit_script 1
			fi
	fi

	# Get the PBE dump device size
	DUMP_DEVICE=`LC_ALL=C dumpadm -r "$ROOT_DIR" | grep 'Dump device' |
	    grep '/dev/zvol/' | /bin/awk '{print $3}'`

	# There's a chance the PBE's dump device isn't set up.
	if [ "$DUMP_DEVICE" = "" ]; then
		# Get the dump device for the CBE instead
		DUMP_DEVICE=`LC_ALL=C dumpadm | grep "Dump device" |
		    grep '/dev/zvol/' | /bin/awk '{print $3}'`
	fi

	if [ "${ROOT_DIR}" != "/" ] ; then
		$LUBIN/luumount -f "${PBE_NAME}"
	fi

	# if the PBE defines a dump device, use that size
	DUMP_SIZE_BLKS=0
	if [ -n "$DUMP_DEVICE" ]; then
	    # Get the dump device size in blocks
	    DUMP_SIZE_BLKS="`lulib_get_devsize $DUMP_DEVICE`"
	    if [ $? -ne 0 -o -z "$DUMP_SIZE_BLKS" ] ; then
		${LUPRINTF} -Eelp2 "`gettext 'Unable to determine dump device \
size for boot environment <%s>.'`" "{$PBE_NAME}"
		exit_script 1
	    fi
	fi

	if [ $DUMP_SIZE_BLKS != 0 ]; then
	    # Determine the dump device size in megabytes
	    # The block size is 512 bytes so the computation can be simplified to:
	    DUMP_SIZE_MB=`expr $DUMP_SIZE_BLKS '/' 2048`
	    DUMP_SIZE_REM=`expr $DUMP_SIZE_BLKS '%' 2048`
	    if [ "$DUMP_SIZE_REM" -ne 0 ] ; then
		DUMP_SIZE_MB=`expr $DUMP_SIZE_MB '+' 1`
	    fi
	else
	    # calculate physical memory size
	    mem=`LC_ALL=C /usr/sbin/prtconf | /bin/grep '^Memory size:'`
	    mag=`echo $mem | /bin/awk '{print $3}'`
	    units=`echo $mem | /bin/awk '{print $4}' | /bin/cut -c1 |
	        /bin/tr '[a-z]' '[A-Z]'`

	    # If the units of the prtconf output are in megabytes, then
	    # we use half physical memory as a starting point.  Otherwise,
	    # we assume it's "G" or more, and limit the dump size to 2GB.
	    if [ "$units" = "M" ]; then
	        DUMP_SIZE_MB=`expr $mag / 2`

		# ensure it's in range
		if [ "$DUMP_SIZE_MB" -gt 2048 ]; then
			DUMP_SIZE_MB=2048
		elif [ "$DUMP_SIZE_MB" -lt 512 ]; then
			DUMP_SIZE_MB=512
		fi
	    else
		DUMP_SIZE_MB=2048
	    fi

	fi

	DUMP_SIZE_ARG="${DUMP_SIZE_MB}m"

	# Create the dump device
	/sbin/zfs create -o volblocksize=128k -V "$DUMP_SIZE_ARG" "${POOL}/dump" 2>${TMP_RESULT_FILE}
	if [ "$?" -ne "0" ] ; then
		[ -s "${TMP_RESULT_FILE}" ] && \
		    ${LUPRINTF} -elp2 '%R' < "${TMP_RESULT_FILE}"
		${LUPRINTF} -Eelp2 "`gettext 'Unable to create dump zvol of \
size <%s> for pool <%s>.'`" "${DUMP_SIZE_ARG}" "${POOL}"
		exit_script 1
	fi
}

################################################################################
# Name:		lulib_get_total_swap_size
# Description:	Return the total swap size as specified in the input BE ICF file
# Arguments:	$1 = PBE ICF
# Example:	lulib_get_total_swap_size currBE
# Returns:
#		Total swap size in blocks
################################################################################

lulib_get_total_swap_size()
{
	PBE_ICF=$1
	total_swap=`nawk -F: '$4 == "swap" { total_swap += $5 }
	    END { print total_swap }' $PBE_ICF`

	# ensure we got an answer, and it's at least 512mb
	if [ "$total_swap" = "" ] || [ "$total_swap" -lt 1048576 ]; then
	    total_swap=1048576
	fi
	
	echo $total_swap
}

################################################################################
# Name:         lulib_clone_BE_dataset
# Description:  Snapshot/clone the specified dataset.
# Arguments:    $1 = zfs dataset to clone (e.g. rpool/ROOT/newBE)
#		$2 = ABE name 
#		$3 = cloned dataset name
# Example:      lulib_clone_BE_dataset rpool/zones/z1 newBE rpool/zones/z1_newBE
# Returns:      0 - successful
#               1 - unsuccessful
################################################################################
lulib_clone_BE_dataset()
{
	src_dataset=$1
	abe_name=$2
	dest_dataset=$3

	# Snapshot the dataset
	snapshot_name=${src_dataset}@${abe_name}
	COMMAND="/sbin/zfs snapshot ${snapshot_name}"
	${LUPRINTF} -lp2D - \
	    "`gettext 'Executing ZFS snapshot command: <%s>.'` " "$COMMAND"
	${LUPRINTF} -lp1 \
	    "`gettext 'Creating snapshot for <%s> on <%s>.'`" \
	    $src_dataset $snapshot_name

	ERRMSG="`/sbin/sh -c \"$COMMAND\" 2>&1`"

	if [ $? -ne 0 ]; then
		${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
		${LUPRINTF} -Eelp2 \
		    "`gettext 'Unable to snapshot <%s> on <%s>.'`" \
		    $src_dataset $snapshot_name
		return 1
	fi
	${LUPRINTF} -lp2D - '%s' "${ERRMSG}"


	# Ensure that the clone-to-be's parent exists
	ds_parent=`/usr/bin/dirname $dest_dataset`
	lulib_dataset_exists $ds_parent
	if [ $? = 0 ]; then
		/sbin/zfs create -p -o canmount=noauto $ds_parent
	fi

	# Clone the dataset
	COMMAND="/sbin/zfs clone ${snapshot_name} $dest_dataset"
	${LUPRINTF} -lp2D - \
	    "`gettext 'Executing ZFS clone command: <%s>.'` " "$COMMAND"
	${LUPRINTF} -lp1 \
	    "`gettext 'Creating clone for <%s> on <%s>.'`" \
	    $snapshot_name $dest_dataset

	ERRMSG="`/sbin/sh -c \"$COMMAND\" 2>&1`"

	if [ $? -ne 0 ]; then
		${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
		${LUPRINTF} -Eelp2 "`gettext 'Unable to clone <%s> on <%s>.'`"
		    $snapshot_name $dest_dataset
		return 1
	fi
	${LUPRINTF} -lp2D - '%s' "${ERRMSG}"

	lulib_dataset_mounted $dest_dataset
	if [ $? -eq 1 ] ; then
		/sbin/zfs umount $dest_dataset
	fi

	src_mntprop=`/sbin/zfs get -Ho value mountpoint "${src_dataset}"`
	if [ $src_mntprop = "legacy" ] ; then
		/sbin/zfs set mountpoint=legacy "${dest_dataset}"
	else
        	# For the ABE, set the mountpoint to be inherited from the PBE
        	src_mountpoint=`/sbin/zfs get -Ho value mountpoint $src_dataset`
        	if [ $src_mountpoint != "/" ]; then

                    # check if the file lu_moved is present in the source BE
                    # this file contains the name of the BE or the suffix to be used
                    # if present, then get the suffix name and use it to create the
                    # dataset as well as the mountpoint by swapping the BE names
                    if [ -f "$src_mountpoint/lu_moved" ]; then
                        pbesuffix=`cat $src_mountpoint/lu_moved"`
                        abe_ds=`echo $src_dataset | 
				sed "s/$pbesuffix"'$//;s/$/'"$abe_name/"`
                        abe_mountpoint=`echo $src_mountpoint | 
				sed "s/$pbesuffix"'$//;s/$/'"$abe_name/"`

                    # else append the ABE name to the datset and mountpoint
                    else
                        abe_ds="$src_dataset-$abe_name"
                        abe_mountpoint="$src_mountpoint-$abe_name"
                    fi

                    # Finally, set the mountpoint for the dataset 
                    if [ $dest_dataset = $abe_ds ]; then
                        /sbin/zfs set mountpoint=$abe_mountpoint $dest_dataset
                    fi
		fi
        fi

	return 0

}

################################################################################
# Name:         lulib_get_zfs_dataset_from_mntpt
# Description:  Given a zfs mount point return the dataset name.  Assumes that
#		the dataset is mounted.
# Arguments:    $1 = zfs file system mount point (e.g. /rpool/ROOT/newBE)
# Example:      lulib_get_zfs_dataset_from_mntpt '/rpool/ROOT/newBE'
# Outputs:	The dataset name associated with the mountpoint
################################################################################
lulib_get_zfs_dataset_from_mntpt()
{
	if [ ! -x /sbin/zfs ]; then
		return
	fi

	# handle the easy case first

        # To get the appropriate dataset, we loop through the /etc/mnttab and
        # extract the correct dataset

        # if the 3rd field is "zfs" in /etc/mnttab
        # check if the mountpoint is same as the passed argument,
        # then store the result and no further entries of /etc/mnttab needs
        # to be read and jump to END block (This is the case when the
        # source BE is same as the current BE)

        # if the source BE is different than current BE (lucreate -s option)
        # then the etc/mnttab will have entries like below. Note that the extra
        # entry of "lofs" gets created when lumount is called for the BE
        # which is not the current running BE. Therefore we cannot directly get
        # the value of dataset as done in previous case.
        #
        # zone7azr/zone7aroot-NEW_BE  /local/zones/zone7a-NEW_BE           zfs
        # /local/zones/zone7a-NEW_BE  /.alt.tmp/local/zones/zone7a-NEW_BE  lofs
        #
        # For such case, create a (mountpoint,dataset) pair & store it in array
        # the index of this array would contain the mountpoint name and dataset
        # would be the value at that index.
        #
        # then check for the lofs mount, if the 2nd field is same as the passed
        # argument, store it to be used as index afterwards.
        #
        # Finally, get the value of the dataset either from the result
        # OR
        # get the value from the array by using lookup as the index

        source=`/bin/nawk -v DIR="$1" '$3 == "zfs" {
                if ($2 == DIR) { result=$1; exit; }
                loc[$2] = $1
        }

        $3 == "lofs" {
                if ($2 == DIR) { lookup=$1; }
        }

        END {
                if (lookup != "") { print loc[lookup] }
                else if (result != "") { print result; }
        }' /etc/mnttab`

	if [ -n "$source" ]; then
		lcldataset=`/sbin/zfs get -Ho name name "$source" 2> /dev/null`
		if [ "$lcldataset" = "$source" ]; then
			echo "$source"
			return 0
		fi
	fi

	# strip off the double // if it exists
	nodub=`echo "$1" | sed -e 's+//+/+g'`

	# the first part may or may not have a trailing /
	topbn=/`echo "$1" | cut -d/ -f2`

	# the rest won't
	restbn=`echo "$1" | cut -d/ -f3-`

	# If there is no "rest", then we don't need to add it on
	if [ "$restbn" = "" ]; then
		sstring1="$topbn"
		sstring2="$topbn/"
	else
		sstring1="$topbn/$restbn"
		sstring2="$topbn//$restbn"
	fi
	/sbin/zfs mount | /usr/bin/nawk -v MP="$sstring1" -v MPS="$sstring2" \
	    '$2 == MP { print $1 }
	    $2 == MPS { print $1 }'
}

################################################################################
# Name:         lulib_dataset_exists
# Description:  Determine if the specified dataset exists
# Arguments:    $1 = zfs dataset
# Example:      lulib_dataset_exists rpool/zones/z1
# Returns:      0 - dataset does not exist
#               1 - dataset does exist
################################################################################
lulib_dataset_exists()
{
	if [ -x /sbin/zfs ]; then
		/sbin/zfs list -Ho name "$1" >/dev/null 2>&1
		if [ $? -ne 0 ] ; then
			return 0
		fi
		return 1
	else
		return 0
	fi
}

################################################################################
# Name:         lulib_dataset_mounted
# Description:  Determine if the specified dataset is mounted
# Arguments:    $1 = zfs dataset
# Example:      lulib_dataset_mounted rpool/zones/z1
# Returns:      0 - dataset is not mounted
#               1 - dataset is mounted
################################################################################
lulib_dataset_mounted()
{
	if [ -x /sbin/zfs ]; then
		is_mounted=`/sbin/zfs get -Ho value mounted $1`
		if [ $? -ne 0 -o "$is_mounted" = "no" ] ; then
			return 0
		fi
		return 1
	else
		return 0
	fi
}

################################################################################
# Name:         lulib_destroy_BE_dataset
# Description:  Destroy the specified dataset and the snapshot that it was
#		created from if it exists
# Arguments:    $1 = zfs dataset to destroy
# Example:      lulib_destroy_be_dataset rpool/zones/z1
# Returns:      0 - successful
#               1 - unsuccessful
################################################################################
lulib_destroy_BE_dataset()
{
	dataset=$1

	origin=`lulib_get_zfs_filesystem_origin $dataset`

        # Destroy the dataset
        COMMAND="/sbin/zfs destroy -r ${dataset}"
        ${LUPRINTF} -lp2D - \
            "`gettext 'Executing ZFS destroy command: <%s>.'` " "$COMMAND"
        ${LUPRINTF} -lp1 \
            "`gettext 'Deleting ZFS dataset <%s>.'`" $dataset

        ERRMSG="`/sbin/sh -c \"$COMMAND\" 2>&1`"

        if [ $? -ne 0 ]; then
                ${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
                ${LUPRINTF} -Eelp2 \
                    "`gettext 'Unable to delete ZFS dataset <%s>.'`" $dataset
                return 1
        fi
        ${LUPRINTF} -lp2D - '%s' "${ERRMSG}"

	# Destroy the snapshot that the dataset was created from if it exists
	if [ "$origin" != "-" -a "$origin" != "" ] ; then
		COMMAND="/sbin/zfs destroy -r ${origin}"
		${LUPRINTF} -lp2D - "`gettext \
		    'Executing ZFS destroy command: <%s>.'` " "$COMMAND"
		${LUPRINTF} -lp1 \
		    "`gettext 'Deleting ZFS snapshot <%s>.'`" $origin

		ERRMSG="`/sbin/sh -c \"$COMMAND\" 2>&1`"

		if [ $? -ne 0 ]; then
			${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
			${LUPRINTF} -Eelp2 \ "`gettext \
			    'Unable to delete ZFS snapshot <%s>.'`" $origin
			return 1
		fi
		${LUPRINTF} -lp2D - '%s' "${ERRMSG}"
	fi

	return 0
}

###############################################################################
# Name:		lulib_list_nonshared_zones
# Description:	Get a parseable list of the zones installed in a given
#		boot environment with root on filesystem not shared between BEs.
# Arguments:	[flags] <be-root> <pbe_icf> <abe_icf>
#		Flags are those accepted for "zoneadm list"; documented as
#		[list_options] in zoneadm(1M).  The expected options here are
#		"-i", "-c" or no option at all.
#		<be_root> is the path to the boot environment root.
#               <pbe_icf> is path to source BE ICF file 
#               <abe_icf> is path to alternate BE ICF file 
# Returns:	None
# Outputs:	List zone data in "zoneadm list -p" (parseable) format.
###############################################################################
lulib_list_nonshared_zones()
{
    list_zones_flags=
    case "$1" in
	-*)
	    list_zones_flags="$list_zones_flags $1"
	    shift
	    ;;
    esac
    list_zones_rootdir="$1"
    if [ -z "$1" ]; then
	list_zones_rootdir=/
    fi

    pbe_icf="$2"
    abe_icf="$3"

    SAVEIFS_NBZ="$IFS"

    # Parsing list of zones which are in
    # state "running" or "ready"
    lulib_list_zones $list_zones_flags $list_zones_rootdir |
    while IFS=: read zoneid zonename state path junk; do
	IFS="$SAVEIFS_NBZ"

	# get mountpoint for zone root filesystem
	zone_mp=`df $path | nawk '{ print $1 }'`

	# Parse list of mount points shared between
	# source and alternate BEs and compare them
	# to mountpoint of zone root filesystem
	$LUETCBIN/ludo filter_shared $pbe_icf $abe_icf |
	    egrep -s "^[^:]+:$zone_mp:"

	if [ $? -eq 0 ] ; then
	    $LUPRINTF -lp2D - "`gettext \
	      'Root of zone <%s> is on non-shared fs'`" $zonename
	fi
    done
}

################################################################################
# Name:		lulib_list_zone_datasets
# Description:	List all the datasets that are the zone roots for zones in
#		the specified BE
# Local Prefix:	n/a
# Arguments:	$1 = The BE to search
# Returns:	A list of datasets
################################################################################
lulib_list_zone_datasets()
{
	LC_ALL=C /sbin/zfs list -Ho name -t filesystem |
		grep -v 'no datasets available' |
		xargs /sbin/zfs get -Ho name,value zpdata:rbe 2> /dev/null |
		nawk -v BE="$1" '$2 == BE {print $1}'
}

################################################################################
# Name:		lulib_elide_bootadm_entries
# Description:	Remove all bootadm controlled entries (except bootenv.rc and
#		and transient boot entries)
# Local Prefix:	ebe_
# Arguments:	$1 = The GRUB menu to be modified
# Returns: 
#		0 = success.
#		1 = fatal error
################################################################################
lulib_elide_bootadm_entries()
{
   ebe_preserve="/tmp/.lulib.ebe.preserve.$$"
   ebe_res="/tmp/.lulib.ebe.res.$$"
   ebe_tmp="/tmp/.lulib.ebe.tmp.$$"
   ebe_state="/tmp/.lulib.ebe.state.$$"
   ebe_menu_tmp="/tmp/.lulib.ebe.menu.$$"

   /bin/rm -f "$ebe_preserve"
   /bin/rm -f "$ebe_res"
   /bin/rm -f "$ebe_tmp"
   /bin/rm -f "$ebe_state"
   /bin/rm -f "$ebe_menu_tmp"

   if [ "$LU_SYSTEM_ARCH" != i386 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_elide_bootadm_entries: This function can only run on x86 systems.'`"
      return 1
   fi

   if [ "$#" -ne 1 -o -z "$1" ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_elide_bootadm_entries: Usage: lulib_elide_bootadm_entries <GRUB-menu>.'`"
      return 1
   fi

   ebe_menu="$1"

   
   # We may be called from a DCA BE, so it is normal to have a missing menu
   if [ ! -f "$ebe_menu" -o ! -s "$ebe_menu" ]; then
      ${LUPRINTF} -lp1 "`gettext 'Skipping elide of bootadm entries: Non-existent or zero length GRUB menu.'`"
      return 0
   fi

   # Check that we have at least 1 live upgrade menu in the GRUB menu
   # before eliding bootadm entries
   if /bin/grep "$BOOT_MENU_HDR_SUFFIX" "$ebe_menu" > /dev/null 2>&1; then
      :
   else
      ${LUPRINTF} -lp1 "`gettext 'Skipping elide of bootadm entries: No Live Upgrade entries.'`"
      return 0
   fi

   /bin/cp -p "$ebe_menu" "$ebe_menu_tmp"

   lulib_save_default "$ebe_menu_tmp" "$ebe_state"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot save default. Cannot elide bootadm entries from GRUUB menu'`"
      /bin/rm -f "$ebe_menu_tmp"
      /bin/rm -f "$ebe_state"
      return 1
   fi

   ebe_blank=""
   ebe_error=""
   while true
   do
      starts=`/usr/bin/awk "/^$BOOTADM_HDR\$/ {print NR }" "$ebe_menu_tmp"` 
      if [ -z "$starts" ]; then
         ebe_blank=yes
      fi

      stops=`/usr/bin/awk "/^$BOOTADM_FTR\$/ {print NR }" "$ebe_menu_tmp"` 
      if [ -z "$stops" ]; then
         if [ "$ebe_blank" = yes ]; then
            ${LUPRINTF} -lp1 "`gettext 'No more bootadm entries. Deletion of bootadm entries is complete.'`"
	    break;
         fi
         ${LUPRINTF} -Eelp2 "`gettext 'bootadm header present but not footer.'`"
	 ebe_error=yes
	 break
      fi

      if [ "$ebe_blank" = yes ]; then
         ${LUPRINTF} -Eelp2 "`gettext 'bootadm header absent but footer is present.'`"
	 ebe_error=yes
         break
      fi

      while true
      do
         startval=`/bin/echo $starts | /bin/cut -d " " -f 1`
         stopval=`/bin/echo $stops | /bin/cut -d " " -f 1`
         if [ -z "$startval" -a -z "$stopval" ]; then
            ${LUPRINTF} -lp1 "`gettext 'Deletion of bootadm entries is complete.'`"
	    break 2
         fi
         if [ -z "$startval" -a -n "$stopval" ]; then
            ${LUPRINTF} -Eelp2 "`gettext 'bootadm header absent but footer is present at line $stopval.'`"
	    ebe_error=yes
	    break 2
         fi
         if [ -n "$startval" -a -z "$stopval" ]; then
            ${LUPRINTF} -Eelp2 "`gettext 'bootadm header present at line $startval but not footer.'`"
	    ebe_error=yes
	    break 2
         fi

         /bin/nawk -v "hdr=$startval" -v "ftr=$stopval" "NR >= hdr && NR <= ftr {print}" "$ebe_menu_tmp" > "$ebe_tmp"
         /bin/nawk -v "hdr=$startval" -v "ftr=$stopval" "NR < hdr || NR > ftr {print}" "$ebe_menu_tmp" > "$ebe_res"

         /bin/cp -p "$ebe_res" "$ebe_menu_tmp"

         /bin/grep "$BOOTADM_BOOTENV" "$ebe_tmp" > /dev/null 2>&1
         ret1="$?"
         /bin/grep "$BOOTADM_TRANSIENT" "$ebe_tmp" > /dev/null 2>&1
         ret2="$?"

         if [ "$ret1" -eq 0 -o "$ret2" -eq 0 ]; then
            /bin/cat "$ebe_tmp" >> "$ebe_preserve"
         fi
         break
      done
   done

   if [ "$ebe_error" = yes ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'One or more errors encountered. Cannot elide bootadm entries from GRUB menu'`"
      /bin/rm -f "$ebe_preserve"
      /bin/rm -f "$ebe_res"
      /bin/rm -f "$ebe_tmp"
      /bin/rm -f "$ebe_state"
      /bin/rm -f "$ebe_menu_tmp"
      return 1
   fi

   if [ -f "$ebe_preserve" -a -s "$ebe_preserve" ]; then
      /bin/cat "$ebe_preserve" >> "$ebe_menu_tmp"
   fi
   /bin/rm -f "$ebe_preserve"
   /bin/rm -f "$ebe_res"
   /bin/rm -f "$ebe_tmp"

   lulib_restore_default "$ebe_menu_tmp" "$ebe_state"
   if [ "$?" -ne 0 ]; then
      ${LUPRINTF} -Eelp2 "`gettext 'Cannot restore default. Cannot elide bootadm entries from GRUB menu'`"
      /bin/rm -f "$ebe_menu_tmp"
      /bin/rm -f "$ebe_state"
      return 1
   fi

   /bin/rm -f "$ebe_state"

   /bin/cp -p "$ebe_menu_tmp" "$ebe_menu"

   /bin/rm -f "$ebe_menu_tmp"

   ${LUPRINTF} -lp1 "`gettext 'Done eliding bootadm entries.'`"

   return 0
}

################################################################################
# Name:		lulib_save_default
# Description:	Record the current position of the default and save it in the
#		state file passed in
# Local Prefix:	lsa_
# Arguments:	$1 = The GRUB menu
#		$2 = state file
# Returns: 
#		0 = success.
#		1 = fatal error
################################################################################
lulib_save_default()
{
  if [ "$LU_SYSTEM_ARCH" != i386 ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_save_default: This function can only run on x86 systems.'`"
     return 1
  fi

  if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_save_default: Usage: lulib_save_default <GRUB-menu> <state-file>.'`"
     return 1
  fi

  lsa_menu="$1"
  lsa_state="$2"

  /bin/rm -f "$lsa_state"

  if [ ! -f "$lsa_menu" -o ! -s "$lsa_menu" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'lulib_save_default: Non-existent or zero length GRUB menu.'`"
     return 1
  fi

  #
  # First derive and copy the default entry title
  #
  deftitle=""
  defcmd_line=`/bin/egrep -v "^[ 	]*#" $lsa_menu | /bin/egrep "^[ 	]*${LU_GRUB_DEFAULT_CMD}[ 	=]+[-]*[0-9]+[ 	]*"`
  if [ -n "${defcmd_line}" ]; then
     /bin/echo "$defcmd_line" | /bin/grep '=' > /dev/null 2>&1
     if [ "$?" -eq 0 ]; then
        grub_defcmd_value=`/bin/echo "$defcmd_line" | /bin/cut -d '=' -f 2`
     else
        grub_defcmd_value=`/bin/echo "$defcmd_line" | /usr/bin/awk '{ print $2 }'`
     fi 

     if [ -n "$grub_defcmd_value" -a "$grub_defcmd_value" -ge 0 ]; then
        ${LUPRINTF} -lp2D - "`gettext 'Current GRUB menu default setting is <%s>'`" "${grub_defcmd_value}"
        # Adjust GRUB value (starts from 0) to actual value
        default=`/bin/expr "${grub_defcmd_value}" + 1`

        deftitle=`/bin/egrep -v "^[ 	]*#" $lsa_menu | /bin/egrep "^[ 	]*${LU_GRUB_TITLE_CMD}[ 	=]+" | /bin/nawk -v defnum="$default" ' { if (NR == defnum) {printf("%s\n", $0); exit 9;}}'`
        if [ "$?" -eq 9 -a -n "$deftitle" ]; then
           ${LUPRINTF} -lp2D - "`gettext 'Extracted default GRUB title'`"
           /bin/echo "$deftitle" > "$lsa_state"
	else
           ${LUPRINTF} -lp1 "`gettext 'Current GRUB menu default setting is not valid'`"
        fi
     else
        ${LUPRINTF} -Eelp2 "`gettext 'Cannot derive value of default setting'`"
     fi
   else
      ${LUPRINTF} -lp1 "`gettext 'GRUB menu has no default setting'`"
   fi
   
   return 0
} 

################################################################################
# Name:		lulib_restore_default
# Description:	Restore the current default from the saved value in the state file
# Local Prefix:	lrst_
# Arguments:	$1 = The GRUB menu
#		$2 = state file
# Returns: 
#		0 = success.
#		1 = fatal error
################################################################################
lulib_restore_default()
{

  lrst_tmp="/tmp/.lulib.lrst.tmp.$$"

  /bin/rm -f "$lrst_tmp"

  if [ "$LU_SYSTEM_ARCH" != i386 ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_restore_default: This function can only run on x86 systems.'`"
     return 1
  fi

  if [ "$#" -ne 2 -o -z "$1" -o -z "$2" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'Internal error: lulib_restore_default: Usage: lulib_restore_default <GRUB-menu> <state-file>.'`"
     return 1
  fi

  lrst_menu="$1"
  lrst_state="$2"

  if [ ! -f "$lrst_menu" -o ! -s "$lrst_menu" ]; then
     ${LUPRINTF} -Eelp2 "`gettext 'lulib_restore_default: Non-existent or zero length GRUB menu.'`"
     return 1
  fi

  if [ -f "$lrst_state" -a -s "$lrst_state" ]; then
     deftitle=`/bin/cat "$lrst_state"`
  else
     deftitle=""
  fi

  # Now update the value of the default command
  if [ -n "$deftitle" ]; then
     new_default=`/bin/egrep -v "^[ 	]*#" $lrst_menu | /bin/egrep "^[ 	]*${LU_GRUB_TITLE_CMD}[ 	=]+" | /bin/nawk -v "line=$deftitle" ' { if ($0 == line) { print NR }} '`

     # "new_default" will either be an empty string or an integer
     if [ -z "$new_default" ]; then
        new_grub_default=0
     elif [ "$new_default" -lt 1 ]; then
        new_grub_default=0
     else
        new_grub_default=`/bin/expr "$new_default" - 1`
     fi

     grub_defcmd_value=""
     defcmd_line=`/bin/egrep -v "^[ 	]*#" $lrst_menu | /bin/egrep "^[ 	]*${LU_GRUB_DEFAULT_CMD}[ 	=]+[-]*[0-9]+[ 	]*"`
     if [ -n "${defcmd_line}" ]; then
        /bin/echo "$defcmd_line" | /bin/grep '=' > /dev/null 2>&1
        if [ "$?" -eq 0 ]; then
           grub_defcmd_value=`/bin/echo "$defcmd_line" | /bin/cut -d '=' -f 2`
        else
           grub_defcmd_value=`/bin/echo "$defcmd_line" | /usr/bin/awk '{ print $2 }'`
        fi 
     fi


     if [ "$new_grub_default" -ne "$grub_defcmd_value" ]; then
        ${LUPRINTF} -lp1 "`gettext 'Changing GRUB menu default setting to <%s>'`" "$new_grub_default"
        /bin/egrep -v "^[ 	]*${LU_GRUB_DEFAULT_CMD}[ 	=]+[-]*[0-9]+[ 	]*" "$lrst_menu" > "$lrst_tmp"
        /bin/echo "$LU_GRUB_DEFAULT_CMD" "$new_grub_default" > "$lrst_menu"
        /bin/cat "$lrst_tmp" >> "$lrst_menu"
        /bin/rm -f "$lrst_tmp"
     else
        ${LUPRINTF} -lp1 "`gettext 'GRUB menu default setting is unaffected'`"
     fi
   else
     ${LUPRINTF} -lp1 "`gettext 'GRUB menu default setting is unchanged'`"
   fi

   return 0
}

################################################################################
# Name:		lulib_copy_zone
# Description:	Restore the current default from the saved value in the state file
# Local Prefix:	lcz_
# Arguments:	$1 = zone name
#		$2 = PBE mountpoint
#		$3 = PBE name
#		$4 = ABE mountpoint
#		$5 = ABE name
#		$6 = ABE icf
# Returns: 
#		0 = success.
#		1 = fatal error
################################################################################
lulib_copy_zone_to_dataset()
{
    lcz_zone="$1"
    lcz_pbemnt="$2"
    lcz_pbename="$3"
    lcz_abemnt="$4"
    lcz_abename="$5"
    lcz_abeicf="$6"

    echo "$lcz_abename" > "$lcz_abemnt/etc/zones/lu_suffix"

    lcz_parentds=`lulib_get_zfs_dataset_from_mntpt $lcz_abemnt`
    lcz_zoneparent="$lcz_parentds/zoneds"

    lulib_dataset_exists "$lcz_zoneparent"
    if [ $? = 0 ]; then
	/sbin/zfs create -o canmount=noauto "$lcz_zoneparent"
    fi

    SAVEIFS="$IFS"
    zoneadm -z "$lcz_zone" list -p |
    while IFS=: read zoneid zonename state path uuid junk; do
	IFS="$SAVEIFS"

	newpath=`echo "$lcz_abemnt/zoneds/$zonename-$lcz_abename" | sed 's+//+/+g'`

	zonecfg -R "$lcz_abemnt" -z $zonename set -F zonepath="$newpath"
	if [ $? != 0 ]; then
	    $LUPRINTF -Eelp2 "`gettext 'Unable to set zonepath to <%s> for zone <%s>'`" "$newpath" "$zonename"
	    return
	fi

	lcz_dataset="$lcz_zoneparent/$zonename-$lcz_abename"
	$LUPRINTF -lp2 "`gettext 'Creating dataset <%s> for zone <%s>'`" "$lcz_dataset" "$zonename"
	/sbin/zfs create -o canmount=noauto "$lcz_dataset"
	/sbin/zfs mount "$lcz_dataset"
	if [ $? = 0 ]; then
		newrawpath=`/sbin/zfs get -Ho value mountpoint "$lcz_dataset"`

		/sbin/zfs set zpdata:zn="$zonename" "$lcz_dataset"
		/sbin/zfs set zpdata:rbe="$lcz_abename" "$lcz_dataset"

		$LUPRINTF -lp2 "`gettext 'Copying root of zone <%s>.'`" \
		    $zonename

		chmod 700 "$newrawpath"
		echo "$lcz_abename" > "$newrawpath/lu_moved"

		# The use of 'while' here facilitates the use of subshell
		# variables and deal with zoneadm failures.  The actual loop
		# executes at most once.
		SAVEIFS="$IFS"
		zoneadm -R "$lcz_pbemnt" -z $zonename -u "$uuid" list -p |
		while IFS=: read ozoneid ozonename ostate oldpath junk; do
		    IFS="$SAVEIFS"

		    if [ "$ostate" = mounted ]; then
			zroot=/a
		    elif [ "$ostate" = running ]; then
			zroot=
		    elif [ "$ostate" = installed ]; then
		        if [ $lcz_pbemnt = "/" ]; then
		            zoneadm -R "$lcz_pbemnt" -z $zonename mount
			    if [ $? -eq 0 ]; then
		                zroot=/a
			        ostate="mounted"
			        lcz_mountednow="yes"
			    fi
			fi
		        if [ $ostate = installed ]; then
			    $LUPRINTF -Eelp2 \
			        "`gettext 'Zone <%s> in BE <%s> is in <%s> state.'`" \
			        $ozonename "$lcz_pbename" $ostate
			    /usr/sbin/zoneadm -R "$lcz_abemnt" -z $zonename \
			        mark incomplete
			    continue
			fi
		    fi

		    # Make sure some famous things get set up first.
		    for dir in etc/svc/volatile proc \
			system/contract system/object tmp
		    do
			mkdir -p "$newrawpath/root/$dir"
		    done
		    touch "$newrawpath/root/etc/mnttab"

		    # Compute the list of lofs mount points within the zone,
		    # relative to the zone root.  We must do this because the
		    # find(1) -xdev option doesn't (and can't) skip over lofs
		    # mounts.  It will instead descend into them and cause a
		    # space explosion.
		    excl=/tmp/lulib.zcopy.exclude.$$
		    mount -p | while read device raw mntpt fstype junk; do
			[ $fstype = lofs ] || continue
			subdir=`expr $mntpt : "$oldpath\(/.*\)"` || continue
			echo ".$subdir"
		    done > $excl

		    # The new zone is currently inert and empty.  Begin the
		    # population process by copying over the root-resident
		    # files, including the 'dev' directory.  We use 'sort -r'
		    # because we can't use -depth with -prune.
		    zonecpio=/tmp/.lulib.cpio_err.$ozonename
		    (
			cd "$oldpath" &&
			find . -xdev \
			    \( -type d -exec fgrep -x '{}' $excl \; -prune \) \
			    -o -print |
			sort -r |
			/usr/bin/cpio -pPdum "$newrawpath"
		    ) 2>$zonecpio 1>&2
		    retv=$?
		    rm -f $excl

		    if [ $retv -ne 0 -a -s $zonecpio ]; then
			$LUPRINTF -Eelp2 \
			    "`gettext 'Zone <%s> in BE <%s>: cannot copy root\n\
\tSee <%s> for details.'`" $zonename "$lcz_pbename" $zonecpio
			/usr/sbin/zoneadm -R "$lcz_abemnt" -z $zonename \
			    mark incomplete
		        if [ "$lcz_mountednow" = "yes" ]; then
		            zoneadm -R "$lcz_pbemnt" -z $zonename unmount
		        fi
			continue
		    fi

		    # Mount each non-lofs zone import in a temporary location
		    # and copy over the bits that belong there, extracted from
		    # the running zone.  We are now reaching through zone-
		    # controlled paths and thus must be extremely careful.
		    # Direct copies are not safe.
		    tdir=/tmp/lulib.zcopy.zonedir.$$
		    rm -rf $tdir
		    mkdir $tdir
		    lulib_get_zone_icffs "$lcz_abeicf" $zonename |
		    awk '$4 != "lofs" { print $3; }' > /tmp/lulib.zcopy.zonefs.$$
		    zonecfg -R "$lcz_abemnt" -z $zonename info inherit-pkg-dir |
		    awk '$1 == "dir:" { print $2; }' > /tmp/lulib.zcopy.zoneipd.$$
		    lulib_get_zone_icffs "$lcz_abeicf" $zonename |
		    while read special raw mountpoint fstype fsckpass \
			    atboot opts; do

			if [ $fstype = lofs ]; then
			    # ignore loopback
			    continue
			fi
			case "$opts" in
			    # ignore if read-only
			    ro|*,ro|ro,*|*,ro,*) continue;;
			esac
			if mount -p | grep "^$special " > /dev/null; then
			    # ignore if mounted
			    continue
			fi
			if [ -n "$opts" -a "$opts" != "-" ]; then
			    opts="-o $opts"
			else
			    opts=
			fi
			if mount -F $fstype $opts $special $tdir; then
			    $LUPRINTF -lp2 \
				"`gettext 'Copying <%s> in zone <%s>.'`" \
				$mountpoint $zonename
			    zonefscpio=${zonecpio}.`basename $special`
			    (
				(
				    fgrep -xv $mountpoint /tmp/lulib.zcopy.zonefs.$$
				    cat /tmp/lulib.zcopy.zoneipd.$$
				) | sed 's+.*+^&/+' |
				zlogin $ozonename \
				    "cat > /tmp/lulib.zcopy.excl.$$; \
				    (
					if [ -s /tmp/lulib.zcopy.excl.$$ ]; then
					    cd $zroot$mountpoint && \
					    find . -depth -print | \
					    egrep -vf /tmp/lulib.zcopy.excl.$$ | \
					    cpio -ocmP@
					else
					    cd $zroot$mountpoint && \
					      find . -depth -print | cpio -ocmP@
					fi
				    )" |
				( cd $tdir && cpio -icdmP@ )
				lulib_unmount_pathname $tdir
			    ) 2>$zonefscpio 1>&2
			    if egrep -v '^[0-9]* blocks$' $zonefscpio 1>&2; then
				$LUPRINTF -Wlp2 \
	    "`gettext 'Zone <%s> mount point <%s>: data copy incomplete\n\
	\tSee <%s> for details.'`" $zonename $mountpoint $zonefscpio
			    else
				rm $zonefscpio
			    fi
			else
			    $LUPRINTF -Wlp2 \
				"`gettext \
				  'Zone <%s> mount point <%s>: cannot copy'`" \
				$zonename $mountpoint
			fi
		    done
		    if [ "$lcz_mountednow" = "yes" ]; then
		        zoneadm -R "$lcz_pbemnt" -z $zonename unmount
		    fi
		    rmdir $tdir
		    rm /tmp/lulib.zcopy.zonefs.$$ /tmp/lulib.zcopy.zoneipd.$$ $zonecpio
		done
	fi
    done
}
