#!/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	"@(#)lucopy.sh	5.56	09/07/26 SMI"
#
# This utility is not for public use; the interface is subject to change 
# without notice.
#
# USAGE:              lucopy <icf_file>
# FUNCTION:           Copies the files from PBE to ABE
# INPUT:              ICF of BE NAME
# OUTPUT:             NONE
#
################################################################################

LU_PROG_FULL_PATH="$0"
LU_PROG_NAME="`basename $LU_PROG_FULL_PATH`"; export LU_PROG_NAME

ERR_FLG=""
ABE_ICF=""
PBE_ICF=""
TEMP_MNTPT="/.alt.lucopy.$$"
TMP_RESULT_FILE="/tmp/.lucopy.results.tmp.$$"
TMP_FILE="/tmp/.lucopy.tmp_file.$$"
TMP_FDFILE="/tmp/.lucopy.fd1.$$"
TMP_FDFILE1="/tmp/.lucopy.fd2.$$"
ABE_FILE="/tmp/.lucopy.abe_file.$$"
ABE_FILESAVE="/tmp/.lucopy.abe_filesav.$$"
MAIL_ROOT="/tmp/.lucopy.mail.root.$$"
ERR_MSG_LOG="/tmp/.lucopy.err.$$"
CPIO_ERR="/tmp/.lucopy.cpio_err.$$"
CPIO_ERR_TMP="/tmp/.lucopy.cpio_err_tmp.$$"
FIND_ERR="/tmp/.lucopy.find_err.$$"
INTEGRITY_CHECK="yes"
FILTER_FILE="/tmp/.lucopy_filter_one.$$"
TEMP_FILTER_FILE="/tmp/.lucopy_filter_temp.$$"
FILTER_FILE_2="/tmp/.lucopy_filter_two.$$"
TMP_REMOVABLE_DEV_FILE="/tmp/.lucopy_removable_devs.$$"
MNTTAB_TMP_FILE="/tmp/.lucopy_mnttab.$$"

# This file is used by shell sub-processes (such as inside of a 'while..done')
# to signal the main shell process that an error has occurred
FLAG_FILE="/tmp/.lucopy_flagfile.$$"

# define commands used
DATE_CMD="/usr/bin/date"
MKTEMP_CMD="/usr/bin/mktemp"
CP_CMD="/usr/bin/cp"
CPIO_CMD="/usr/bin/cpio"
FDO_CMD="/etc/lib/lu/ludo lufdo"

# Normalize file operations temporary file name prefix
NORMALIZECLI_PREFIX="lucopy.normalizeCliFileops"

# permanent file that is left behind if the copy fails
CPIO_ERROR_FILE="/tmp/lucopy.errors.$$"

trap "" 1 2 3 15

################################################################################
# Name:		usage
# Description:	output command line usage information; then call exit_script to
#		terminate execution.
# Local Prefix:	<none>
# Arguments:	$1 = exit code for script ("" defaults to "3").
# Example:	usage 3
# Returns:	<none> 
################################################################################

usage()
{
  $LUPRINTF -p2 "`gettext 'USAGE: %s [-l error_log] [-o outfile] \
-i <abe_icf_file> -p <pbe_icf_file>'`" "$LU_PROG_NAME"
  if [ -z "$1" ] ; then
    exit_script 3
  fi
  exit_script "$1"
}

################################################################################
# Name:		normalizeCliFileops	
# Description:	Scan the input filter file for user specified include/exclude
#		entries.  Find out if there is any duplicate entry in the filter
#		file elsewhere preceded by '+' or '-'.  If so, remove all such
#		entries.  This is to give the user specified entries priority
#		over the ones determined by system.  Note that only the entries
#		preceded by '+' or '-' will be removed.
# Local Prefix:	ncf_	
# Arguments:	$1 = Name of the filter file with absolute path. 
# Example:	normalizeCliFileOps "$FILTER_FILE"	
# Returns:	<none> 
################################################################################

normalizeCliFileops()
{
	ncf_filterFile="$1"
	
	# generate temporary file name for storing the normalized filters
	# use /usr/bin/mktemp if available - otherwise construct file name to
	# use
	if [ -x $MKTEMP_CMD ] ; then
		# mktemp is available - use that to generate temp name
		ncf_filterFileTmp=`$MKTEMP_CMD -t ${NORMALIZECLI_PREFIX}.XXXXXX`
		[ $? -ne 0 ] && return
	else
		ncf_filterFileTmp="/tmp/${NORMALIZECLI_PREFIX}.$$.`$DATE_CMD \
		    +\"%d""%g""%G""%H""%j""%m""%M""%S""%w""%W\"`"
		$CP_CMD /dev/null "$ncf_filterFileTmp"
		[ $? -ne 0 ] && return
	fi

	# debugging output: file name generated
	$LUPRINTF -lp2D - \
	    "`gettext 'Normalize cli file operations temporary file <%s>.'`" \
	    "$ncf_filterFileTmp"

	# return if filter file name not specified
	[ -z $ncf_filterFile ] && return

	# return if filter file does not exist or is not readable
	[ -r $ncf_filterFile ] || return

	# return if filter file is empty
	[ -s $ncf_filterFile ] || return

	# delete temporary file if it exists
	[ -f $ncf_filterFileTmp ] && \
	    /bin/rm -f $ncf_filterFileTmp > /dev/null 2>&1

	# determine line number of first line of lu_content_control file
	ncf_lineNumber=`/bin/grep -n "#####" $ncf_filterFile | /bin/head -1 | \
	    /bin/cut -d ':' -f1`

	# return if lu_content_control file is not included
	[ -z "$ncf_lineNumber" ] && return

	# return if lu_content_control file is at the head of the filter file
	[ $ncf_lineNumber -le 1 ] && return

	# determine number of lines of "user file operations"
	# split out user file operations and filter file lines
	ncf_userLineNumber=`/bin/expr $ncf_lineNumber - 1`

	# create the initial edit expression
	ncf_userRegExpr="^(\+ |\- )("

	# add all user operations to the expression
	for i in `/bin/head -$ncf_userLineNumber $ncf_filterFile | \
	    /bin/egrep "^(\+ |\- )" | /bin/cut -d ' ' -f2 `
	do
		ncf_userRegExpr="$ncf_userRegExpr$i|"
	done

	# terminate the edit expression
	ncf_userRegExpr="$ncf_userRegExpr )(/+?)$"

	# create new filter file - include user file operations first
	/bin/head -$ncf_userLineNumber $ncf_filterFile > $ncf_filterFileTmp

	# search $ncf_filterFile and append edited filter contents
	/bin/cat $ncf_filterFile | /bin/egrep -v "$ncf_userRegExpr" >> \
	    $ncf_filterFileTmp

	# replace real filter file with modified filter file
	/bin/mv $ncf_filterFileTmp $ncf_filterFile

	return
}

################################################################################
# Name:		do_integrity_check
# Description:	perform pre-copy content integrity check (if enabled)
# Local Prefix:	ick_
# Arguments:	$1 = filter file to perform integrity check against
#		$2 = mount point of source boot environment to check
# Returns:	0 - integrity check was successful (or skipped)
#		1 - integrity check failed
################################################################################

do_integrity_check()
{
	ick_filterFile="$1"
	ick_pbeMpt="$2"

	# return if no filter file
	[ -z "$ick_filterFile" ] && return 0
	[ -f "$ick_filterFile" ] || return 0
	[ -s "$ick_filterFile" ] || return 0

	# return if source boot environment mount point is not valid
	[ -z "$ick_pbeMpt" ] && ick_pbeMpt="/"
	[ -d "$ick_pbeMpt" ] || return 0

	# Determine location of package database on source boot environment
	if [ "$ick_pbeMpt" = '/' ] ; then
		ick_contentsFile='/var/sadm/install/contents'
		ick_installDB='/var/sadm/install/install.db'
	else
		ick_contentsFile="$ick_pbeMpt/var/sadm/install/contents"
		ick_installDB="$ick_pbeMpt/var/sadm/install/install.db"
	fi

	# return if no contents (package) database
	[ -f "$ick_installDB" -a -s "$ick_installDB" ] ||
	[ -f "$ick_contentsFile" -a -s "$ick_contentsFile" ] ||
	return 0

	# return if integrity check is not enabled
	if [ "$INTEGRITY_CHECK" != "yes" ] ; then
		$LUPRINTF -lp2 "`gettext 'No integrity check performed \
(\"-I\" option set).'`"
		return 0
	fi

	# integrity check enabled: check package integrity
	$LUPRINTF -lp2 "`gettext 'Checking selection integrity.'`"
	$LUPRINTF -lp2D - \
	    "`gettext 'Check integrity against package database.'`"
	$FDO_CMD integrity_check "$ick_filterFile" "$ick_pbeMpt"
	if [ $? -ne 0 ] ; then
		$LUPRINTF -Eelp2 "`gettext 'Integrity check failed.'`"
		return 1
	fi

	# integrity check successful
	$LUPRINTF -lp2 "`gettext 'Integrity check OK.'`"
	return 0
}

################################################################################
# Name:		is_mntpt_in_skiplist
# Description:	determine if a mount point is in a skip list file
# Local Prefix:	ims_
# Arguments:	$1 = skip list file name
#		$2 = mount point to serch for
# Returns:	0
# Outputs:	If the mountpoint is found in the skiplist file, the name of
#		the mountpoint is output
################################################################################
is_mntpt_in_skiplist()
{
	ims_skiplist="$1"
	ims_mntpt="$2"

	# return if skiplist file is not defined or is empty
	[ -z "$ims_skiplist" ] && return 0
	[ -s "$ims_skiplist" ] || return 0

	# return if mountpoint is not defined
	[ -z "$ims_mntpt" ] && return 0

	# read skiplist file looking for specified mountpoint
	while read ims_line ; do
		[ "$ims_line" = "$ims_mntpt" ] && echo "$ims_mntpt"
	done < $ims_skiplist

	# done scanning file - return
	return 0
}

################################################################################
# Name:		process_fs_list
# Description:	For each file system to be created on the new boot environment
#		(that is not shared and is not swap), add entries to the filter
#		file depending on whether the file system is "preserved" or not:
#		  - add "<" entries for preserved file systems
#		  - add "+" entries for non-preserved file systems
# Local Prefix:	pfs_
# Arguments:	$1 = skip list file name
#		$2 = filter to append mount point include/excludes to
#		$3 = parent boot environment icf file
#		$4 = new boot environment icf file
# Returns:	0 - no file systems skipped
#		1 - one or more file systems skipped
################################################################################
process_fs_list()
{
	pfs_skiplist="$1"
	pfs_filter="$2"
	pfs_pbeicf="$3"
	pfs_abeicf="$4"
	pfs_anySkipped=0

	# return if skiplist file is not defined or is empty
	[ -z "$pfs_skiplist" ] && return 0

	# return if filter file is not defined or does not exist
	[ -z "$pfs_filter" ] && return 0
	[ -f "$pfs_filter" ] || return 0

	# return if pbe icf file is not defined or is empty
	[ -z "$pfs_pbeicf" ] && return 0
	[ -s "$pfs_pbeicf" ] || return 0

	# return if abe icf file is not defined or is empty
	[ -z "$pfs_abeicf" ] && return 0
	[ -s "$pfs_abeicf" ] || return 0

	# Process each mount point for the BE being populated
	# For each mount point an entry must be made in the filter file:
	# - if the mount point is preserved, add a "<" entry to the filter
	# - if the mount point is populated, add a "+" entry to the filter
	# We add "zfs" to the list of unsupported filesystem types as
	# they are treated as global filesystems (similar to /export/home
	# being on a separate slice).
	for pfs_mntpt in `$LUETCBIN/ludo filter_shared_and_swap \
	    $pfs_pbeicf $pfs_abeicf | /bin/awk -F: '{print $2}'` ; do
		# search for this mountpoint in the new BE in the skip list file
	 	# if the mount point is to be skipped, exit 1, else exit 0

		if [ -n "`is_mntpt_in_skiplist \"$pfs_skiplist\" \
		    \"$pfs_mntpt\"`" ] ; then
			$LUPRINTF -lp1 "`gettext 'Preserving contents of \
mount point <%s>.'`" "$pfs_mntpt"
			$FDO_CMD mountpoints_to_copy '<' /etc/vfstab \
			    /etc/mnttab $pfs_mntpt \
			    "$LU_UNSUPPORTED_FILE_SYSTEM_TYPES zfs" >> \
			    $FILTER_FILE
			pfs_anySkipped=1
		else
			$LUPRINTF -lp1 "`gettext 'Populating contents of \
mount point <%s>.'`" "$pfs_mntpt"
			$FDO_CMD mountpoints_to_copy '+' /etc/vfstab \
			    /etc/mnttab $pfs_mntpt \
			    "$LU_UNSUPPORTED_FILE_SYSTEM_TYPES zfs" >> \
			    $FILTER_FILE
			# In case of populating contents of mount point,
			# usually + will be prefixed to that mont point.
			# If same mount point prefixed with '<' or '>' type,
			# in FILTER_FILE, then exclude/remove '<' and '>' 
			# entries from FILTER_FILE
			if [ $pfs_anySkipped -eq 1 ]; then
			    /bin/egrep "^\+ $pfs_mntpt" $FILTER_FILE \
				>/dev/null 2>&1
			    if [ $? -eq 0 ]; then
				/bin/egrep -v "^(<|>) $pfs_mntpt" \
				    < $FILTER_FILE > $TEMP_FILTER_FILE
				/bin/cp $TEMP_FILTER_FILE $FILTER_FILE
			    fi
			fi
		fi
	done
	/bin/rm -f $TEMP_FILTER_FILE
	return $pfs_anySkipped
}

send_mail_to_root()
{
  # Send mail to root regarding problems faced during cpio.
  
  TMP_MAIL_ROOT=${MAIL_ROOT}.tmp
  /bin/rm -f $TMP_MAIL_ROOT
  $LUPRINTF +X -Wpa "$TMP_MAIL_ROOT" \
      "`gettext 'cpio failed due to the reasons listed below.'`"
  $LUPRINTF +X -Wpa "$TMP_MAIL_ROOT" \
      "`gettext 'The reason for failure may or may not be critical.'`"
  $LUPRINTF +X -Wpa "$TMP_MAIL_ROOT" \
      "`gettext 'It is left to the system administrator to decide whether the \
error is fatal or not.'`"
  $LUPRINTF +X -Wpa "$TMP_MAIL_ROOT" '%s' \
      "`gettext '------------------------------------------------------------'`"
  /bin/sed '/^[0-9][0-9]*[ 	][ 	]*blocks/d' $MAIL_ROOT >> $TMP_MAIL_ROOT
  /bin/mailx -s "`gettext 'lucopy problems'`" root < $TMP_MAIL_ROOT
  /bin/rm -f $TMP_MAIL_ROOT
}
  
copy_error_exit()
{
  # output error message if included in function call
  [ -n "$1" ] && $LUPRINTF -Eelp2 '%s' "$*"

  # Unmount the ABE slices, as we have come across some error, and
  # we want to exit.
  unmountbe ABE "$ABE_NAME" "$ABE_ICF" "$dest" "return 1"
  error_exit 1
}

error_exit()
{
  [ -d "$TEMP_MNTPT" ] && /bin/rmdir "$TEMP_MNTPT"
  if [ -n "$PBE_ICF" -a -n "$PBE_NAME" -a -n "$CURR_BE" \
      -a "$PBE_NAME" != "$CURR_BE" ] ; then
      unmountbe PBE "$PBE_NAME" "$PBE_ICF" "$PBE_MPT" "return 1"
  else
      unmountzones PBE "$PBE_NAME" "$PBE_MPT"
  fi
  if [ -z "$1" ] ; then
    exit_script 1
  fi
  exit_script "$1"
}

################################################################################
# Name:		exit_script
# Description:	Perform cleanup operations and exit this script.
# Local Prefix:	<none>
# Arguments:	$1 = optional exit value for script ("" or none is = "0")
# Example:      exit_script "0"
# Returns:	<none>
################################################################################

exit_script()
{
  # Remove all temporary files used

  /bin/rm -f "$FILTER_FILE" "$FILTER_FILE_2" "$TMP_FDFILE" \
      "$TMP_FDFILE1" $ABE_FILE $ABE_FILESAVE $CPIO_ERR \
      $ERR_MSG_LOG $FIND_ERR $MAIL_ROOT $TMP_FILE \
      "$TMP_RESULT_FILE" "$FLAG_FILE" $TMP_REMOVABLE_DEV_FILE

  # Determine the exit status code.

  retcode="0"
  if [ -n "$1" ] ; then
    retcode="$1"
  fi

  exit "$retcode"
}

################################################################################
# Name:		mountzones
# Description:	Mount all of the zones in a given boot environment
# Arguments:	$1 = env type
#		$2 = env name
#		$3 = boot environment root
# Example:      mountzones PBE "$PBE_NAME" /.alt.pbe
# Returns:	non-zero on failure
################################################################################
mountzones()
{
    ENV=$1
    BENAME=$2
    ROOT=${3:-/}

    lulib_zone_check "$ROOT"

    SAVEIFS="$IFS"
    lulib_list_zones -c "$ROOT" |
    while IFS=: read zoneid zonename state path junk; do
	IFS="$SAVEIFS"
	if [ $zonename = global ]; then
	    continue
	fi
	# Note that this can happen only if the source is the current
	# BE.
	if [ $state = ready ]; then
	    global_ready_list="$global_ready_list $zonename"
	    /usr/sbin/zoneadm -R "$ROOT" -z $zonename halt
	    state=installed
	fi
	if [ $state = installed ]; then
	    /usr/sbin/zoneadm -R "$ROOT" -z $zonename mount || (
		$LUPRINTF -Eelp2 "`gettext \
		    'Error: cannot mount zone %s in %s <%s>'`" \
		    $zonename $ENV "$BENAME"
		return 1
	    )
	fi
    done
    return 0
}

################################################################################
# Name:		mountbe
# Description:	Mount a boot environment and all of the zones therein
# Arguments:	$1 = flags
# 		$2 = env type
#		$3 = env name
#		$4 = ICF
#		$5 = mount point
#		$6 = exit function
# Example:      mountbe -Z PBE "$PBE_NAME" "$PBE_ICF" /.alt.pbe "exit_script 1"
# Returns:	mount point on stdout (exits on failure)
################################################################################
mountbe()
{
    FLAGS=$1
    ENV=$2
    BENAME=$3
    ICF=$4
    MNTPT=$5
    EXITFUNC=$6
    tmp=/tmp/mountbe.$$

    NEWMNT=`LU_OUTPUT_FORMAT=text \
	$LUBIN/lumount ${MNTPT:+-c} ${MNTPT:+"$MNTPT"} ${FLAGS} -i "$ICF" 2>$tmp`
    if [ $? -ne 0 ] ; then
	if [ -s "$TMP_RESULT_FILE" ]; then
	    $LUPRINTF -elp2 '%R' < "$TMP_RESULT_FILE"
	fi
	$LUPRINTF -Eelp2 \
	    "`gettext 'Unable to mount %s <%s> from ICF file <%s>.'`" $ENV \
	    "$BENAME" "$ICF"
	$LUPRINTF -Eelp2 \
	    "`gettext 'Contents of ICF file <%s>:\n****\n%R\n****'`" "$ICF" < \
	    "$ICF"
	(
	    if [ -n "$NEWMNT" ]; then
		echo $NEWMNT
	    fi
	    cat $tmp
	) | $LUPRINTF -Eelp2 "`gettext 'Output from <%s>:\n****\n%R\n****'`" \
	    "$LUBIN/lumount ${MNTPT:+-c} $MNTPT ${FLAGS} -i $ICF"
	rm -f $tmp
	$EXITFUNC
    fi
    if [ -z "$NEWMNT" -o ! -d "$NEWMNT" ] ; then
	if [ -s "$TMP_RESULT_FILE" ]; then
	    $LUPRINTF -elp2 '%R' < "$TMP_RESULT_FILE"
	fi
	$LUPRINTF -Eelp2 \
	    "`gettext 'Failed to mount %s <%s> from ICF file <%s>.'`" $ENV \
	    "$BENAME" "$ICF"
	$LUPRINTF -Eelp2 \
	    "`gettext 'Contents of ICF file <%s>:\n****\n%R\n****'`" "$ICF" < \
	    "$ICF"
	(
	    if [ -n "$NEWMNT" ]; then
		echo $NEWMNT
	    fi
	    cat $tmp
	) | $LUPRINTF -Eelp2 "`gettext 'Output from <%s>:\n****\n%R\n****'`" \
	    "$LUBIN/lumount ${MNTPT:+-c} $MNTPT ${FLAGS} -i $ICF"
	rm -f $tmp
	$EXITFUNC
    fi
    rm -f $tmp

    echo "$NEWMNT"
}

in_list()
{
    VAL=$1
    shift
    for i
    do
	if [ "$VAL" = "$i" ]; then
	    return 0
	fi
    done
    return 1
}

################################################################################
# Name:		unmountzones
# Description:	Unmount all of the zones in a given boot environment
# Arguments:	$1 = env type
#		$2 = env name
#		$3 = boot environment root
# Example:      unmountzones PBE "$PBE_NAME" /.alt.pbe
# Returns:	<none>
################################################################################
unmountzones()
{
    ENV=$1
    BENAME=$2
    ROOT=${3:-/}

    SAVEIFS="$IFS"
    lulib_list_zones -c "$ROOT" |
    while IFS=: read zoneid zonename state path junk; do
	IFS="$SAVEIFS"
	if [ $zonename = global ]; then
	    continue
	fi
	if [ $state = mounted ]; then
	    /usr/sbin/zoneadm -R "$ROOT" -z $zonename unmount ||
	    $LUPRINTF -Eelp2 \
		"`gettext 'Warning: cannot unmount zone %s in %s <%s>'`" \
		$zonename $ENV "$BENAME"
	fi
	if [ "$ROOT" = / ] && in_list $zonename $global_ready_list; then
	    /usr/sbin/zoneadm -R "$ROOT" -z $zonename ready
	fi
    done
    return 0
}

################################################################################
# Name:		unmountbe
# Description:	Unmount a boot environment and all of the zones therein
# Arguments:	$1 = env type
#		$2 = env name
#		$3 = ICF
#		$4 = boot environment root
#		$5 = exit function
# Example:      unmountbe PBE "$PBE_NAME" "$PBE_ICF" /.alt.pbe "return 1"
# Returns:	<none>
################################################################################
unmountbe()
{
    ENV=$1
    BENAME=$2
    ICF=$3
    ROOT=$4
    EXITFUNC=$5

    $LUBIN/luumount -f -i "$ICF"
    if [ $? -ne 0 ] ; then
	$LUPRINTF -Eelp2 \
	    "`gettext 'Unable to unmount %s <%s> from ICS file <%s>.'`" $ENV \
	    "$BENAME" "$ICF"
	$EXITFUNC
    fi
}

################################################################################
# Name:         zoneskip_check
# Description:	Checking the zones to be skipped
# Arguments:	$1 = zone name
#		$2 = zone path
#		$3 = file system skip list
#		$4 = ABE mountpoint
#		$5 = Temporary mnttab file
# Returns:	0 if zone is to be skipped
#		1 if zone must be copied to ABE
################################################################################
zoneskip_check()
{
    zc_zonename=$1
    zc_dir=$2
    zc_fs_skiplist=$3
    zc_abe_mpt=$4
    zc_mnttab=$5

    while [ "$zc_dir" != '/' ]
    do
	/bin/egrep "^$zc_dir$" $zc_mnttab > /dev/null 2>&1
	zc_filesystem=$?
	if [ "$zc_filesystem" -eq 0 ] ; then
	    break
        fi
        zc_dir=`dirname $zc_dir`
    done

    zc_dir=`echo $zc_dir | /usr/bin/sed "s:^$zc_abe_mpt\(.*\):\1:"`
    /bin/egrep "^$zc_dir$" $zc_fs_skiplist > /dev/null 2>&1
    return $?
}

################################################################################
# Name:		<main>
# Description:	Main code (outside of any function definitions) - executed at
#		script startup.
# Local Prefix:	<none>
# Arguments:	$0...$n = All arguments specified by user on command line that
#		invoked this script.
################################################################################

# 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

LUBIN=${LUBIN:=/usr/lib/lu}
COPYLOCK=${COPYLOCK:=/etc/lu/COPY_LOCK}

# 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

# Check for existence and non-zero size of lutab file.

if [ ! -f $LU_LUTAB_FILE -o ! -s $LU_LUTAB_FILE ] ; then
  $LUPRINTF -Eelp2 \
      "`gettext 'No boot environments are configured on this system.'`"
  exit 1
fi

################################################################################
############### Command line option and argument processing ####################
################################################################################

# Reset all command line parse flags to default values.
flag_F="" # -F f - filter file to use (PRIVATE)
flag_I="" # -I - no integrity check (PRIVATE).
flag_c="" # -c n - mount point to clone directory permissions from
flag_i="" # -i n - abe icf file to use.
flag_o="" # -o f - output file path.
flag_l="" # -l f - log file path.
flag_p="" # -p n - pbe icf file to use.
flag_s="" # -s f - file system skip file (PRIVATE).
flag_x="" # -x n = set debug level to n (PRIVATE).
flag_z="" # -z f - filter file (PRIVATE).

# file system skip list file name
FS_SKIP_LIST="" 

# Remove any temporary files before they are used
/bin/rm -f "$FILTER_FILE" "$FILTER_FILE_2" "$TMP_FDFILE" \
    "$TMP_FDFILE1" $ABE_FILE $ABE_FILESAVE $CPIO_ERR \
    $ERR_MSG_LOG $FIND_ERR $MAIL_ROOT $TMP_FILE \
    "$TMP_RESULT_FILE" "$FLAG_FILE" $TMP_REMOVABLE_DEV_FILE

# Parse command line options
while [ $# -ne 0 ] ; do
  while getopts c:F:Ii:l:o:p:s:x:Xz: c
  do
    case $c in
      I) # -I - no integrity check
	 INTEGRITY_CHECK="no"
	 ;;

      c) # -c mntpt
         lulib_cannot_duplicate_option "$flag_c" "$OPTARG" "-c"
	 flag_c="$OPTARG"
	 ;;

      i) # -i abe_icf_file
	 lulib_cannot_duplicate_option "$flag_i" "$OPTARG" "-i"
	 flag_i="$OPTARG"
	 ABE_ICF="$OPTARG"
	 ;;

      l) # -l f - error log file path.
	 # This overrides the LU_ERROR_LOG_FILE setting read from
	 # /etc/default/lu
	 lulib_cannot_duplicate_option "$flag_l" "$OPTARG" "-l"
	 $LUPRINTF -lp2D - "`gettext 'Verifying that the error log file \
<%s> specified can be created and appended to.'`" "$OPTARG"
	 ERRMSG="`$LUPRINTF -c \"$OPTARG\" 2>&1`"
	 if [ $? -ne 0 ] ; then
	   [ -n "$ERRMSG" ] && $LUPRINTF -elp2 '%s' "$ERRMSG"
	   $LUPRINTF -Eelp2 "`gettext 'Argument <%s> to -l option may not \
be created or appended to.'`" "$OPTARG"
	   exit_script 3
	 fi
	 flag_l="$OPTARG"
	 lulib_set_error_log_file "$flag_l"
	 ;;

      o) # -o f - output file path.
	 # This overrides the LU_SESSION_LOG_FILE setting read from
	 # /etc/default/lu
	 lulib_cannot_duplicate_option "$flag_o" "$OPTARG" "-o"
	 $LUPRINTF -lp2D -  "`gettext 'Verifying that the session log file \
<%s> can be created and appended to.'`" "$OPTARG"
	 ERRMSG="`$LUPRINTF -c \"$OPTARG\" 2>&1`"
	 if [ $? -ne 0 ] ; then
	   [ -n "$ERRMSG" ] && $LUPRINTF -elp2 '%s' "$ERRMSG"
	   $LUPRINTF -Eelp2 "`gettext 'Argument <%s> to -o option may not be \
created or appended to.'`" "$OPTARG"
	   exit_script 3
	 fi
	 flag_o="$OPTARG"
	 lulib_set_session_log_file "$flag_o"
	 ;;

      p) # -p n - pbe icf file to use.
	 lulib_cannot_duplicate_option "$flag_p" "$OPTARG" "-p"
	 flag_p="$OPTARG"
	 PBE_ICF="$OPTARG"
	 ;;

      s) # -s f - file system skip file (PRIVATE).
	 lulib_cannot_duplicate_option "$flag_s" "$OPTARG" "-s"
	 flag_s="$OPTARG"
	 FS_SKIP_LIST="$OPTARG"
	 ;;

      X) # -X - set XML output mode.
	  lulib_set_output_format 'xml'
	  ;;

      z) # -z f - filter file (PRIVATE).
	 lulib_cannot_duplicate_option "$flag_z" "$OPTARG" "-z"
	 ERRMSG="`$CP_CMD \"$OPTARG\" \"$FILTER_FILE\" 2>&1`"
	 if [ $? -ne 0 ] ; then
	   [ -n "$ERRMSG" ] && $LUPRINTF -elp2 '%s' "$ERRMSG"
	   $LUPRINTF -Eelp2 "`gettext 'Argument <%s> to -z option cannot be \
used as filter file.'`" "$OPTARG"
	   exit_script 3
	 fi
	flag_z="$OPTARG"
	;;

      \?) # unknown - option.
	  usage 3
	  esac
  done

  # Found either end of arguments, +option, or non-option argument; shift out
  # what has been processed so far; if a non-option argument is present
  # capture it and continue processing the command line arguments.
  shift `/bin/expr $OPTIND - 1`
  OPTIND=1
  if [ $# -ne 0 -a "$1" = '+X' ] ; then
      # +X - set TEXT output mode.
      lulib_set_output_format 'text'
      shift
  else
    break
  fi
done

# Fixup debug, session log, and error log settings
lulib_fixup_startup_settings

################################################################################
###### Validate all command line arguments and options as possible #############
################################################################################

# If any command line arguments provided, exit with error.
if [ "$#" -ne 0 ] ; then
  $LUPRINTF -Eelp2 "`gettext 'Command line arguments <%s> not allowed.'`" "$*"
  usage 3
fi

# Make sure that a PBE internal configuration file name was specified.

if [ -z "$PBE_ICF" ] ; then
  $LUPRINTF -Eelp2 "`gettext 'You must use the <-p> option to specify the \
ICF file of the PBE to copy file systems from.'`"
  usage 3
fi

# Validate the PBE ICF file.

lulib_icf_validate "$PBE_ICF"
if [ $? -ne 0 ] ; then
  $LUPRINTF -Eelp2 "`gettext 'The file <%s> specified by the <-p> option \
is not a valid ICF file.'`" "$PBE_ICF"
  usage 3
fi

# Make sure that a ABE internal configuration file name was specified.

if [ -z "$ABE_ICF" ] ; then
  $LUPRINTF -Eelp2 "`gettext 'You must use the <-p> option to specify the \
ICF file of the ABE to copy file systems from.'`"
  usage 3
fi

# Validate the ABE ICF file.

lulib_icf_validate "$ABE_ICF"
if [ $? -ne 0 ] ; then
  $LUPRINTF -Eelp2 "`gettext 'The file <%s> specified by the <-p> option is \
not a valid ICF file.'`" "$ABE_ICF"
  usage 3
fi

# Get the current BE name

CURR_BE="`lulib_lucurr`"
if [ $? -ne 0 -o -z "$CURR_BE" ] ; then
  $LUPRINTF -Eelp2 \
      "`gettext 'Unable to determine the name of the current active PBE.'`"
  exit_script 1
fi

# If the PBE specified is NOT the current BE, then mount the PBE to be copied
# from

PBE_MPT=/
PBE_NAME="`/bin/awk -F: '{print $1;exit}' $PBE_ICF`"
ABE_NAME="`/bin/awk -F: '{print $1;exit}' $ABE_ICF`"

if [ "$PBE_NAME" != "$CURR_BE" ] ; then
    PBE_MPT=`mountbe "" PBE "$PBE_NAME" "$PBE_ICF" "" "exit_script 1"`
else
    # at least make sure the zones are all mounted and ready
    mountzones PBE "$PBE_NAME" "$PBE_MPT"
fi

# Make sure we have the right Zones tools for the source boot environment
lulib_zone_check "$PBE_MPT"

COPYLOCK=${COPYLOCK:=/etc/lu/COPY_LOCK}

# Output debugging information about filters and integrity checks
if [ -s "$FILTER_FILE" ] ; then
  # Filter file exists
  $LUPRINTF -lp2D - \
      "`gettext 'File system filter specifications file: <%s>'`" \
      "$FILTER_FILE"
else
  # No filter file - create empty filter file
  $LUPRINTF -lp2D - "`gettext 'No file system filter in use.'`"
  ERRMSG="`$LUPRINTF -c \"$FILTER_FILE\" 2>&1`"
  if [ $? -ne 0 ] ; then
    [ -n "$ERRMSG" ] && $LUPRINTF -elp2 '%s' "$ERRMSG"
    $LUPRINTF -Eelp2 \
	"`gettext 'Unable to create file system filter file <%s>.'`" \
	"$FILTER_FILE"
    exit_script 1
  fi
fi

$LUPRINTF -lp2D - "`gettext 'Integrity check setting: <%s>'`" \
    "$INTEGRITY_CHECK"

# Create temporary mount point if it does not already exist
if [ ! -d "$TEMP_MNTPT" ] ; then
  ERRMSG="`/bin/mkdir \"$TEMP_MNTPT\" 2>&1`"
  if [ ! -d "$TEMP_MNTPT" ] ; then
    [ -n "$ERRMSG" ] && $LUPRINTF -elp2 '%s' "$ERRMSG"
    $LUPRINTF -Eelp2 \
	"`gettext 'Unable to create temporary mount point <%s>.\n'`" \
	"$TEMP_MNTPT"
    exit_script 1
  fi
fi

# Root slice of ABE is mounted, to do the special processing for /usr and
# /var filesystems.

# In the following while loop, a "0" exit code means "not found" and a
# "1" exit code means "found" as per this comment in man sh: If no
# commands in the do list are executed, then the while command returns
# a zero exit status. So "0" will mean NOTHING was found in the ICF
# file that matched "/"...

/bin/rm -f $FLAG_FILE
$LUETCBIN/ludo filter_shared_and_swap $PBE_ICF $ABE_ICF |
    /bin/nawk -F: '$2 == "/" && $6 == "" { printf("%s %s\n", $3, $4) }' |
while read bdevice fstyp ; do
  if [ -z "$bdevice" -o -z "$fstyp" ] ; then
    $LUPRINTF -Eelp2 "`gettext 'ICF files <%s> and <%s> for BEs <%s> and \
<%s> contains invalid contents.'`" "$PBE_ICF" "$ABE_ICF" "$PBE_NAME" \
	"$ABE_NAME"
    /bin/touch $FLAG_FILE
    exit 0
  fi

  # bypass the mount and checks for zfs file systems
  if [ "$fstyp" = "zfs" ] ; then
	exit 2
  fi

  if [ ! -b "$bdevice" ] ; then
    $LUPRINTF -Eelp2 "`gettext 'Device <%s> for mount point </> from ICF \
file <%s> for ABE <%s> is not a block device.'`" "$bdevice" "$ABE_ICF" \
	"$ABE_NAME"
    /bin/touch $FLAG_FILE
    exit 0
  fi

  real_fstyp="`lulib_fstyp $bdevice`"
  if [ $? -ne 0 ] ; then
    $LUPRINTF -Eelp2 "`gettext 'Unable to determine file system type for \
device <%s> for mount point </> from ICF file <%s> for ABE <%s>.'`" \
	"$bdevice" "$ABE_ICF" "$ABE_NAME"
    /bin/touch $FLAG_FILE
    exit 0
  fi

  if [ "$real_fstyp" != "$fstyp" ] ; then
    $LUPRINTF -Eelp2 "`gettext 'File system type <%s> for device <%s> for \
mount point </> from ICF file <%s> for ABE <%s> should be <%s>.'`" \
	"$real_fstyp" "$bdevice" "$ABE_ICF" "$ABE_NAME" "$fstyp"
    /bin/touch $FLAG_FILE
    exit 0
  fi

  ERRMSG="`/usr/sbin/mount -F $fstyp $bdevice \"$TEMP_MNTPT\" 2>&1`"
  if [ $? -ne 0 ] ; then
    [ -n "$ERRMSG" ] && $LUPRINTF -Eelp2 '%s' "$ERRMSG"
    $LUPRINTF -Eelp2 "`gettext 'Unable to mount device <%s> for mount \
point </> for ABE <%s>.'`" "$bdevice" "$ABE_NAME"
    /bin/touch $FLAG_FILE
    exit 0
  fi

  # Cause data/mountpoint to be flushed/synced
  if [ -x "/usr/sbin/lockfs" ] ; then
	  # force log to be flushed before unmounting

	  /usr/sbin/lockfs -f "$TEMP_MNTPT" 1>/dev/null 2>&1
  else
	  # sync data to storage medium before unmounting
	  /bin/sync
  fi

  # unmount boot environment
  ERRMSG="`lulib_unmount_pathname \"$TEMP_MNTPT\" 2>&1`"
  ret=$?
  if [ $ret -ne 0 ] ; then
    ERRMSG="`lulib_unmount_pathname -f \"$TEMP_MNTPT\" 2>&1`"
    ret=$?
  fi

  # If the umount failed, issue error message
  if [ $ret -ne 0 ] ; then
    [ -n "$ERRMSG" ] && $LUPRINTF -Eelp2 '%s' "$ERRMSG"
    $LUPRINTF -Eelp2 "`gettext 'Unable to unmount ABE <%s>.'`" "$ABE_NAME"
    /bin/touch $FLAG_FILE
    exit 0
  fi

  /bin/rmdir "$TEMP_MNTPT"
  exit 2
done

if [ $? -ne 2 -o -f "$FLAG_FILE" ] ; then
  /bin/rm -f "$FLAG_FILE"
  $LUPRINTF -Eelp2 \
      "`gettext 'Unable to determine file systems for ABE <%s>.'`" "$ABE_NAME"
  error_exit 1
fi

#--------------------------------------------------------------------------

# Copy the file systems of ABE into $ABE_FILE in reverse order.

$LUETCBIN/ludo filter_shared_and_swap $PBE_ICF $ABE_ICF |
    /bin/sort -r -t: +1 -2 | /bin/awk -F: '$6 == "" { printf("%s\n",$2)}' \
    > $ABE_FILE
if [ $? -ne 0 ] ; then
  $LUPRINTF -Eelp2 "`gettext 'Unable to determine file system list from ICF \
files <%s> and <%s> for ABE <%s>.'`" "$PBE_FILE" "$ABE_FILE" "$ABE_NAME"
  error_exit 1
fi

ERRMSG="`$CP_CMD \"$ABE_FILE\" \"$ABE_FILESAVE\" 2>&1`"
if [ $? -ne 0 ] ; then
  $LUPRINTF -Eelp2 \
      "`gettext 'Unable to copy file system list file <%s> to <%s>.'`" \
      "$ABE_FILE" "$ABE_FILESAVE"
  error_exit 1
fi

#--------------------------------------------------------------------------

# Determine the file systems to be copied to ABE.

compul_list=`$LUETCBIN/ludo filter_shared_and_swap $ABE_ICF $PBE_ICF | \
    /bin/sort -r -t: +1 -2 | /bin/awk -F: '$6 == "" { printf("%s ",$2) }'`
if [ $? -ne 0 ] ; then
  $LUPRINTF -Eelp2 "`gettext 'Unable to determine file system list from ICF \
files <%s> and <%s> for ABE <%s>.'`" "$PBE_FILE" "$ABE_FILE" "$ABE_NAME"
  error_exit 2
fi

#--------------------------------------------------------------------------

# Mount the file systems in the ABE. Adding a 'Z' option as the first argument to skip mounting zones.
dest=`mountbe -Z ABE "$ABE_NAME" "$ABE_ICF" "${flag_c:+$PBE_MPT}" "error_exit 1"`
RETV=$?
if [ $RETV -ne 0 ]; then
    error_exit $RETV
fi

#--------------------------------------------------------------------------
#
# Create the filter used to control file systems that are copied.
#
# The copy algorithm only descends into directories on file systems that are
# explicitly included in the filter specification; the copy is done via a "copy
# only what is included" list.
#
# If mount points come into existence during the copy operation (either through
# auto or direct mounting) they are not included in the cloned boot environment.
#
# The initial filter file contains:
#
#  - user (lucreate command line) item include or exclude specifications
#
#  - all required file systems forced includes:
#    - mandatory file include/exclude list from /etc/lu/lu_content_control
#
# The following is then appended:
#
#  - exclude all currently mounted boot environments
#  - exclude new boot environment destination mountpoints
#  - exclude all shared file systems
#  - exclude all files in all crash dump directories under /var/crash
#  - exclude all non-directories from /var/run and /var/tmp
#
# The integrity of the selection is then checked to make sure that the package
# database is maintained; no required item listed in the package database may
# be removed by a filter specification.
#
# The following is then appended:
#
#  - include/preserve all source/destination file systems
#  - represent all network mount points as directories
#
# The filter is sorted; the resulting sorted list is given to "fdo filter_dir"
# which descends the parent boot environment file system hierarchy and outputs
# file and directory names to be copied.

#----------------------------------------

# Exclude mounted boot environments including new BEs destination mountpoint
# Lines from "lumount -X" look like this:
#   <beStatus name="c0t2d0s0" complete="yes" active="yes" \
#   activeOnReboot="yes" busy="no" status="" deletable="no" \
#   mounted="yes" mountPoint="/"/>
# Extract mountPoint= value for all lines with mounted="yes"
#    - add "x mpt" for all currently mounted boot environments
#    - add "x mpt" for the new BEs destination mount point

$LUBIN/lumount -X 2>/dev/null | while read entireLine ; do
	beMntpt=`echo "$entireLine" \
	| /bin/grep '^<beStatus ' \
	| /bin/fgrep ' mounted="yes"' \
	| /bin/fgrep -v ' mountPoint="/"' \
	| /bin/sed 's/.* mountPoint="//' \
	| /bin/cut -d'"' -f1 \
	| $LUETCBIN/ludo xml_decode_string`
	[ -n "$beMntpt" ] && $LUPRINTF -a "$FILTER_FILE" \
'# boot environment %s\nx %s' "$entireLine" "$beMntpt"
done

#----------------------------------------

# Exclude all shared file systems
#    - add "x mpt" for all shared file systems (remote all shared)

$LUETCBIN/ludo get_shared $ABE_ICF $PBE_ICF >> $FILTER_FILE
if [ $? -ne 0 ] ; then
	copy_error_exit "`gettext 'Cannot discover shared file systems.'`"
fi

#----------------------------------------

# Exclude all crash dump files
#    - add "x file" for all files in all crash dump directories
# This directory contains crash dump files that are only pertinent to the
# current boot environment - in addition they are potentially very large.
# Excluding them here helps limit the size of the new be being created.

if [ -d /var/crash ] ; then
	/bin/find /var/crash/* -type f -print 2>/dev/null | \
	    while read entireLine ; do
		$LUPRINTF -a "$FILTER_FILE" 'x %s' "$entireLine"
	done
fi

#----------------------------------------

# For x86 only: Exclude GRUB boot signatures
#    - add "x file" for all files in GRUB boot signature directory
#    - add "x file" for backup boot signature file
# This primary and backup boot signatures are only meaningful in the BE
# they were created in.

if [ "$LU_SYSTEM_ARCH" = i386 ]; then
   if [ -d "$LU_SIGN_DIR" ] ; then
      /bin/find "${LU_SIGN_DIR}"/* -type f -print 2>/dev/null | \
	    while read entireLine ; do
		$LUPRINTF -a "$FILTER_FILE" 'x %s' "$entireLine"
	done
   fi
   $LUPRINTF -a "$FILTER_FILE" 'x %s' "$LU_SIGN_BACKUP"
fi

#----------------------------------------

# Perform the integrity check

do_integrity_check "$FILTER_FILE" "$PBE_MPT"
if [ $? -ne 0 ] ; then
	copy_error_exit "`gettext 'New boot environment integrity compromised \
by file exclusions specified.'`"
fi

#----------------------------------------

# include/preserve all source/destination file systems
#    - add "+ mpt" for each file system copied but not preserved
#    - add "< mpt" for each file system copied but preserved

process_fs_list "$FS_SKIP_LIST" "$FILTER_FILE" "$PBE_ICF" "$ABE_ICF"
anySkipped=$?

#----------------------------------------

# Exclude any zfs datasets - they are treated as global directories
# similar to /export/home

if [ -x /sbin/zfs ]; then
	LC_ALL=C /sbin/zfs list -Ho name -t filesystem |
	    grep -v 'no datasets available' |
	    xargs /sbin/zfs get -Ho value mountpoint 2> /dev/null |
	    grep '^/' | sed -e 's/^/x /' >> "$FILTER_FILE"
fi

#----------------------------------------

# Represent all network mount points as directories
#    - add ". mpt" for all network mount points

$FDO_CMD mountpoints_to_exclude /etc/vfstab /etc/mnttab $PBE_MPT \
    $TMP_REMOVABLE_DEV_FILE >> $FILTER_FILE
if [ $? -ne 0 ] ; then
	copy_error_exit \
	    "`gettext 'Cannot discover shared file system mountpoints.'`"
fi

#----------------------------------------

# exclude /var/tmp and /var/run
#    - add "x item" for all non-directory entries in /var/tmp and /var/run
# These directories contain entries that are only pertinent to the currently
# running instance of Solaris - they are also highly subject to change for
# the duration of the copy.  Excluding them conserves disk space on the target
# boot environment, and prevents "cannot open" or "cannot create" messages
# from being produced by cpio.

/bin/ls -a /var/tmp | sed -e 's/^\.\.$//;s/^\.$//;/^$/d;s/^/\/var\/tmp\//;' | \
    while read entireLine ; do
		$LUPRINTF -a "$FILTER_FILE" 'x %s' "$entireLine"
done

/bin/ls -a /var/run | sed -e 's/^\.\.$//;s/^\.$//;/^$/d;s/^/\/var\/run\//;' | \
    while read entireLine ; do
                $LUPRINTF -a "$FILTER_FILE" 'x %s' "$entireLine"
done

#----------------------------------------

# Normalize the filter file to remove directory/file entries that are
# overridding entries specified by the user to be included/excluded.

normalizeCliFileops "$FILTER_FILE"

#----------------------------------------

# sort the filter list
$FDO_CMD sort_list $PBE_MPT $FILTER_FILE > $FILTER_FILE_2
if [ $? -ne 0 ] ; then
	copy_error_exit \
	    "`gettext 'Cannot create boot environment content filter.'`"
fi

#--------------------------------------------------------------------------

# Output appropriate pre-copy debugging information

$LUPRINTF -lp2D 4 "`gettext 'Primary Boot Environment ICF:\
\n********************\n%R\n********************'`" < "$PBE_ICF"

$LUPRINTF -lp2D 4 "`gettext 'New Boot Environment ICF:\
\n********************\n%R\n********************'`" < "$ABE_ICF"

$LUPRINTF -lp2D 3 "`gettext 'Filter before sorting:\
\n********************\n%R\n********************'`" < "$FILTER_FILE"

$LUPRINTF -lp2D 2 "`gettext 'Final copy filter:\
\n********************\n%R\n********************'`" < "$FILTER_FILE_2"

if [ $LU_DEBUG -gt 0 ] ; then
  $FDO_CMD describe_filter $FILTER_FILE_2
fi

#--------------------------------------------------------------------------

# Populate the new boot environment

# Output appropriate 'we are now copying.' message

if [ "$anySkipped" -eq 0 ] ; then
	$LUPRINTF -lp2 "`gettext 'Copying.'`"
else
	$LUPRINTF -lp2 \
	    "`gettext 'Copying file systems that have not been preserved.'`"
fi

# Do the copy.

( cd $PBE_MPT &&
    $FDO_CMD filter_dir $FILTER_FILE_2 $PBE_MPT |
	LANG=C LC_ALL=C $CPIO_CMD -pPcdum "$dest" 2>$CPIO_ERR 1>&2
)
ret=$?

#
# FS_SKIP_LIST is used in a scenario when the contents of a file system
# need to be preserved. Such a case can happen when a new Boot
# environment is to be created with the root mirrored, and the contents
# of one PBE file system's need to be preserved. Following code will
# create the logical device and raw device entries of such a mirror in the 
# new Boot environment. This is an ugly hack.
#

if [ $ret -eq 0 -a -n "$FS_SKIP_LIST" ]; then
    /usr/sbin/mount -p | /bin/sort -k 3,3 -t' ' | while read device raw mntpt junk ; do
	if [ $mntpt = $dest ]; then
	    (
	    echo .$device
	    echo .$device | /bin/sed 's/\/dsk\//\/rdsk\//g'
	    ) | (cd $PBE_MPT && LANG=C LC_ALL=C $CPIO_CMD -pPcdum "$dest" 2>>$CPIO_ERR 1>&2)
	    ret2=$?
	    if [ $ret2 -ne 0 ]; then
		ret=$ret2
		break
	    fi
	fi
    done
fi

if [ $ret -ne 0 -a -s "$CPIO_ERR" ] ; then
	# Determine why copy failed.
	# If during the copy:
	#  - a source item was deleted,
	#  - a file cannot be opened and was skipped 
	#  - the text %d error, %d errors, or %d error(s)
	# cpio issues an error and exits with a non-zero status
	# Neither of these are fatal errors and can be ignored;
	# this is admittedly an inelegant solution to the problem
	# but it is the way the problem has been handled since the
	# first release of Live Upgrade - when the new copy method
	# is implemented, this kind of error can be detected in a
	# more direct manner.

	# First, remove stray messages from the cpio error output
	/bin/egrep -v '^cpio:.* errno 2,' < "$CPIO_ERR" |
	    /bin/egrep -v '^cpio: Error with .*\(\) of ".*", errno 2.*' |
	    /bin/egrep -v '^[0123456789]* (error[s()]*|blocks)$' |
	    /bin/egrep -v '^cpio: Cannot open.*, skipped, errno.*' |
	    /bin/egrep -v 'LC_ALL=' |
	    /bin/egrep -v ' "/var/(tmp|run)/' > "$CPIO_ERR_TMP"
	mv -f "$CPIO_ERR_TMP" "$CPIO_ERR"

	# the remainder of the copy errors are processed after the
	# zone copy and the lofs mounted libc fix
fi

zdataset="`lulib_get_zfs_dataset_from_mntpt \"$dest\"`"
if [ -n "$zdataset" ]; then
    #
    # If we ran out of room during the copy, no reason to continue now
    #
    zpoolname="`echo \"$zdataset\" | cut -d/ -f1`"
    avail_space="`/sbin/zfs get -Ho value -p avail \"$zpoolname\"`"
    if [ "$avail_space" -lt 1048576 ]; then
	$LUBIN/luumount -f -i "$ABE_ICF"
        /sbin/zfs destroy -r "$zdataset"
        copy_error_exit "`gettext 'Ran out of room during copy operation.'`"
    fi

    # If the destination BE is on a ZFS dataset, then we have to
    # filter out any CPR entries from power.conf and also the rootdev
    # entry from /etc/system.
    if [ -f "$dest/etc/power.conf" ]; then
	grep -v '^statefile.*\/\.CPR' "$dest/etc/power.conf" > "$dest/etc/power.conf.new"
	mv "$dest/etc/power.conf.new" "$dest/etc/power.conf"
    fi
    if [ -f "$dest/etc/system" ]; then
	grep -v '^rootdev:' "$dest/etc/system" > "$dest/etc/system.new"
	mv "$dest/etc/system.new" "$dest/etc/system"
    fi

    # The last thing we do for ZFS is copy the bootlst file into the root
    # pool's dataset
    bootlstdest="/$zpoolname/platform/`uname -m`"
    [ ! -d "$bootlstdest" ] && mkdir -p "$bootlstdest"
    cp "$PBE_MPT/platform/`uname -m`/bootlst" "$bootlstdest"
fi

#--------------------------------------------------------------------------

# Create mount points for shared file systems.
# Need to create mountpoints in the new boot environment that mirror
# currently mounted file systems, except:
# - ignore automounter mounted file systems - the best we can do is to
# -- ignore remote file systems that are not in the /etc/vfstab file
# -- otherwise stale NFS mount points might be accessed which can cause
# -- the process to hang indefinitely
# - ignore mount points that belong to removable devices
# - ignore mount points that belong to file systems that have been copied
# - ignore mount points inside tmpfs; they'll go away on reboot anyway
# - ignore mount points inside zones; we handle zones later

$LUPRINTF -lp2 "`gettext 'Creating shared file system mount points.'`"

remov_devs=`cat $TMP_REMOVABLE_DEV_FILE`

mounted_bes=`/usr/sbin/lumount | /usr/bin/awk '{print $3}'`

zoneroots=`lulib_list_zones | \
    while IFS=: read zoneid zonename state path uuid junk; do \
	echo $path ; \
    done`

mount_list=""

/bin/rm -f "$FLAG_FILE"
/usr/sbin/mount -p | /bin/sort -k 3,3 -t' ' |
    while read special raw mountPoint fsType fsckpass atboot mountopt ; do

    # Ignore mount points that do not begin with "/" and entries
    # that are already inside the ABE (read-only lofs mounts from
    # lumount).
    case $mountPoint in
    $dest/*)	continue;;
    /*)		;;
    *)		continue;;
    esac

    # Ignore entries that are not directories
    [ -d $mountPoint ] || continue

    # Ignore entries that already exist on the ABE
    [ -d "$dest/$mountPoint" ] && continue

    # Ignore any mounts into (within) tmpfs; they disappear on reboot.
    parent=`dirname $mountPoint`
    [ `df -k $parent | awk '{ fst=$1 } END { print fst }'` = swap ] && continue

    # Ignore entries related to running or mounted zones.  We will create
    # these when we process the zones themselves.
    lulib_subdir_list $mountPoint/ $zoneroots && continue

    # Determine if the entry is remote or not
    isRemote=no
    if [ -f /etc/dfs/fstypes ]; then
	/bin/egrep -s -e "^$fsType " /etc/dfs/fstypes && isRemote=yes
    elif [ $fsType = nfs -o $fsType = autofs -o $fsType = cachefs ]; then
	isRemote=yes
    fi

    # Ignore entries that are remote but not listed in vfstab
    if [ $isRemote = yes ]; then
	/bin/egrep -s -e ".*[ 	]$mountPoint[ 	].*" \
	    "$PBE_MPT/etc/vfstab" || continue
    fi

    # Ignore entries that belong to removable devices
    in_list $mountPoint/ $remov_devs && continue

    # Ignore entries that belong to file systems already copied
    in_list $mountPoint $compul_list && continue

    # if $mountPoint is the root mount point of a BE, we know for sure 
    # that it will be removed later, so we do not create this
    # mount point.
    in_list $mountPoint $mounted_bes && continue

    # Check whether $mountPoint is a mount point under an already mounted
    # point.  If so we do not want to create a directory.
    lulib_subdir_list $mountPoint/ $mount_list && continue

    # $mountPoint is a mount point, not on a mount point(sub mount point).
    # So we store it in variable $mount_list, with a '/' appended,
    # so that when a mount point which is mounted on $mountPoint is visited,
    # we can segregate it, with our logic of expr(1) command.
    mount_list="$mount_list $mountPoint/"

    # make the directory for $dest/$mountPoint
    if /bin/mkdir -p "$dest/$mountPoint"; then
	$LUPRINTF -lp2D 2 "`gettext 'Created ABE <%s> mount point <%s>.'`" \
	    "$ABE_NAME" "$dest/$mountPoint"
    else
	$LUPRINTF -Eelp2 \
	    "`gettext 'Unable to create ABE <%s> mount point <%s>.'`" \
	    "$ABE_NAME" "$dest/$mountPoint"
	/bin/touch "$FLAG_FILE"
    fi

    # Clone directory tree permissions
    if $LUETCBIN/ludo clone_directory_tree "$PBE_MPT" "$dest" "$mountPoint"
    then
	$LUPRINTF -lp2D 2 "`gettext 'Cloned directory permissions for \
ABE <%s> PBE path <%s> ABE path <%s> mount point <%s>.'`" \
	    "$ABE_NAME" "$PBE_MPT" "$dest" "$mountPoint"
    else
	$LUPRINTF -Eelp2 "`gettext 'Unable to clone directory \
permissions for ABE <%s> PBE path <%s> ABE path <%s> mount point <%s>.'`" \
	    "$ABE_NAME" "$PBE_MPT" "$dest" "$mountPoint"
	/bin/touch "$FLAG_FILE"
    fi
done

if [ -f "$FLAG_FILE" ] ; then
  /bin/rm -f "$FLAG_FILE"
  $LUPRINTF -Eelp2 \
      "`gettext 'Unable to access active mount points on ABE <%s>.'`" \
      "$ABE_NAME"
  copy_error_exit
fi

#--------------------------------------------------------------------------

# If there are non-global zones in the new BE, then one of three things
# is true for each zone:
#
#   A.	The zone path is on an unshared file system.  In this case, it
#	will be writable.   Just clear out the contents and copy over.
#   B.	The zone path is on a shared file system.  The zone path won't
#	be writable, so we'll need to change it and resolve the lofs
#	mounts back to the underlying file system.
#   C.	The zone path is unresolved in the source BE, or the source BE
#	is just unavailable.  Warn, but otherwise do nothing.
#
# Once the zone root has been copied over, we go through the mount
# point replication logic within the zone.  We can't mount up the new
# zone yet to do this (because the mount points are missing), nor can
# we trust the output of commands run within the source zone.  We must
# therefore find the mount points for the zone by looking at the
# global zone, and then convert and replicate them in the new non-
# global zone.  This is safe because the output of "mount" never
# includes symlinks anywhere in the path.
#
# Finally, once the mount points have been created, we can mount up
# the non-global zone, enter it, and copy the contents of file systems
# within the zone.

if [ -d "$dest/etc/zones" ]; then
    if [ -f "$PBE_MPT/etc/zones/lu_suffix" ]; then
	STRIPSFX="-"`cat "$PBE_MPT/etc/zones/lu_suffix"`
    else
	STRIPSFX=
    fi
    ADDSFX=$ABE_NAME
    echo "$ADDSFX" > "$dest/etc/zones/lu_suffix"
    SAVEIFS="$IFS"
    /bin/grep "^/dev/" /etc/mnttab | /bin/grep -v "lofs" | cut -f2 > $MNTTAB_TMP_FILE
    abe_pool=`lulib_get_zfs_dataset_from_mntpt "$dest" | cut -d/ -f1`
    lulib_list_zones -c "$dest" |
    while IFS=: read zoneid zonename state path uuid junk; do
	IFS="$SAVEIFS"
	if [ $zonename = global ]; then
	    continue
	fi
	zoneskip_check $zonename $path $FS_SKIP_LIST $dest $MNTTAB_TMP_FILE
        zoneSkipped=$?
	# If the zone belongs to filesystem that is preserved (present in 
	# the FS_SKIP_LIST file), then skipping the zone copy.
        if [ $zoneSkipped -eq 0 ] ; then
            continue
        fi

	if lulib_path_writable "$path" 700; then
	    rawpath="$path"
	    newpath="$path"
	    newrawpath="$path"
	else
	    newpath=`echo $path | sed "s/$STRIPSFX"'$//;s/$/-'"$ADDSFX/"`
	    zonecfg -R "$dest" -z $zonename set -F zonepath="$newpath"
	    rawpath=`lulib_resolve_lofs "$dest" "$path"`
	    newrawpath=`echo $rawpath | sed "s/$STRIPSFX"'$//;s/$/-'"$ADDSFX/"`
	fi

	#
	# if the source is a zfs dataset mountpoint then snapshot/clone.
	# if the snapshot and clone already exist then destroy them
	# before cloning
	#
	orig_path=`zoneadm -R "$PBE_MPT" -z $zonename -u "$uuid" list -p | \
	    awk -F: '{print $4}'`
	zone_dataset_name=`lulib_get_zfs_dataset_from_mntpt $orig_path`
	if [ -z "$zone_dataset_name" ]; then
		lofspoint=`/usr/sbin/mount -p |
		    /usr/bin/nawk -v LOC="$path" '$3 == LOC {print $1; exit}'`
		if [ -n "$lofspoint" ]; then
			# found a loopback mount - is it a dataset?
			zone_dataset_name=`lulib_get_zfs_dataset_from_mntpt $lofspoint`
		fi
	fi

	zone_pool=`echo "$zone_dataset_name" | cut -d/ -f1`

	do_copy=1
	dest_is_zfs=""
	if [ -n "$zone_dataset_name" ] ; then
		if [ -n "$abe_pool" ]; then
			abe_dataset=""
			pbe_root_fstype=`awk -F: '$2=="/" {print $4}' < $PBE_ICF`
			if [ $pbe_root_fstype = "zfs" ] ; then
			    pbe_root_ds=`awk -F: '$2=="/" {print $3}' < $PBE_ICF`
			    abe_root_ds=`awk -F: '$2=="/" {print $3}' < $ABE_ICF`
			    abe_dataset=`echo "$zone_dataset_name"|sed "s:^${pbe_root_ds}/:${abe_root_ds}/:"`
			    [ ${abe_dataset} = ${zone_dataset_name} ] && abe_dataset=""
		        fi

			if [ -n "$abe_dataset" ]; then
				mntprop=`zfs get -Ho value mountpoint "$zone_dataset_name"`

				#Ideally, zone copy should take place in the code block that follows below
				#after the creation of datasets. However, because of existing bug 6727337,
				#zones are getting copied to wrong location as part of global zone file
				#system copy done with cpio above.
				#the following rm removes the zone files from their incorrect location.
				#otherwise, dataset fails to mount with error directory not empty
				rm -rf $path 2>/dev/null
				/sbin/zfs create -o canmount=noauto -p "$abe_dataset"
				if [ $mntprop = "legacy" ] ; then
					/sbin/zfs set mountpoint=legacy "$abe_dataset"
				fi
				/sbin/zfs set zpdata:rbe=$ABE_NAME "$abe_dataset"
				/sbin/zfs set zpdata:zn=$zonename "$abe_dataset"
				uplevel=`dirname $abe_dataset`
				cm=`/sbin/zfs list -Ho canmount $uplevel`
				while [ "`basename $uplevel`" != "$ABE_NAME" -a "$cm" != "noauto" ]; do
					/sbin/zfs set canmount=noauto $uplevel
					uplevel=`dirname $uplevel`
					cm=`/sbin/zfs list -Ho canmount $uplevel`
				done
				/usr/bin/mkdir -p "$path"
				dsname="$abe_dataset"
				if [ $mntprop != "legacy" ] ; then
					newpath="$path"
					newrawpath="$path"
				fi
				lulib_mount_pathname "$abe_dataset" "$newrawpath" >/dev/null
				dest_is_zfs=1
			else
				# instead of copying the zone to the
				# new pool, we'll just snapshot and clone
				# within the existing pool
				do_copy=0
			fi
		else
			# this is a ufs->ufs live upgrade migration, so
			# we can just snapshot/clone the datasets, and we
			# can avoid the copy operation
			do_copy=0
		fi
	elif [ -n "$abe_pool" ]; then
		# We come in here if the zone is ufs-based, but the destination
		# BE is zfs.  In this case, we want to check to see if the
		# zone is the sole occupant of the ufs slice that it's in.
		# If so, that gives us leave to generate a dataset for it.
		mountdev=`mount -p | nawk -v MP="$orig_path" '$3 == MP && $4 == "ufs" {print $1}'`
		if [ -n "$mountdev" ]; then
			basepath=/zoneds`expr $path : "$dest"'\(.*\)'`
			basepath=`echo $basepath | sed "s/$STRIPSFX"'$//;s/$/-'"$ADDSFX/"`
			dsname="${abe_pool}/ROOT/${ABE_NAME}$basepath"
			newpath="$dest$basepath"
			/sbin/zfs create -p "$dsname"
			[ $? != 0 ] && copy_error_exit
			zonecfg -R "$dest" -z "$zonename" set -F zonepath="$newpath"
			/sbin/zfs set canmount=noauto "$dsname"
			/sbin/zfs set zpdata:rbe=$ABE_NAME "$dsname"
			/sbin/zfs set zpdata:zn=$zonename "$dsname"
			newrawpath="$newpath"
			echo "$ABE_NAME" > "$newpath/lu_moved"
			uplevel=`dirname $dsname`
			cm=`/sbin/zfs list -Ho canmount $uplevel`
			while [ "`basename $uplevel`" != "$ABE_NAME" -a "$cm" != "noauto" ]; do
				/sbin/zfs set canmount=noauto $uplevel
				uplevel=`dirname $uplevel`
				cm=`/sbin/zfs list -Ho canmount $uplevel`
			done
			dest_is_zfs=1
		fi
	fi

	if [ $do_copy = 0 ]; then
		clone_name=`echo $zone_dataset_name |
		    sed "s/$STRIPSFX"'$//;s/$/-'"$ADDSFX/"`

		# if zone_dataset_name is a pool name, we prefix the clone name
		# with the pool name, so that there's a valid dataset on top of it.
		echo $zone_dataset_name | grep "/" > /dev/null
		if [ $? -ne 0 ] ; then
			clone_name="$zone_dataset_name/$clone_name"
		fi

		lulib_clone_BE_dataset "$zone_dataset_name" "$ABE_NAME" "$clone_name"
		if [ $? != 0 ]; then
			copy_error_exit
		fi


		/sbin/zfs set zpdata:rbe=$ABE_NAME $clone_name
		/sbin/zfs set zpdata:zn=$zonename $clone_name

		zone_ds_mntprop=`/sbin/zfs get -Ho value mountpoint $zone_dataset_name`
		if [ "$zone_ds_mntprop" = "legacy" ] ; then
			[ ! -d $newrawpath ] && /usr/bin/mkdir -p "$newrawpath"
			/sbin/mount -F zfs "$clone_name" "$newrawpath"
			echo "$ABE_NAME" > "$newrawpath/lu_moved"
		else
			clonepath=`echo $path | sed "s/$STRIPSFX"'$//;s/$/-'"$ADDSFX/"`
			zonecfg -R "$dest" -z $zonename set -F zonepath="$clonepath"
			clonerawpath=`echo $clonepath | sed "s:${dest}/:/:"`
			/sbin/zfs set mountpoint="$clonerawpath" $clone_name
			/sbin/zfs mount "$clone_name"
			echo "$ABE_NAME" > "$clonerawpath/lu_moved"
			/sbin/zfs set canmount=off "$clone_name"
		fi
	else
		$LUPRINTF -lp2 "`gettext 'Copying root of zone <%s> to <%s>.'`" \
		    "$zonename" "$newpath"
		if [ -d "$newpath/lost+found" -o -n "$dest_is_zfs" ]; then
		    # If the zone path is at the top of a file system (as
		    # evidenced by the existence of lost+found inside the zone
		    # path), then lumake or lucreate will have done lumkfs on
		    # it first, so it's already empty.  If it's shared, then
		    # that's just an error case, so no reason to try to
		    # remove anything.
		    :
		elif [ -d "$newpath" ]; then
		    (
			# Remove all the contents without attempting to remove
			# '.' or '..'.  The rm command will complain on
			# either of those.
			cd "$newrawpath" && \
			    rm -rf `echo .?* * | \
			    sed -e 's/^\.\. //;s/ \.\. / /;s/ \.\.$//'`
		    )
		else
		    mkdir -p "$newrawpath"
		fi
		chmod 700 "$newrawpath"
		if [ ! -d "$newpath" ]; then
		    $LUPRINTF -Eelp2 "Internal error: $newpath is missing"
		    continue
		fi
		if [ "$newpath" != "$newrawpath" -o -n "$dest_is_zfs" ]; then
		    echo "$ABE_NAME" > "$newrawpath/lu_moved"
		fi
		# 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 "$PBE_MPT" -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=
		    else
			$LUPRINTF -Eelp2 \
			  "`gettext 'Zone <%s> in BE <%s> is in <%s> state.'`" \
			  $ozonename "$PBE_NAME" $ostate
			/usr/sbin/zoneadm -R "$dest" -z $zonename \
			    mark incomplete
			continue
		    fi

		    # Make sure some famous things get set up first.
		    for dir in etc/svc/volatile proc \
			system/contract system/object
		    do
			mkdir -p "$newrawpath/root/$dir"
		    done
		    mkdir -m 1777 -p "$newrawpath/root/tmp"
		    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/lucopy.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=${CPIO_ERR}.$ozonename
		    (
			cd "$oldpath" &&
			find . -xdev \
			    \( -type d -exec fgrep -x '{}' $excl \; -prune \) \
			    -o -print |
			sort -r |
			$CPIO_CMD -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 "$PBE_NAME" $zonecpio
			/usr/sbin/zoneadm -R "$dest" -z $zonename \
			    mark incomplete
			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/lucopy.zonedir.$$
		    rm -rf $tdir
		    mkdir $tdir
		    lulib_get_zone_icffs "$ABE_ICF" $zonename |
		    awk '$4 != "lofs" { print $3; }' > /tmp/lucopy.zonefs.$$
		    zonecfg -R "$dest" -z $zonename info inherit-pkg-dir |
		    awk '$1 == "dir:" { print $2; }' > /tmp/lucopy.zoneipd.$$
		    lulib_get_zone_icffs "$ABE_ICF" $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/lucopy.zonefs.$$
				    cat /tmp/lucopy.zoneipd.$$
				) | sed 's+.*+^&/+' |
				zlogin $ozonename \
				    "cat > /tmp/lucopy.excl.$$; \
				    (
					if [ -s /tmp/lucopy.excl.$$ ]; then
					    cd $zroot$mountpoint && \
					    find . -depth -print | \
					    egrep -vf /tmp/lucopy.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
		    rmdir $tdir
		    rm /tmp/lucopy.zonefs.$$ /tmp/lucopy.zoneipd.$$ $zonecpio
		    [ -n "$dest_is_zfs" ] && lulib_unmount_pathname "$dsname"
		done
	fi
    done
fi

# This code repairs the incorrect copy of the libc library that is actually
# a lofs mount of libc_hwcapX. 
# Make sure that we are copying from the parent BE.
if [ "$PBE_NAME" = "$CURR_BE" ] ; then
    # loop over the lofs mounted libc's on the system
    /sbin/mount -p |
    /usr/bin/awk '$3 ~ /\/lib\/libc\.so\.1$/ { print $0 }' |
    while read special raw mountpoint fstype fsckpass atboot mountopt; do
	# remove the bad copy
        /bin/rm -f "$dest$mountpoint"
	# umount the lofs mount
        /usr/sbin/umount $mountpoint && (
	    # copy the underlying file
            $CP_CMD -p $mountpoint "$dest$mountpoint" 2>/dev/null
	    # reestablish the lofs mount
            /usr/sbin/mount -OF $fstype $special $mountpoint
        )

            # This is the error message given by cpio if /lib/libc.so.1 is a
            # lofs mount.  Remove it from the cpio error log.
            CPIO_LIBC_ERR="$mountpoint\", errno 18, Cross-device link"

            if [ -f "$CPIO_ERR" ] ; then
		    /bin/fgrep -v "$CPIO_LIBC_ERR" "$CPIO_ERR" > "$CPIO_ERR_TMP"
		    /bin/mv "$CPIO_ERR_TMP" "$CPIO_ERR"
            fi
    done
fi

# now finish processing cpio errors from the BE creation
if [ -s "$CPIO_ERR" ] ; then
	cnt=`/bin/wc -l < "$CPIO_ERR"`
	/bin/mv "$CPIO_ERR" "$CPIO_ERROR_FILE"
	$LUPRINTF -fWelp2 "`gettext 'The file <%s> contains a list \
of <%d> potential problems (issues) that were encountered while populating \
boot environment <%s>.'`" "$CPIO_ERROR_FILE" $cnt "$ABE_NAME"
	$LUPRINTF -fIelp2 "`gettext 'You must review the issues \
listed in <%s> and determine if any must be resolved. In general, you can \
ignore warnings about files that were skipped because they did not exist or \
could not be opened. You cannot ignore errors such as directories or files \
that could not be created, or file systems running out of disk space. You \
must manually resolve any such problems before you activate boot \
environment <%s>.'`" "$CPIO_ERROR_FILE" "$ABE_NAME"
fi
/bin/rm -f "$CPIO_ERR" "$CPIO_ERR_TMP"

#--------------------------------------------------------------------------

# Do processing only for x86 boot partition on intel platforms.

/bin/grep -s -v '^#' /etc/vfstab | \
    /bin/grep "[ 	]/boot[ 	]*pcfs[ 	]" >/dev/null

if [ $? -eq 0 -a "$LU_SYSTEM_ARCH" = "i386" ] ; then
	$LUPRINTF -lp2D - "`gettext 'Processing /boot partition.'`"

	diskid="`/bin/grep -s -v '^#' /etc/vfstab | \
	    /bin/grep \"[ 	]/boot[ 	]*pcfs[ 	]\" | \
	    /bin/awk '{print $1}' | /bin/sed -e 's:p0\:boot::g'`"
	diskid="`/bin/basename $diskid`"

# Obtain the disk table; it will look something like the following:
#
# * Id    Act  Bhead  Bsect  Bcyl    Ehead  Esect  Ecyl    Rsect    Numsect
#   130   128  27     28     0       242    9      553     1728     8897472
# 
# Delete all blank lines, and all lines that begin with *, leaving
# only actual fdisk entries that we can scan looking for the X86BOOT
# partition

	/usr/sbin/fdisk -W - /dev/rdsk/${diskid}p0 | /bin/grep -v '^*' | \
	    /bin/grep -v '^$' > $TMP_FDFILE1

	num=1

	/bin/rm -f "$FLAG_FILE"
	while read id act bhead bcyl ehead ecyl rsect numsect
	do
		# Ignore entry if not X86 /boot partition
		# ID '190' is the X86BOOT partition (see man fdisk(1M))

		if [ $id -ne "190" ] ; then
			num=`/bin/expr $num + 1`
			continue
		fi

		# Found X86 boot partition - save current boot partition
		bootpart_id=/dev/rdsk/${diskid}p$num
		$LUPRINTF -lp1 "`gettext 'CBE <%s> boot device is <%s>.'`" \
		    "$CURR_BE" "$bootpart_id"
		ERRMSG="`/bin/dd if=$bootpart_id \
		    of=/etc/lu/.dd_x86_boot_copy 2>&1`"
		if [ $? -ne 0 ] ; then
			[ -n "$ERRMSG" ] && \
			    $LUPRINTF -Eelp2 '%s' "$ERRMSG"
			$LUPRINTF -Eelp2 "`gettext 'Unable to save copy of \
active BE <%s> X86 boot device.'`" "$CURR_BE" "$bootpart_id"
			/bin/touch "$FLAG_FILE"
			exit 0
		fi

		if [ "$PBE_NAME" -eq "$CURR_BE" ] ; then
			lobootdev=`/usr/sbin/lofiadm -a \
			    /etc/lu/.dd_x86_boot_copy`
			if [ $? -ne 0 ] ; then
				[ -n "$ERRMSG" ] && \
				    $LUPRINTF -Eelp2 '%s' "$ERRMSG"
				$LUPRINTF -Eelp2 "`gettext 'Unable to make \
lo-device <%s>.'`" "/etc/lu/.dd_x86_boot_copy"
				/bin/touch "$FLAG_FILE"
				exit 0
			fi
			source_boot_dev="/tmp/tmpbootdev.$$"
			/bin/mkdir $source_boot_dev
			/usr/sbin/mount -F pcfs $lobootdev $source_boot_dev
			if [ $? -ne 0 ] ; then
				[ -n "$ERRMSG" ] && \
				    $LUPRINTF -Eelp2 '%s' "$ERRMSG"
				$LUPRINTF -Eelp2 "`gettext 'Unable to mount \
lo-device <%s>.'`" "$lobootdev"
				/bin/touch "$FLAG_FILE"
				exit 0
			fi
		else
			source_boot_dev="$PBE_MPT/boot"
		fi

		if [ -f $source_boot_dev/mdbootbp ] ; then
			mdboot="$source_boot_dev/mdbootbp"
		else
			mdboot="$source_boot_dev/mdboot"
		fi

		echo y | /usr/lib/fs/pcfs/mkfs -F pcfs \
		    -o S,s,B=$mdboot,b=BOOT,i=$source_boot_dev/strap.com \
		    /dev/rdsk/${diskid}p0:boot >> $LOGFILE 2>&1
		$LUPRINTF -lp1 "`gettext 'Copying X86 boot device.'`"

		OLD_PWD=`/bin/pwd`
		cd $source_boot_dev
		/bin/find "." -mount \! -type s -print 2> $FIND_ERR | \
		    $CPIO_CMD -pPcdum "/boot" 2>&1 | $LUBIN/lustripcpioerr
		if [ $? -ne 0 ] ; then
			$LUPRINTF -Eelp2 "`gettext 'Unable to copy PBE <%s> \
boot partition contents to BE <%s>.'`" "$PBE_NAME" "$ABE_NAME"
			/bin/touch "$FLAG_FILE"
			exit 0
		fi
		cd $OLD_PWD

		ERRMSG="`/bin/dd if=$bootpart_id \
		    of=$dest/etc/lu/.dd_x86_boot_copy 2>&1`"
		if [ $? -ne 0 ] ; then
			[ -n "$ERRMSG" ] && \
			    $LUPRINTF -Eelp2 '%s' "$ERRMSG"
			$LUPRINTF -Eelp2 "`gettext 'Unable to make dd copy \
of ABE <%s> X86 boot device <%s>.'`" "$ABE_NAME" "$bootpart_id"
			/bin/touch "$FLAG_FILE"
			exit 0
		fi

		if [ "$PBE_NAME" -eq "$CURR_BE" ] ; then
			# sync data to storage medium before unmounting
			/bin/sync
			# unmount source boot environment
			lulib_unmount_pathname $source_boot_dev
			if [ $? -ne 0 ] ; then
				[ -n "$ERRMSG" ] && \
				    $LUPRINTF -Eelp2 '%s' "$ERRMSG"
				$LUPRINTF -Eelp2 "`gettext 'Unable to umount \
lo-device <%s>.'`" "$lobootdev"
				/bin/touch "$FLAG_FILE"
				exit 0
			fi
			/usr/sbin/lofiadm -d /etc/lu/.dd_x86_boot_copy
			if [ $? -ne 0 ] ; then
				[ -n "$ERRMSG" ] && \
				    $LUPRINTF -Eelp2 '%s' "$ERRMSG"
				$LUPRINTF -Eelp2 "`gettext 'Unable to remove \
lo-device <%s>.'`" "$lobootdev"
				/bin/touch "$FLAG_FILE"
				exit 0
			fi
		fi
		# sync data to storage medium before unmounting
		/bin/sync
		# unmount boot partition
		lulib_unmount_pathname /boot
		if [ $? -ne 0 ] ; then
			[ -n "$ERRMSG" ] && \
			    $LUPRINTF -Eelp2 '%s' "$ERRMSG"
			$LUPRINTF -Eelp2 "`gettext 'Unable to umount X86 \
boot device <%s> before restore.'`" "$bootpart_id"
			/bin/touch "$FLAG_FILE"
			exit 0
		fi
		ERRMSG="`/bin/dd if=/etc/lu/.dd_x86_boot_copy \
		    of=$bootpart_id 2>&1`"
		if [ $? -ne 0 ] ; then
			[ -n "$ERRMSG" ] && \
			    $LUPRINTF -Eelp2 '%s' "$ERRMSG"
			$LUPRINTF -Eelp2 "`gettext 'Unable to restore X86 \
boot device <%s>.'`" "$bootpart_id"
			/bin/touch "$FLAG_FILE"
			exit 0
		fi
		/usr/sbin/mount /boot
		if [ $? -ne 0 ] ; then
			[ -n "$ERRMSG" ] && \
			    $LUPRINTF -Eelp2 '%s' "$ERRMSG"
			$LUPRINTF -Eelp2 "`gettext 'Unable to mount X86 \
boot device <%s> before restore.'`" "$bootpart_id"
			/bin/touch "$FLAG_FILE"
			exit 0
		fi
	done < $TMP_FDFILE1

	if [ -f "$FLAG_FILE" ] ; then
		/bin/rm -f "$FLAG_FILE"
		copy_error_exit
	fi
fi

#--------------------------------------------------------------------------

# Remove menu.lst from the ABE's software database to avoid pkgchk errors.

if [ "$LU_SYSTEM_ARCH" = i386 ]; then
	PKGNAME=`/bin/nawk -v BOOT_MENU="/$BOOT_MENU" \
'index($1, BOOT_MENU) {print $NF}' "$dest/var/sadm/install/contents"`
	if [ -n "$PKGNAME" ]; then
		/usr/sbin/removef -R "$dest" $PKGNAME "/$BOOT_MENU" > /dev/null
		/usr/sbin/removef -f -R "$dest" $PKGNAME
	fi
fi

# Create and update the compare database for the boot environment just created.

if [ "$CREATECOMPARE" = "yes" -o "$CREATECOMPARE" = "YES" ] ; then
	# Create the compare database for the new boot environment
	$LUPRINTF -lp1 "`gettext 'Creating compare databases for boot \
environment <%s>.'`" "$ABE_NAME"
	cc_currBe="`echo $CURR_BE | /bin/sed 's/ /___/g'`"
	cc_abeName="`echo $ABE_NAME | /bin/sed 's/ /___/g'`"
	cc_databaseFile="$LU_COMPARE_DATABASE_DIR/$cc_currBe:$cc_abeName"
	$CP_CMD /dev/null "$cc_databaseFile"
	for cc_filsys in $compul_list ; do
		$LUPRINTF -lp1 "`gettext 'Creating compare database for \
file system <%s>.'`" "$cc_filsys"
		$LUBIN/compare -c -m "$dest" -p "$cc_filsys" \
-o "$cc_databaseFile" -M -S
	done

	# Update the compare database on the new boot environment
	lulib_update_compare "$dest" "$ABE_NAME"
else
	$LUPRINTF -lp1 "`gettext 'Skipping creation of compare databases for \
boot environment <%s> (<%s> set to <%s>)'`" "$ABE_NAME" 'CREATECOMPARE' \
"$CREATECOMPARE"
fi

#--------------------------------------------------------------------------

# Remove COPY_LOCK, tmp vfstab, and DelayUpdate on ABE if present.

/bin/rm -fr $dest$COPYLOCK $dest/etc/lu/DelayUpdate/* \
$dest/etc/vfstab.pf2 $dest/etc/vfstab.pf1 $dest/etc/vfstab.sav

# Unmount the ABE slices after the comparison is complete.

unmountbe ABE "$ABE_NAME" "$ABE_ICF" "$dest" "error_exit 2"

#--------------------------------------------------------------------------

# Update the compare database on all boot environments.

if [ "$CREATECOMPARE" = "yes" -o "$CREATECOMPARE" = "YES" ] ; then
  lulib_update_compare
fi

#--------------------------------------------------------------------------

# Send a mail to root on problems encountered during cpio on file systems
# other than special processing.

if [ -n "$ERR_FLG" ] ; then
	send_mail_to_root
fi

if [ "$MAILLOGTO" != "" -a -s /etc/lu/lu.log ] ; then
	/bin/cat $LU_LUTAB_FILE /etc/lu/ICF.* /etc/lu/vtoc.* /etc/vfstab \
	    /etc/lu/lu.log 2> /dev/null > /tmp/$$.mail
	/bin/mailx -s "Live Upgrade Copy Log" $MAILLOGTO < /tmp/$$.mail
	/bin/rm -f /tmp/$$.mail
fi

#--------------------------------------------------------------------------

# Unmount the source primary boot environment if it is not the current
# boot environment.

if [ "$PBE_NAME" != "$CURR_BE" ] ; then
    unmountbe PBE "$PBE_NAME" "$PBE_ICF" "$PBE_MPT" "return 1"
else
    unmountzones PBE "$PBE_NAME" "$PBE_MPT"
fi

# Successful!

exit_script 0
