#!/sbin/sh

#################################################################################################
#
# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
# ident	"@(#)lurootspec.sh	1.1	08/06/25 SMI"
#
# This utility is not for public use; the interface is subject to change 
# without notice.
#
# USAGE:        lurootspec [-m mntpt] 
# FUNCTION:     Outputs the logical specification for the root filesystem.
#		This should handle SCSI slices, DAP Vdisks, VM Volumes, 
#		RAID slices, and ZFS pools.
# INPUT:	-m mntpt - optional mount point to determine root device for
#			(this mount point MUST be a boot mount point, 
#			e.g. must contain /etc directory)
#			chosen from the boot prom
# OUTPUT:	Full logical specification of root file system
# DEV:          JKJ
#
# Note: performance testing has proven that "/sbin/sh" provides the best performance over
# /bin/sh and /bin/ksh.
#
#################################################################################################

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

#################################################################################################
# Name:		usage
# Description:	output command line usage information; then call exit 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] [-m mntpt]'`" "${LU_PROG_NAME}"

  if [ -z "$1" ] ; then
    exit 3
  fi
  exit "$1"
}


#################################################################################################
# Name:		do_oos_mode
# Description:	Perform operation in single user maintenence mode.
# Local Prefix:	dom_
# Arguments:	$1 = optional mount point to return root device of ("" implies current BE)
#               $2 = allow metadevice and ZFS pool names ("" implies do NOT
#		    allow meta device names)
# Example:      exit_script "0"
# Returns:	<none>
#################################################################################################

do_oos_mode()
{
  dom_mntpt="${1:-/}"
  dom_metayes="$2"

  LU_BE_CONFIG_FILE="/etc/lu/.BE_CONFIG"

  # Attempt to determine the root device using devnm; if that fails,
  # attempt to find the root devices from the vfstab file.

  ROOT_SPEC="`/usr/sbin/devnm ${dom_mntpt} 2>/dev/null | awk ' { print $1 } '`"

  if [ -z "${ROOT_SPEC}" -a -r "${dom_mntpt}/etc/vfstab" ] ; then
    ROOT_SPEC=`/bin/sed -e '/^[	 ]*$/d' -e '/#.*/d' < "${dom_mntpt}/etc/vfstab" | awk ' { if ( $3 == "/" ) { print $1; exit 0 } } '`
  fi

  if [ -n "${ROOT_SPEC}" ] ; then
      echo "${ROOT_SPEC}"
      return 0
  fi

  # See if the root specification can be obtained from the lutab file.

  BE_ROOT_SPEC=`${LUETCBIN}/ludo get_root_slice_from_mntpt "${dom_mntpt}" 2>/dev/null`
  if [ "$?" -eq 0 -a -n "${BE_ROOT_SPEC}" -a  -b "${BE_ROOT_SPEC}" ] ; then
      echo "${BE_ROOT_SPEC}"
      exit 0
  fi

  echo "`gettext 'Unable to determine root specificatio for mount point: '`""<${dom_mntpt}>" >&2
  return 1
}

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

##########
# If lurootspec is invoked in maintenance mode, then it needs to perform
# the out of service administration. We do this by executing '/bin/who -r',
# (Indicates the current run-level of the init process) and see if the
# run-level is "s" or "S" (single user mode) or "1" (system administrator 
# mode) - if so then we are in single user / maintenance mode. If 'who -r'
# does not return any value, then use 'who -a' and attempt to extract
# the run-level. This is for 2.6 systems where 'who -r' in single user mode
# does not return any value...
#
# Output looks like this in single user mode:
#   --> # who -r
#   -->   .       run-level S  Mar 27 19:48     S      0  ?
# Output looks like this in system maintenance mode:
#   --> # who -r
#   -->   .       run-level 1  Mar 28 09:50     1      0  S
# Output looks like this in non-single user mode:
#   --> # who -q
#   -->   .       run-level 3  Mar 24 11:06     3      0  S
##########

initRunLevel="`LANG=C LC_ALL=C /bin/who -r | /bin/awk '{print $3; exit 0}'`"
if [ -z "${initRunLevel}" ] ; then
  initRunlevel="`LANG=C LC_ALL=C /bin/who -a | /bin/awk '{if ($2 == \"run-level\") {print $3; exit 0}}'`"
fi
if [ "${initRunLevel}" = "S" -o "${initRunLevel}" = "s" -o "${initRunLevel}" = "1" ] ; then
  # We are in maintenance mode: do minimal operations.
  # Reset all command line parse flags to default values.
  flag_a="" # -a - allow meta device names to be returned; default is real device node name.
  flag_m="" # -m n - alternative BE mount point to look up root device of (assumes '/')

  while getopts m: c
  do
    case $c in
      m) # -m n - BE mount point to find current BE name from.
	 # If the argument is a null string, then ignore the flag - makes scripting easier (e.g. -m "" instead of testing for "" in calling script)
	 if [ -n "${OPTARG}" ] ; then
	   flag_m="$OPTARG"
	 fi
	 ;;
      \?) # unknown - option: ignore.
	  ;;
    esac
  done

  LU_OUTPUT_FORMAT_OVERRIDE='text'
  export LU_OUTPUT_FORMAT_OVERRIDE
  LU_OUTPUT_FORMAT='text'
  export LU_OUTPUT_FORMAT

  # in single user fallback mode - there is no guarantee that /usr contains
  # live upgrade, so set live upgrade's path variables to /mnt if live
  # upgrade is installed there otherwise set them to /usr

  LUPRINTF='echo'

  if [ -d /mnt/usr/lib/lu ] ; then
    LUBIN='/mnt/usr/lib/lu'
    LUETCBIN='/mnt/etc/lib/lu'
    LUPRINTF='/mnt/etc/lib/lu/luprintf'
  else
    LUBIN='/usr/lib/lu'
    LUETCBIN='/etc/lib/lu'
    LUPRINTF='/etc/lib/lu/luprintf'
  fi

  # Invoke single user mode functionality.

  do_oos_mode "${flag_m}"
  exit "$?"
fi

# 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

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

# Reset all command line parse flags to default values.
flag_l="" # -l f - log file path.
flag_m="" # -m n - alternative BE mount point to look up root spec of (assumes '/')
flag_o="" # -o f - output file path.
flag_x="" # -x n - set debug level to n (PRIVATE).

while [ $# -ne 0 ] ; do
  while getopts l:m:o:x:X c
  do
    case $c in
      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 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 3
	 fi
	 flag_o="${OPTARG}"
	 lulib_set_session_log_file "${flag_o}"
	 ;;
      m) # -m n - alternative BE mount point to look up root device of (assumes '/')
	 # If the argument is a null string, then ignore the flag - makes scripting easier (e.g. -m "" instead of testing for "" in calling script)
	 if [ -n "${OPTARG}" ] ; then
	   lulib_cannot_duplicate_option "${flag_m}" "${OPTARG}" "-m"
	   if [ ! -r "${OPTARG}" ] ; then
	     ${LUPRINTF} -Eelp2 "`gettext 'The mount point <%s> provided by the <-m> option is not valid (not mounted, not readable).'`" "${OPTARG}"
	     usage 3
	   fi
	   lulib_validate_bemntpt "${OPTARG}"
	   if [ "$?" -ne "0" ] ; then
	     ${LUPRINTF} -Eelp2 "`gettext 'The mount point <%s> provided by the <-m> option is not a valid ABE mount point.'`" "${OPTARG}"
	     usage 3
	   fi
	   flag_m="$OPTARG"
	 fi
	 ;;
      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

# Determine the status of SDS

lulib_discover_sds_installation
SDS_DEVROOT=${SDS_DEVROOT:="/dev/md"}

# Default mount point to "/" if not specified via -m option
mntpt="${flag_m:=/}"

# Attempt to determine the root specification using devnm; if that fails,
# attempt to find the root spec from the vfstab file.

ROOT_SPEC="`/usr/sbin/devnm ${mntpt} 2>/dev/null | awk ' { print $1 } '`"
[ -n "${ROOT_SPEC}" ] && ${LUPRINTF} -lp2D - "`gettext 'Candidate root device \
for mount point <%s> is <%s> [from <%s>].'`" "${mntpt}" "${ROOT_SPEC}" \
"/usr/sbin/devnm ${mntpt}"

if [ -z "${ROOT_SPEC}" -a -r "${mntpt}/etc/vfstab" ] ; then
  ROOT_SPEC=`$LUBIN/lucomm_del "${mntpt}/etc/vfstab" | awk ' { if ( $3 == "/" ) { print $1; exit 0 } } '`
  [ -n "${ROOT_SPEC}" ] && ${LUPRINTF} -lp2D - "`gettext 'Candidate root specification \
for mount point <%s> is <%s> [from <%s>].'`" "${mntpt}" "${ROOT_SPEC}" "${mntpt}/etc/vfstab"
fi

if [ -n "${ROOT_SPEC}" ] ; then
    ${LUPRINTF} -lp2D - "`gettext 'Root specification for mount point <%s> is <%s>.'`" \
"${mntpt}" "${ROOT_SPEC}"
    echo "${ROOT_SPEC}"
    exit 0
fi

# See if the root spec can be obtained from the lutab file.
BE_ROOT_SPEC=`${LUETCBIN}/ludo get_root_slice_from_mntpt "${mntpt}" 2>/dev/null`
if [ "$?" -eq 0 -a -n "${BE_ROOT_SPEC}" ] ; then
      ${LUPRINTF} -lp2D - "`gettext 'Root specification for mount point <%s> is <%s>.'`" \
"${mntpt}" "${BE_ROOT_SPEC}"
	echo "${BE_ROOT_SPEC}"
	exit 0
else
  ${LUPRINTF} -Wlp2D - "`gettext 'Root specification for mount point <%s> not found \
from <%s>.'`" "${mntpt}" "${LUETCBIN}/ludo get_boot_slice_from_mntpt ${mntpt}"
fi

# If the root device has not been found, issue error message and exit
# with failure return code.

if [ -z "${ROOT_SPEC}" ] ; then
  if [ "${mntpt}" = "/" ] ; then
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to determine root specification for current BE.'`"
  else
    ${LUPRINTF} -Eelp2 "`gettext 'Unable to determine root specification for BE mounted at <%s>.'`" "${mntpt}"
  fi
  exit 1
fi

${LUPRINTF} -lp2D - "`gettext 'Root specification for mount point <%s> is <%s>.'`" "${mntpt}" "${ROOT_SPEC}"
echo "${ROOT_SPEC}"
exit 0
