#!/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	"@(#)lumake.sh	5.26	09/07/23 SMI"
#
# USAGE:        lumake [-l error_log] -t time [-o outfile] [-s SRC_Name] \
#		   -n BE_Name [-m address] [-X] 
#               lumake [-l error_log] [-o outfile] [-s SRC_Name] -n BE_Name [-X]
#           Internal interface :
#            lumake [-l error_log] [-u] -t time [-o outfile] -n BE_Name \
#		-i INODE_ICF
#            lumake [-l error_log] [-p preserve] [-o outfile] [-u] [-x debug] \
#		[-Z] -n BE_Name -i INODE_ICF
#	     lumake [-b copy-lock-pid] -n BE_Name
# MODIFICATIONS: added -u option to internal interface. specify -u to skip check
#                if update is complete.
#
# FUNCTION:     driver program to call lumk_iconf, lumkfs, lupop,
#		and lustat_set.  If the ABE and PBE are zfs based and in the
#		same pool then the calls to lumkfs and lupop are replaced with
#		a call luclonefs.
# INPUT:        logfile - file were errors will be logged
#		outfile - messages that are normally displayed on the tty
#			  are redirected to outfile if it is specified.
#		time - Schedule copy to be done at "time" (time is in at(1M)
#			format).
#		BE_Name - ASCII string for BE name (no ':' or '"' allowed)
#
# OUTPUT:
# DEV:          JKJ
#
#
# ALGORITHM:
# Check for "Copy Lock". If it exists, exit with error. 
# Dot in COPYLOCK contents
# verify the all required PBE file systems are mounted
# if '-t' option is specified, validate $TIME
# Call lumk_iconf to produce an ICF. 
# Make sure branded zones with non-shared root are halted.
# If '-t time' is specified, set up 'at(1)' job, change Copy lock 
#   status to "SCHEDULED", and exit 0
# Set "Copy Lock" to ACTIVE state.
# Mark the ABE as Not Complete.
# Call lumkfs to create file systems.
# Call lupop to populate file systems.
# Call lustat_set to update the BE status in the lutab.
# Remove copy lock.
#
################################################################################

LU_PROG_FULL_PATH="$0"
LU_PROG_NAME="`basename ${LU_PROG_FULL_PATH}`"; export LU_PROG_NAME
TMP_RESULT_FILE="/tmp/.lumake.results.tmp.$$"
FILTER_FILE="/tmp/.lumake.filter_one_.$$"
FS_SKIP_LIST="/tmp/.lumake.fs_skip_list.$$"

################################################################################
# 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 [ -X ] [ -l error_log ] [ -o outfile ] \
-n BE_name [ -t time [ -m email_address ] ]'`" "${LU_PROG_NAME}"
  ${LUPRINTF} -Ip2 \
      "`gettext 'Any BE_name should be enclosed in single quotes.'`"
  if [ -z "$1" ] ; then
    exit_script 3 
  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>
################################################################################

err_exit_script()
{
  ${LUPRINTF} -lp2D - "`gettext 'Removing copy lock.'`"
  rm -f $COPYLOCK
  exit_script "$1"
}

exit_script()
{
  # If external interface remove INODE_ICF
  if [ -z "${flag_i}" -a -n "${INODE_ICF}" ] ; then
    /bin/rm -f $INODE_ICF
  fi

  # Remove temporary files and directories
  /bin/rm -f "${TMP_RESULT_FILE}" "${FILTER_FILE}" "${TMP_MENU_LST}"
  /bin/rmdir "${TMP_MENU_MNT}" > /dev/null 2>&1

  # Remove the skip list file
  /bin/rm -f "${FS_SKIP_LIST}"

  # Determine the exit status code.

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

  exit "${retcode}"
}

################################################################################
# Name:		<main>
# Description:	Main code (outside of any function definitions) - executed at
#		script start-up.
# 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

# Default global variables we expect to be set from /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

trap "" 1 2 3 15

TIME=""
TIME_CHECK=/tmp/time_check.$$
TMP_LOCK=/etc/lu/tmp/COPY_LOCK.$$
BYPASS_ID="OFF"
ABE_NAME=""
PBE_NAME=""
INODE_ICF=""
ABE_ICF=""
PBE_ICF=""
MAILTO=""
TMP_MENU_LST="/etc/lu/lumake_menu_lst.$$"
TMP_MENU_MNT="/tmp/.lumake.mntpt.1.$$"

# Remove temporary files and directories
/bin/rm -f "${TMP_RESULT_FILE}" "${FILTER_FILE}" "${FS_SKIP_LIST}" \
    "${TMP_MENU_LST}"
/bin/rmdir "${TMP_MENU_MNT}" > /dev/null 2>&1

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

# Reset all command line parse flags to default values.
flag_Z="" # -Z - fmli interface in use.
flag_b=""
flag_c=""
flag_i=""
flag_l="" # -l f - log file path.
flag_m=""
flag_n=""
flag_o="" # -o f - output file path.
flag_s=""
flag_t=""
flag_x="" # -x n - set debug level to n (PRIVATE).

while [ $# -ne 0 ] ; do
  while getopts b:ci:l:m:n:o:p:s:t:x:XZ c ; do
    case $c in
      b) # By-pass ID (-b id). Used to ensure two lumakes don't get run at the
	 # same time. But also allows scheduled lumake to run correctly.
	 lulib_cannot_duplicate_option "${flag_b}" "${OPTARG}" "-b"
	 flag_b="${OPTARG}"
	 BYPASS_ID=${OPTARG}
	 ;;

      c) # Called in the context of an lucreate. Don't check for menu
	 # propagation in this case as lucreate already does that.
	 lulib_cannot_duplicate_option "${flag_c}" "yes" "-c"
	 flag_c="yes"
	 ;;

      i) lulib_cannot_duplicate_option "${flag_i}" "${OPTARG}" "-i"
	 flag_i="${OPTARG}"
	 INODE_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}"
	 ;;

      m) lulib_cannot_duplicate_option "${flag_m}" "${OPTARG}" "-m"
	 flag_m="${OPTARG}"
	 MAILTO="${OPTARG}"
	 ;;

      n) lulib_cannot_duplicate_option "${flag_n}" "${OPTARG}" "-n"
	 flag_n="${OPTARG}"
	 ABE_NAME=${OPTARG}
	 ABE_OPT="-n \"$ABE_NAME\""
	 ;;

      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 f - preserve mount point (PRIVATE).
	 if [ ! -d "$OPTARG" -a "$OPTARG" != "-" ] ; then
	   ${LUPRINTF} -Eelp2 \
	       "`gettext 'Argument <%s> to -p option is not a directory.'`" \
	       "${OPTARG}"
	   exit_script
	 fi
	 ${LUPRINTF} +X -a "${FS_SKIP_LIST}" '%s' "${OPTARG}"
	 ;;

      s) lulib_cannot_duplicate_option "${flag_s}" "${OPTARG}" "-s"
	 flag_s="${OPTARG}"
	 PBE_NAME=${OPTARG}
	 ;;

      t) lulib_cannot_duplicate_option "${flag_t}" "${OPTARG}" "-t"
	 flag_t="${OPTARG}"
	 TIME="${OPTARG}"
	 ;;

      x) # -x n - set debug level to n (PRIVATE).
	 # This overrides the default setting read from /etc/default/lu
	 lulib_cannot_duplicate_option "${flag_x}" "${OPTARG}" "-x"
	 /bin/test "${OPTARG}" -ge 0 2>/dev/null
	 if [ "$?" -gt 1 ] ; then
	   ${LUPRINTF} -Eelp2 \
	       "`gettext 'Argument <%s> to -x option is not a number.'`" \
	       "${OPTARG}"
	   usage 3
	 fi
	 flag_x="${OPTARG}"
	 lulib_set_debug "${flag_x}"
	 ;;

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

      Z) # -Z - being run from the FMLI interface.
	 flag_Z="-Z"
	 ;;

      \?) 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 1
fi

# Must specify a BE to make
lulib_must_have_option "${flag_n}" "" "-n"

# Determine the name of Current BE.
CURR_BE="`lulib_lucurr`"
if [ "$?" -ne "0" ] ; then
  ${LUPRINTF} -Eelp2 \
      "`gettext 'Unable to determine the name of the current active BE.'`"
  err_exit_script 1
fi

# Determine that $ABE_NAME is not the current_be.
if [ "$CURR_BE" = "$ABE_NAME" ] ; then
  ${LUPRINTF} -Eelp2 "`gettext 'The boot environment <%s> is the current BE. \
You are not allowed to remake the file systems on the current active BE.'`" \
      "${CURR_BE}"
  err_exit_script 1
fi

if [ "${LU_SYSTEM_ARCH}" = i386 -a -z "${flag_c}" ]; then
   lulib_ask_for_menu_propagate
   if [ "$?" -eq 1 ]; then
      err_exit_script 1
   fi
fi

# If no -s option specified, assume the current BE is the source.
if [ -z "${PBE_NAME}" ] ; then
  PBE_NAME="${CURR_BE}"
fi

if [ "$TIME" != "" ] ; then
  # if '-t' option is specified, validate $TIME
  $LUBIN/lutime_valid "$TIME"
  if [ "$?" -ne "0" ] ; then
    err_exit_script 1
  fi
fi

# Check for "Copy Lock". If it exists, exit with error. 
# Don't validate_lulock for internal use.
if [ "$INODE_ICF" = "" ] ; then
  lulib_validate_lulock
fi

if [ -f "$COPYLOCK" ] ; then
  # Dot in COPYLOCK contents
  . $COPYLOCK
  if [ "$CL_BYPASS_ID" != "$BYPASS_ID" ] ; then
    ${LUPRINTF} -lp2D - "`gettext 'A Copy Lock file <%s> exists: Status <%s> \
Source BE <%s> Target BE <%s>.'`" "${COPYLOCK}" "${CL_STATUS}" \
	"${CL_SOURCE_BE}" "${CL_TARGET_BE}"
    ${LUPRINTF} -Eelp2 "`gettext 'Another Live Upgrade process is either \
running or scheduled...cannot continue.'`"
    exit_script 2
  fi
fi

# Validate the target BE; 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.
lulib_is_be_name_inuse "${ABE_NAME}"
if [ "$?" -ne "0" ] ; then
  ${LUPRINTF} -Eelp2 \
      "`gettext 'Unable to make file systems for boot environment <%s>.'`" \
      "${ABE_NAME}"
  err_exit_script 1
fi

# The BE must not currently be mounted.
lulib_verify_be_unmounted "${ABE_NAME}"
if [ "$?" -ne "0" ] ; then
  ${LUPRINTF} -Eelp2 \
      "`gettext 'Unable to make file systems for boot environment <%s>.'`" \
      "${ABE_NAME}"
  err_exit_script 1
fi

# Print message to let user know we are working
${LUPRINTF} -lp1 \
    "`gettext 'Creating configuration for boot environment <%s>.'`" \
    "${ABE_NAME}"

# Print message to let user know the Source boot Environment
${LUPRINTF} -lp1 "`gettext 'Source boot environment is <%s>.'`" "${PBE_NAME}"

# 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.'`"
  err_exit_script 1
fi

ABE_ID=`${LUETCBIN}/ludo get_be_id "$ABE_NAME"`
if [ "$?" -ne "0" ] ; then
  ${LUPRINTF} -Eelp2 '%s' "${ABE_ID}"
  ${LUPRINTF} -Eelp2 \
      "`gettext 'Unable to make file systems for boot environment <%s>.'`" \
      "${ABE_NAME}"
  err_exit_script 1
fi

ABE_ICF=/etc/lu/ICF.$ABE_ID

# Get the status of the ABE
BE_STAT="`${LUETCBIN}/ludo get_be_status_from_be_name \"$ABE_NAME\"`"
if [ "$?" -ne "0" ] ; then
  ${LUPRINTF} -Eelp2 "`gettext 'Unable to determine the target boot \
environment <%s> configuration.'`" "${ABE_NAME}"
  err_exit_script 1
fi

abe_root_fstyp=`lulib_get_root_fstyp_from_icf "${ABE_ICF}"`

if [ "$BE_STAT" = "C" -a "$abe_root_fstyp" != "zfs" ] ; then
  # Create ICF using lumk_iconf
  ${LUPRINTF} -lp2D - \
      "`gettext 'Creating ICF file for boot environment <%s>.'`" "${ABE_NAME}"
  # Obtain the name of the ICF file, forcing recreation so that the
  # current partition sizes for all file systems are determined.
  ABE_ICF="`$LUBIN/lumk_iconf -f -F \"$ABE_NAME\"`"
  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to determine disk partition \
configuration information for boot environment <%s>.'`" "${ABE_NAME}"
    err_exit_script 2
  fi
  # Call luupdall to copy the abe ICF file to all defined BEs.
  $LUBIN/luupdall ${ABE_ICF} 
  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to propagate the file <%s> to all \
boot environments.'`" "${ABE_ICF}"
    err_exit_script 2
  fi
else
  # Use the /etc/lu/ICF.{ID} file
  lulib_icf_validate "${ABE_ICF}"
  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'The boot environment <%s> is in an \
incomplete state and the internal configuration file <%s> is not valid.'`" \
	"${ABE_NAME}" "${ABE_ICF}"
    err_exit_script 2
  fi
fi

# Since there is possibility that branded zones exist in system, check
# if they are in appropriate state lumake can deal with:
# [1] If root of branded zone is on shared filesystem, the actual state
# of zone does not matter.
# [2] If root of branded zone is on unshared filesystem, the branded
# zone must be halted.
# If running branded zones with root on unshared filesystem exist,
# inform the user and exit.
# In order to check for shared filesystems, it is necessary to have
# valid ICF files for both source and new boot environments. They
# should be available for now, since ICF file for source boot
# evironment was created before and ICF of destination boot environment
# has been prepared just now.
# For lumake invoked from lucreate, this check has been already done
# in lucreate command, but it costs nothing to do this check again.
PBE_ICF=/etc/lu/ICF.`$LUETCBIN/ludo get_be_id $PBE_NAME`
NSBZ=`lulib_list_nonshared_branded_zones / $PBE_ICF $ABE_ICF`
if [ -n "$NSBZ" ] ; then
  $LUPRINTF -Eelp2 \
    "`gettext 'Branded zones with non-shared root are not halted: %s'`" \
    $NSBZ

  exit_script 2
fi

# Make sure the PBE is mounted and that the OS support vxfs-root if the ABE
# file system type is "vxfs"
lulib_validate_be_for_copy "${PBE_ICF}"
if [ "$?" -ne "0" ] ; then 
  ${LUPRINTF} -Eelp2 "`gettext 'The source boot environment <%s> cannot be \
used to create the target BE <%s>.'`" "${PBE_NAME}" "${ABE_NAME}"
  err_exit_script 2
fi

# Call lucomp_size, if not internal interface (i.e not via lucreate)

if [ -z "${flag_i}" -a "$abe_root_fstyp" != "zfs" ] ; then
  # Inode file does not exist
  INODE_ICF="/tmp/inode_icf.$$"

  $LUBIN/lucomp_size -p $PBE_NAME -i ${ABE_ICF} -O $INODE_ICF -n $ABE_NAME
  if [ "$?" -ne "0" ] ; then
    # Size is not sufficient
    ${LUPRINTF} -Eelp2 "`gettext 'File systems on ABE <%s> have insufficient \
space for repopulation from boot environment <%s>. It is recommended to \
delete this BE and create a fresh BE.'`" "${ABE_NAME}" "${PBE_NAME}"
    err_exit_script 1
  fi
fi

# If '-t time' is specified, we need to set up an 'at(1)' job to
# execute lumake at the specified time.

if [ "$TIME" != "" ] ; then
  BYPASS_ID=$$
  ${LUPRINTF} -lp1 "`gettext 'Scheduling the copy.'`"
  if [ "X${MAILTO}" != "X" ] ; then
	/bin/cat <<-EOF | /bin/at -s "$TIME" > /tmp/at.out$$ 2>&1
	  $LUBIN/lumake -b $BYPASS_ID -c $ABE_OPT 2>&1 >/tmp/lumake.log.$$
	  /bin/mailx -s \
	      "Live Upgrade Copy to $ABE_NAME on `uname -n` Completed" \
	      "$MAILTO" </tmp/lumake.log.$$
	  rm /tmp/lumake.log.$$
	EOF
  else
	/bin/cat <<-EOF | /bin/at -s -m "$TIME" > /tmp/at.out$$ 2>&1
		$LUBIN/lumake -b $BYPASS_ID -c $ABE_OPT
	EOF
  fi
  RET=$?
  # This gets the at job number and is flexible enough to handle
  # the out put from at(1) even if the at(1) output changes in
  # the future due to internationalization.
  AT_JOB_NUM=`/bin/awk '{ 
		for (i=0; i <= NF; i++)
		{
			if ( $i == "Job" || $i == "job" )
			{ 
				i++
				print $i 
				exit 0
			}
		}
	}' /tmp/at.out$$`

  /bin/grep INFO /tmp/at.out$$ > /dev/null 2>&1
  if [ "$?" -eq "0" ] ; then
    AT_JOB_TIME=`/bin/grep INFO /tmp/at.out$$ | /bin/cut -d" " -f6-`
  else
    /bin/grep -i job /tmp/at.out$$ > /dev/null 2>&1
    if [ "$?" -eq "0" ] ; then
      AT_JOB_TIME=`/bin/grep job /tmp/at.out$$ | /bin/cut -d" " -f4-`
    else
      AT_JOB_TIME="CANNOT DETERMINE"
    fi
  fi

  /bin/rm -f /tmp/at.out$$
  if [ $RET = 0 ] ; then
    # Change Copy lock status to "SCHEDULED"
    if [ -f $COPYLOCK ] ; then
      ${LUPRINTF} -lp2D - "`gettext 'Changing Copy Lock status to SCHEDULED.'`"
      /bin/grep -v "^CL_STATUS" $COPYLOCK | \
      /bin/grep -v "^CL_BYPASS_ID" >> $TMP_LOCK
    else
      ${LUPRINTF} -lp2D - \
	  "`gettext 'Creating Copy Lock and setting status to SCHEDULED.'`"
      echo "CL_SOURCE_BE=\"$PBE_NAME\"" >> $TMP_LOCK
      echo "CL_TARGET_BE=\"$ABE_NAME\"" >> $TMP_LOCK
      echo "CL_ICF=\"${ABE_ICF}\"" >> $TMP_LOCK
    fi
    echo "CL_STATUS=\"SCHEDULED\"" >> $TMP_LOCK
    echo "CL_EXEC_TIME=\"$AT_JOB_TIME\"" >> $TMP_LOCK
    echo "CL_AT_JOB_NUM=\"$AT_JOB_NUM\"" >> $TMP_LOCK
    echo "CL_BYPASS_ID=\"$BYPASS_ID\"" >> $TMP_LOCK
    /bin/mv $TMP_LOCK $COPYLOCK
    exit_script 0
  else
    ${LUPRINTF} -Eelp2 "`gettext 'Attempt to schedule lumake at the specified \
time <%s> failed.'`" "${TIME}"
    if [ "$BE_STAT" = "C" ] ; then
      # Remove ICF and COPYLOCK
      # DO NOT remove lutab entry or free devices.
      ${LUPRINTF} -lp2D - "`gettext 'Removing configuration file.'`"
      /bin/rm -f ${ABE_ICF}
    fi
    err_exit_script 1
  fi
else
  # Set "Copy Lock" to ACTIVE state.
  if [ -f $COPYLOCK ] ; then
    ${LUPRINTF} -lp2D - "`gettext 'Changing Copy Lock status to ACTIVE.'`"
    /bin/grep -v "^CL_STATUS" $COPYLOCK > $TMP_LOCK
  else
    ${LUPRINTF} -lp2D - \
	"`gettext 'Creating Copy Lock and setting status to ACTIVE.'`"
    echo "CL_SOURCE_BE=\"$PBE_NAME\"" > $TMP_LOCK
    echo "CL_TARGET_BE=\"$ABE_NAME\"" >> $TMP_LOCK
    echo "CL_ICF=\"${ABE_ICF}\"" >> $TMP_LOCK
  fi
  echo "CL_STATUS=\"ACTIVE\"" >> $TMP_LOCK
  /bin/mv $TMP_LOCK $COPYLOCK
fi

#
# If being run from the FMLI interface, need to inform the user that there
# is no more user interaction that will be required.
#
if [ -n "${flag_Z}" ] ; then
  ${LUPRINTF} -lp1 ''
  ${LUPRINTF} -lp1 '%s' \
      '**********************************************************************'
  ${LUPRINTF} -lp1 ''
  ${LUPRINTF} -lp1 \
      "`gettext 'Beginning process of creating boot environment <%s>.'`" \
      "${ABE_NAME}"
  ${LUPRINTF} -lp1 "`gettext 'No more user interaction is required until this \
process is complete.'`"
  ${LUPRINTF} -lp1 ''
  ${LUPRINTF} -lp1 '%s' \
      '**********************************************************************'
  ${LUPRINTF} -lp1 ''
else
  ${LUPRINTF} -lp1 "`gettext 'Creating boot environment <%s>.'`" "${ABE_NAME}"
fi

# Mark the ABE as Not Complete.
${LUPRINTF} -lp2D - "Setting boot environment <%s> state to Not Complete." \
    "${ABE_NAME}"
$LUBIN/lustat_set -n "$ABE_NAME" -s NC 
if [ "$?" -ne "0" ] ; then
  ${LUPRINTF} -Eelp2 "`gettext 'Unable to update the status of boot \
environment <%s> in the BE configuration.'`" "${ABE_NAME}"
  err_exit_script 1
fi

#
# On x86: No need to save the GRUB menu. We get
# it from the PBE
#


ABE_ROOT_POOL="`lulib_get_root_pool_name_from_icf ${ABE_ICF}`"
PBE_ROOT_POOL="`lulib_get_root_pool_name_from_icf ${PBE_ICF}`"


if [ -n "${ABE_ROOT_POOL}" -a "${ABE_ROOT_POOL}" = "${PBE_ROOT_POOL}" ] ; then
  # Call luclonefs to snapshot/clone the PBE file systems to create ABE

  ${LUPRINTF} -lp1 "`gettext 'Cloning file systems from boot environment \
<%s> to create boot environment <%s>.'`" "${PBE_NAME}" "${ABE_NAME}"

  if [ -z "${flag_i}" ] ; then
      $LUBIN/luclonefs -a ${ABE_ICF} -p ${PBE_ICF}
  else
      $LUBIN/luclonefs -i -a ${ABE_ICF} -p ${PBE_ICF}
  fi

  if [ "$?" -ne "0" ] ; then
	${LUPRINTF} -Eelp2 "`gettext 'Unable to clone the existing file \
systems from boot environment <%s> to create boot environment <%s>.'`" \
	  "${PBE_NAME}" "${ABE_NAME}"
	exit_script 1
  fi

  #
  # Create the BE_CONFIG file for the newly cloned BE
  #
  CLONE_ERR_STR="cannot complete ABE clone setup"
  LU_ALT=`LU_OUTPUT_FORMAT=text $LUBIN/lumount -Z -i $ABE_ICF 2>${TMP_RESULT_FILE}`
  if [ "$?" -ne "0" ]; then
    [ -s "${TMP_RESULT_FILE}" ] && ${LUPRINTF} -elp2 '%R' < "${TMP_RESULT_FILE}"
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to mount ABE <%s>: %s'`" \
	"${ABE_NAME}" "${CLONE_ERR_STR}"
    exit_script 1
  fi
  $LUBIN/luedvfstab -i "${ABE_ICF}" -m "${LU_ALT}" -n "${ABE_NAME}"
  
  lulib_create_be_config_file "$ABE_NAME" "$LU_ALT" "$CLONE_ERR_STR"

  # The COPY_LOCK file was cloned along with the rest of the datset,
  # so we need to remove it here.
  rm -f "$LU_ALT/$COPYLOCK"

  $LUBIN/luumount -f -i $ABE_ICF 

else
# Calls lumkfs to create file systems.

  ${LUPRINTF} -lp1 \
     "`gettext 'Creating file systems on boot environment <%s>.'`" "${ABE_NAME}"
  $LUBIN/lumkfs -i ${ABE_ICF} -n ${PBE_NAME} -s ${FS_SKIP_LIST}
  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to create all required file systems \
for boot environment <%s>.'`" "${ABE_NAME}"
    err_exit_script 1
  fi

  #if there are zones residing at the top of ufs/vxfs file systems, those file systems cannot
  #be considered as shared. If the entries for those file systems in ABE ICF file indicate as
  #if they are shared, we need to remove those entries from ICF. In effect, ABE ICF file correctly
  #indicates the fact that these file systems got merged with parent file systems in ABE.
  #Following code block does this work.

  if [ -x /usr/sbin/zoneadm ]; then
	if [ "$PBE_NAME" = "$CURR_BE" ] ; then
	    pbe_root="/"
	else
	    pbe_root=`$LUBIN/lumount -i "$PBE_ICF"`
	    if [ $? -ne 0 ] ; then
	        $LUPRINTF -Eelp2  "`gettext 'Failed to mount <%s> from ICF file <%s>.'`" "$PBE_NAME" "$PBE_ICF"
	        err_exit_script 1
	    fi
	fi

	#obtain the list of shared file systems
	shared_fslist=`${LUETCBIN}/ludo get_shared "${PBE_ICF}" "${ABE_ICF}"|awk '{print $2}'`

	remap_a=/tmp/.icf.remap.$$
	remap_b=/tmp/.icf.newmap.$$
	/bin/cp "$ABE_ICF" $remap_a
	SAVEIFS="$IFS"

	/usr/sbin/zoneadm -R "$pbe_root" list -cp |
	while IFS=: read z_id z_name z_state z_path z_junk; do
		IFS="$SAVEIFS"
		[ "$z_name" = global ] && continue

		#if zonepath is not at the top of a file system, no remapping needed 
		z_fsmnt=`df -n "$z_path"| awk -F: '{print $1}'`
		[ $z_fsmnt != $z_path ] && continue

		z_rawfsmnt=`echo "$z_fsmnt"|sed "s:^$pbe_root/:/:"` 

		#if the file system containing zonepath is not in the list of shared fs,
		#do nothing
		echo "${shared_fslist}"| fgrep -x ${z_rawfsmnt} >/dev/null
		[ $? -ne 0 ] && continue

		z_fstype=`df -n "$z_path"| awk -F: '{print $2}'`
		if [ $z_fstype = "ufs" -o $z_fstype = "vxfs" ] ; then
		    /bin/nawk -v MP=$z_rawfsmnt \
		        -F: '{if ($2 != MP) 
		       {print}}' $remap_a > $remap_b
		fi
		mv "$remap_b" "$remap_a"
	done
	mv $remap_a "$ABE_ICF"

	if [ "$pbe_root" != "/" ] ; then
		$LUBIN/luumount -f -i "$PBE_ICF"
		if [ $? -ne 0 ] ; then
		    $LUPRINTF -Eelp2  "`gettext 'Failed to unmount boot environment <%s>.'`" "$PBE_NAME"
		    err_exit_script 1
	        fi
	fi
  fi

  # Mount the ABE file systems to verify sufficient inodes in each file system
  # Bypass for zfs since it doesn't have inodes

  if [ "$abe_root_fstyp" != "zfs" ] ; then
	${LUPRINTF} -lp1 \
	    "`gettext 'Mounting file systems for boot environment <%s>.'`" \
	    "${ABE_NAME}"
	dest=`LU_OUTPUT_FORMAT=text $LUBIN/lumount -Z -i ${ABE_ICF} \
	    2>${TMP_RESULT_FILE}`
	if [ "$?" -ne "0" ] ; then
	  # About 1 in 1000 async ufs creations will leave the FS state
	  # flag in superblock wrong. Do a fsck of the BE to try and fix this.
	  [ -s "${TMP_RESULT_FILE}" ] && \
		${LUPRINTF} -elp2 '%R' < "${TMP_RESULT_FILE}"
	  ${LUPRINTF} -Wlp1 "`gettext 'Attempting to correct problems detected \
	    with file systems for boot environment <%s>.'`" "${ABE_NAME}"

	  $LUBIN/lufsck -i ${ABE_ICF}
	  dest=`LU_OUTPUT_FORMAT=text $LUBIN/lumount -Z -i ${ABE_ICF} \
		2>${TMP_RESULT_FILE}`
	  if [ "$?" -ne "0" -o ! -d "${dest}" ] ; then
	    [ -s "${TMP_RESULT_FILE}" ] && \
		${LUPRINTF} -elp2 '%R' < "${TMP_RESULT_FILE}"
	    ${LUPRINTF} -Wlp1 "`gettext 'Unable to correct problems detected \
		with file systems for boot environment <%s>.'`" "${ABE_NAME}"
	    err_exit_script 1
	  fi
	fi

	# After making the file system, verify that the ABE file systems
	# have sufficient number of inodes.  This loop reads the INODE_ICF
	# file, which is produced by luconfig (when doing lucreate) or by
	# lucomp_size (when running lumake by hand).

	${LUPRINTF} -lp1 "`gettext 'Calculating required sizes of file systems \
		for boot environment <%s>.'`" "${ABE_NAME}"
	errfile=/tmp/.lumake.inode_errs.$$
	/bin/rm -f $errfile

	SAVEIFS="$IFS"
	while IFS=: read mount_pt inode_num zonename slice
	do
		IFS="$SAVEIFS"

		if [ "$mount_pt" = "-" -o "$inode_num" -le 0 ]; then
			continue
		fi

		# Determine the number of inodes that are present
		# on ABE $mount_pt file system.  
		tot_inode=`
			LANG=C LC_ALL=C df -t $slice | /bin/awk '
			{ files=$4 }
			END {
				print files
			}'`
		if [ -z "$tot_inode" ]; then
			tot_inode=0
		fi

		if [ "$tot_inode" -lt "$inode_num" ]; then
		    echo "$mount_pt $zonename $tot_inode $inode_num" > $errfile
		fi
	done < $INODE_ICF
	IFS="$SAVEIFS"

	if [ -s "$errfile" ]; then
		$LUPRINTF -Eelp2 "`gettext 'Insufficient number of inodes on \
the file systems of the boot environment <%s>.  Deleting this BE and \
creating a fresh BE is recommended.'`" "$ABE_NAME"
		while read mount_pt zonename tot_inode inode_num; do
			$LUPRINTF -Eelp2 "`gettext 'Mount point %s in zone %s \
has %d inodes; %d needed'`" $mount_pt $zonename $tot_inode $inode_num
		done
	fi

	# unmount the ABE file systems
	$LUBIN/luumount -f -i ${ABE_ICF} 2> /dev/null
	if [ "$?" -ne "0" -o -f "$errfile" ] ; then
	  /bin/rm -f $errfile
	  err_exit_script 1
	fi
  fi

  # Get filter file from global database.
  FILTER_OPTION=""
  ${LUETCBIN}/ludo get_file_from_xml_db "${LU_DB_GLOBAL}" "${ABE_ID}" \
    'beFilterFile' 'beFilterFileItem' > ${FILTER_FILE}
  [ $? -eq 0 -a -s "${FILTER_FILE}" ] && FILTER_OPTION="-z ${FILTER_FILE}"

  # Get integrity check override from global database.
  INTEGRITY_CHECK_OPTION=""
  SETTING="`${LUETCBIN}/ludo get_setting_from_xml_db \"${LU_DB_GLOBAL}\" \
    \"${ABE_ID}\" 'beFilterSpecifications' 'integrityCheck'`"
  [ $? -eq 0 -a "${SETTING}" = 'no' ] && INTEGRITY_CHECK_OPTION="-I"

  # Calls lupop to populate file systems.
  ${LUPRINTF} -lp1 \
    "`gettext 'Populating file systems on boot environment <%s>.'`" \
    "${ABE_NAME}"
  $LUBIN/lupop -i "${ABE_ICF}" -p "${PBE_NAME}" -s ${FS_SKIP_LIST} \
      ${FILTER_OPTION} ${INTEGRITY_CHECK_OPTION}
  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to populate file systems on boot \
environment <%s>.'`" "${ABE_NAME}"
    err_exit_script 1
  fi
fi

# Calls lustat_set to update the BE status in the lutab.
${LUPRINTF} -lp2D - "Setting boot environment <%s> state to Complete." \
    "${ABE_NAME}"
$LUBIN/lustat_set -n "$ABE_NAME" -s C 
if [ "$?" -ne "0" ] ; then
  ${LUPRINTF} -Eelp2 "`gettext 'Unable to update the status of the boot \
environment <%s> in the BE configuration.'`" "${ABE_NAME}"
  err_exit_script 1
fi

# Call luupdall to copy the ICF files to all defined BEs.
ICF_FILES=`ls /etc/lu/ICF* 2>/dev/null`
if [ $? -eq 0 ]; then
  $LUBIN/luupdall ${ICF_FILES}
  if [ $? != 0 ] ; then
    ${LUPRINTF} -Eelp2 \
	"`gettext 'Cannot propagate the files <%s> to all BEs.'`" "${ICF_FILES}"
    err_exit_script 1
  fi
fi

#
# if x86, copy the GRUB menu from the PBE to the ABE.
#
if [ "${LU_SYSTEM_ARCH}" = i386 -a -f "/${BOOT_MENU}" -a -s "/${BOOT_MENU}" ]; then
   if lulib_propagate_file "/${BOOT_MENU}" "yes"; then
      ${LUPRINTF} -lp1 "`gettext 'Copied GRUB menu from PBE to ABE'`"
   else
      ${LUPRINTF} -Eelp2 "`gettext 'Menu copy failed from PBE to ABE failed'`"
      err_exit_script 1
   fi
fi

# Since we have changed the ABE, remove its entries (if any) from the menu
#
if [ "${LU_SYSTEM_ARCH}" = i386 -o -x /sbin/zpool ]; then
   lulib_delete_menu_entry "${ABE_NAME}" "${ABE_ID}"
   if [ "$?" -ne 0 ] ; then
      ${LUPRINTF} -Eelp2 "`gettext 'Unable to delete menu entry for boot \
environment <%s>.'`" "${ABE_NAME}"
      err_exit_script 1
   fi
fi

# Remove copy lock.
/bin/rm -f $COPYLOCK

${LUPRINTF} -lp1 "`gettext 'Population of boot environment <%s> successful.'`" \
    "${ABE_NAME}"

exit_script 0
