#!/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	"@(#)luedvfstab.sh	5.14	09/07/28 SMI"
#
# USAGE:	luedvfstab  [-l error_log] [-o outfile] [-I]
#		-i <abe_internal_config_file> -m <abe_mount_point> -n <be_name>
# FUNCTION:	edits /etc/vfstab and Zones configuration on target BE to use
#		correct device names.
#		(Assumes ABE is already mounted)
# INPUT:	ABE Internal Config File
#		ABE mount point
#		ABE boot environment name
# OUTPUT:	edited /etc/vfstab and Zones configuration on ABE
# DEV:		WLH
#
# Returns:	0 - Update succeeded.
#		1 - Update failed: failure to perform specific operation requested.
#		2 - Update failed: unexpected failure outside of requested operation.
#		3 - Update failed: command line / user request error.
#
################################################################################

LU_PROG_FULL_PATH="$0"
LU_PROG_NAME="`basename ${LU_PROG_FULL_PATH}`"; export LU_PROG_NAME
ICF=""
LU_ALT=""
ABE_VFSTAB=""
ABE_VFSTAB_SAV=""
ABE_VFSTAB_CAN_BE_RESTORED=""

################################################################################
# Name:		interruptHandler
# Description:	Handle an armed shell "trap"
# Local Prefix:	<none>
# Arguments:	<none>
# Example:      trap "interruptHandler" 1 2 3 9 15
# Returns:	call script cleanup function with exit code "4"
################################################################################

interruptHandler()
{
  # Reset all traps to be ignored so that termination can take place
  # without further interrupts

  # 1- SIGHUP (hangup)
  # 2- SIGINT (user interrupt)
  # 3- SIGQUIT (user quit)
  # 9- SIGKILL (kill process - can not be caught or ignored :)
  # 15- SIGTERM (software termination request)
  trap "" 1 2 3 9 15

  # Output indication of interrupt processed
  ${LUPRINTF} -Ilp2 "`gettext 'Interrupted (Signal received): cleaning up...'`"

  # Cause the script to exit
  exit_script 1
}

################################################################################
# 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 -m ABE_mount_point -n BE_name'`" "${LU_PROG_NAME}"
  if [ -z "$1" ] ; then
    exit_script 3 "yes"
  fi
  exit_script "$1" "yes"
}

################################################################################
# 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")
#		$2 = optional suppress exit status message
#			("" or none = do NOT suppress)
# Example:      exit_script "0"
# Returns:	<none>
################################################################################

exit_script()
{
	# If the vfstab file can be restored and a backup copy exists, restore
	# the vfstab file from the backup copy if it is available

	if [ -n "${ABE_VFSTAB_SAV}" -a -f "${ABE_VFSTAB_SAV}" ] ; then
		if [ -n "${ABE_VFSTAB_CAN_BE_RESTORED}" ] ; then
			${LUPRINTF} -lp1 "`gettext 'Restoring backup copy of vfstab \
file <%s> to <%s> on ABE.'`" "${ABE_VFSTAB_SAV}" "${ABE_VFSTAB}"
			/bin/cp -p "${ABE_VFSTAB_SAV}" "${ABE_VFSTAB}"
		fi
		/bin/rm -f "${ABE_VFSTAB_SAV}" 2>/dev/null
	fi

	# Determine the exit status code.

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

	# Output the exit status message if not suppressed. 
	if [ -z "$2" ] ; then
		if [ "${retcode}" -ne "0" ] ; then
			${LUPRINTF} -lp1 "`gettext 'The update of the vfstab file on the ABE failed.'`"
		fi
	fi

	[ -n ${TEMP_ICF} ] && rm -f ${TEMP_ICF}

	exit "${retcode}"
}

################################################################################
# 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

# Default global variables we expect to be set from /etc/default/lu.

LUBIN=${LUBIN:=/usr/lib/lu}

# Dot the Live Upgrade library functions.

if [ ! -s $LUBIN/lulib ] ; then
  echo "${LU_PROG_NAME}: ""`gettext 'ERROR: The Live Upgrade product is not \
installed properly (${LUBIN}/lulib not found).'`"
  exit 1
fi

. $LUBIN/lulib

# 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_I="" # -I - include filesystems from ICF file only.
flag_l="" # -l f - log file path.
flag_n="" # -n "n" - be name.
flag_o="" # -o f - output file path.
flag_x="" # -x n - set debug level to n (PRIVATE).

while [ $# -ne 0 ] ; do
  while getopts Ii:l:m:n:o:x:X c
  do
    case $c in
      I) # -I - include filesystems from ICF file only.
	 flag_I="yes"
	 ;;
      i) 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) LU_ALT="$OPTARG"
	 ;;
      n) # -n "n" - be name.
	 lulib_cannot_duplicate_option "${flag_n}" "${OPTARG}" "-n"
	 flag_n="${OPTARG}"
	 ;;
      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}"
	 ;;
      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'
	  ;;
      \?) # 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

# A valid BE name must be provided.

if [ -z "${flag_n}" ] ; then
  ${LUPRINTF} -Eelp2 "`gettext 'You must use the <-n> option to specify the target BE name.'`"
  usage 3
fi
BE_NAME="${flag_n}"

# Validate the ABE mount point.

lulib_validate_bemntpt "${LU_ALT}"
if [ "$?" -ne "0" ] ; then
  ${LUPRINTF} -Eelp2 "`gettext 'You must use the <-m> option to specify the \
mount point of the ABE where to create the /etc/vfstab file.'`"
  usage 3
fi

# Make sure that an internal configuration file name was specified.

if [ -z "${ICF}" ]; then
  ${LUPRINTF} -Eelp2 "`gettext 'You must use the <-i> option to specify the \
ICF file to use to build the /etc/vfstab file from.'`"
  usage 3
fi

# Validate the ICF file.

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

ABE_VFSTAB="${LU_ALT}/etc/vfstab"
ABE_VFSTAB_SAV="${LU_ALT}/etc/.vfstab.live-upgrade.save"

if [ ! -f "${ABE_VFSTAB}" ] ; then
  ${LUPRINTF} -lp2D - "`gettext 'The vfstab file <%s> does not exist on \
the ABE: updating skipped.'`" "${ABE_VFSTAB}"
  exit_script 1
fi

# Add command to session log file and to standard error output if debug mode enabled.

${LUPRINTF} -p1D - "`gettext 'Updating boot environment <%s> file system \
configuration information.'`" "${BE_NAME}"

${LUPRINTF} -lp2D - "`gettext 'Updating the vfstab file <%s> on the BE <%s> \
specified by the ICF file <%s>.'`" "${ABE_VFSTAB}" "${BE_NAME}" "${ICF}"

# signal handling for cleanup.
# 1- SIGHUP (hangup)
# 2- SIGINT (user interrupt)
# 3- SIGQUIT (user quit)
# 9- SIGKILL (kill process - can not be caught or ignored :)
# 15- SIGTERM (software termination request)
trap "interruptHandler" 1 2 3 9 15

# Save original ABE vfstab.
ERRMSG="`cd ${LU_ALT}/etc 2>&1`"
cd ${LU_ALT}/etc
if [ "$?" -ne "0" ] ; then
  [ -n "${ERRMSG}" ] && ${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
  ${LUPRINTF} -Eelp2 "`gettext 'Unable to access directory <%s> on the ABE.'`" "${LU_ALT}/etc"
  exit_script 1
fi
/bin/rm -f "${ABE_VFSTAB_SAV}" 2>/dev/null
if [ -f "${ABE_VFSTAB}" ] ; then
  ERRMSG="`/bin/cp -p \"${ABE_VFSTAB}\" \"${ABE_VFSTAB_SAV}\" 2>&1`"
  if [ "$?" -ne "0" -o ! -r "${ABE_VFSTAB_SAV}" ]; then
    [ -n "${ERRMSG}" ] && ${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to save backup copy of ABE vfstab \
file <%s> to <%s>.'`" "${ABE_VFSTAB}" "${ABE_VFSTAB_SAV}"
    exit_script 1
  fi
fi

# Set flag so that the vfstab file on the abe will be restored from
# the saved copy if we are interrupted or when we exit.

ABE_VFSTAB_CAN_BE_RESTORED="yes"

#Make a copy of ABE ICF file to a temporary location
TEMP_ICF="/tmp/luedvfstab.icf.$$"
/bin/cp ${ICF} ${TEMP_ICF}

#Add entries for legacy zone datasets to temporary ICF file. This is required to make
#sure that legacy zone datasets get updated properly in ABE vfstab
if [ -x /usr/sbin/zoneadm -a -x /sbin/zfs ] ; then
    /sbin/zfs list -Ho name,zpdata:rbe,zpdata:zn |
    /bin/nawk -v BE="${BE_NAME}" '$2 == BE {print $1, $3}' | while read ds zn ; do
        mount_prop=`/sbin/zfs get -Ho value mountpoint "$ds"`
        [ $mount_prop != "legacy" ] && continue
        z_path=`/usr/sbin/zonecfg -R ${LU_ALT} -z ${zn} info zonepath | cut -d: -f2`
        z_rawpath=`echo $z_path | sed "s:^${LU_ALT}/:/:"`
	[ -z "$z_path" -o -z "$z_rawpath" ] && exit_script 1
	echo "${BE_NAME}:${z_rawpath}:${ds}:zfs:0"
    done >>${TEMP_ICF}
fi

# If the -I option has been specified, create a simplified vfstab file
# that has only the mount points from the ABE's ICF file; otherwise,
# copy the PBE vfstab file and edit the contents to conform to the
# ABE's file system configuration.

if [ -n "${flag_I}" ] ; then
  # -I specified: create simplified vfstab file
  ${LUPRINTF} -lp2D - "`gettext 'Creating simplified vfstab file for boot \
environment <%s>.'`" "${BE_NAME}"

  # Truncate the existing vfstab file: this way the permissions are preserved.

  ERRMSG=`/bin/cp /dev/null "${ABE_VFSTAB}" 2>&1`
  if [ "$?" -ne "0" ] ; then
    [ -n "${ERRMSG}" ] && ${LUPRINTF} -Eelp2 '%s' "${ERRMSG}"
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to truncate vfstab file <%s>.`'" "${ABE_VFSTAB}"
    exit_script 1
  fi

  # Add temporary header to vfstab file
  ${LUPRINTF} +X -a "${ABE_VFSTAB}" "`gettext '# boot environment <%s> temporary \
vfstab file - BE specified file systems only'`" "${BE_NAME}"

  # create vfstab file from icf file contents
  /bin/nawk -F: '{ printf("%s %s %s\n", $2, $3, $4) }' ${TEMP_ICF} |
  ( while read mntpt device fstyp
  do
    if [ "$fstyp" = "swap" ]; then
      echo "$device\t-\t-\t$fstyp\t1 no -" >>$ABE_VFSTAB
    else
      bdevice=$device
      cdevice="`lulib_get_cdevice $bdevice`"
      if [ -z "$cdevice" ]; then
	${LUPRINTF} -Eelp2 "`gettext 'Unable to determine character device node \
for device <%s>.'`" "$bdevice"
	exit 1
      fi
      # Solaris /,/usr,/var must be set to "no"
      if [ "$mntpt" = "/" -o "$mntpt" = "/usr" -o "$mntpt" = "/var" ] ; then
	echo "$bdevice\t$cdevice\t$mntpt\t$fstyp\t1 no -" >>$ABE_VFSTAB
      else
	echo "$bdevice\t$cdevice\t$mntpt\t$fstyp\t2 yes -" >>$ABE_VFSTAB
      fi
    fi
  done )

  if [ "$?" -ne "0" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to process devices specified in ICF \
file <%s>.'`" "${ICF}"
    exit_script 1
  fi
else
  # no -I: copy and edit PBE's vfstab file
  # Update the target vfstab file
  ${LUPRINTF} -lp2D - "`gettext 'Updating existing vfstab file for boot \
environment <%s>.'`" "${BE_NAME}"

  ${LUETCBIN}/ludo create_abe_vfstab "$ABE_VFSTAB_SAV" "$BE_NAME" "$TEMP_ICF" \
	"$LU_ALT"

  if [ $? -ne 0 ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to update vfstab file for boot \
environment <%s>.'`" "${BE_NAME}"
    exit_script 1
  fi
fi

# Unset flag so that the vfstab file on the abe will NOT be restored
# from the saved copy if we are interrupted or when we exit.

ABE_VFSTAB_CAN_BE_RESTORED=""

# Succeeded!
# Output debugging information on the change.

/bin/diff -w -b "${ABE_VFSTAB_SAV}" "${ABE_VFSTAB}" 2>&1 | \
${LUPRINTF} -lp2D - "`gettext 'Differences between old and new vfstab files:\
\n**********************************\n%R\n**********************************'`"

exit_script 0
