#!/usr/bin/ksh93

#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#

#
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#

#
# =============================================================================
# prepare_ai_image : Modify a bootable AI image to work with VMC
# =============================================================================
#

#
# Establish PATH for non-built in commands
#
export PATH=/usr/xpg4/bin:/bin:/usr/bin:/usr/sbin

#
# Source in shared common VMC code.
# All variable and functions defined in vmc_common are named with
# prefix "vmc" or VMC.
#
. /usr/share/distro_const/vmc/vmc_common

#
# Make sure all math stuff runs in the "C" locale
#
vmc_set_locale

#######################################################################
# cleanup
#	This function attempts to clean up any resources this script
#	could generate. Depending on where in the script this function
#	is involved some resources may not be there to cleanup, but
#	that will not adversely effect anything.
#
#	This function is not defined using the function keyword
#	to avoid an exit loop.
#
# Input: none
# Returns: none
#
#######################################################################
cleanup ()
{

	#
	# It is not necessary to process errors.
	#
	{

		trap "" ERR INT
		set +o errexit

		cd ${START_CWD}


		#
		# Cleanup resources here.
		#
		sleep 5 
		/usr/sbin/umount ${MNT_ISO}

		if [[ ${lofi_dev} != "" ]] ; then
			/usr/sbin/lofiadm -d ${lofi_dev}
		fi

		if [[ ${lofi_dev_mroot} != "" ]] ; then
			/usr/sbin/lofiadm -d ${lofi_dev_mroot}
		fi

		rm -rf ${TMP_DIR}/menu.lst_$$ ${TMP_ISO} ${MNT_ISO}

	} > /dev/null 2>&1

}

#######################################################################
# main
#
# Name: prepare_ai_image
#
# Args:
#       MFEST_SOCKET: Socket to get manifest data via ManifestRead object
#       PKG_IMG_PATH: Package image area
#       TMP_DIR: Temporary directory to contain the bootroot file
#       BR_BUILD: Area where bootroot is put together (not used)
#       MEDIA_DIR: Area where the media is put. (Not used)
#
# Additional arguments passed as arguments to this finalizer script
#       from the VMC Manifest:
#	<full path to bootable ai iso> -
#	<full path to AI client manifest or "default" to use the
#	default AI client manifest already on the media
#
# Output:
#
#	A bootable AI image with a modified GRUB menu which contains
#	the flag: "-B auto_shutdown=enable"
#
# Diagnostic Output:
#
#       Message written to standard output (print -u1) will go to
#       the distro constructor log file.
#
#       Message written to standard error (print -u2) will go to
#       the distro constructor log file and the screen where the
#       distro constructor is being run.
#
# Description:
#
#	This finalizer script will take as input a path to a
#	Bootable AI client image and optionally a path to an AI
#	client manifest. It will modify the GRUB grub/menu.lst
#	to contain a kernel entry with the flag: "-B auto_shutdown=enable
#	and if a client manifest is supplied it will place that
#	manifest on the media to be used during installation.
#
# Returns:
#	1 on failure
#	0 on success
#
#######################################################################

builtin cat
builtin cut
builtin chmod
builtin cp
builtin fgrep
builtin grep
builtin mkdir
builtin mv
builtin pwd
builtin rm
builtin sleep

#
# Variable which act as constants are in CAPs
# Variable which can be modified are in lower case
#

#
# Process command line arguments
#
if (( $# != 7 )) ; then
	print -u2 "\nWrong number of arguments provided by Distro Constructor."
	exit 1
fi

typeset -r PKG_IMG_PATH="$2"
typeset -r TMP_DIR="$3"
typeset -r ISO_FILE="$6"  # path to bootable ai image
typeset -r AI_MANIFEST="$7"  # path to ai client manifest or default

#
# Validate the arguments
#
if [[ ! -d ${PKG_IMG_PATH} ]] ; then
	print -u2 "\nImage package area ${PKG_IMG_PATH} is not valid"
	exit 1
fi

if [[ ! -d ${TMP_DIR} ]] ; then
	print -u2 "\nTemporary area ${TMP_DIR} is not valid"
	exit 1
fi

if [[ ! -f ${ISO_FILE} ]] ; then
	print -u2 "\nISO file ${ISO_FILE} is not found"
	exit 1
fi

if [[ ${AI_MANIFEST} != "default" && ! -f ${AI_MANIFEST} ]] ; then
	print -u2 "\nAI Client Manifest: ${AI_MANIFEST} is not found"
	exit 1
fi

#
# Confirm file(1) reports the specified file is an ISO
#
if [[ $(file ${ISO_FILE}) != ~(E)ISO[ ]*9660[ ]*filesystem[ ]*image ]] ; then
	print -u2 "\nFile ${ISO_FILE} is not an ISO"
	print -u2 "$(file ${ISO_FILE})"
	exit 1
fi

#
# Establish local variables
#
typeset -r  START_CWD=$(pwd)
typeset -r  MNT_ISO="${TMP_DIR}/mnt_iso_$$" # mount for the ISO
typeset -r  TMP_ISO="${TMP_DIR}/tmp_iso_$$"

#
# Set the path the the new modified ISO image This is done in
# vmc_common function so it is set in one place.
#
# This program creates this file so ignore the file not
# found status from vmc_set_new_iso_path
#
vmc_set_new_iso_path ${PKG_IMG_PATH}

#
# Set up error handling.
# Where possible explicitly check command return status for errors.
#
trap "vmc_error_handler_trap" INT
set +o errexit

typeset vol_id=""
typeset vol_set_id=""
typeset lofi_dev=""
typeset lofi_dev_mroot=""
typeset -i cmd_stat=0
typeset min_mem64=""

#
# Clean out any possible content left over from a prior aborted run,
# ignoring any possible errors.
#
{
	rm -rf ${VMC_NEW_ISO} ${MNT_ISO} ${TMP_ISO}
} > /dev/null 2>&1

#
# Create the needed directories
#
mkdir ${MNT_ISO}
cmd_stat=$?
vmc_error_handler ${cmd_stat} "\nFailed to make directory: ${MNT_ISO}"

mkdir ${TMP_ISO}
cmd_stat=$?
vmc_error_handler ${cmd_stat} "\nFailed to make directory: ${TMP_ISO}"

#
# lofiadm/mount the ISO for read-only access
#
lofi_dev=$(/usr/sbin/lofiadm -a ${ISO_FILE})
cmd_stat=$?
vmc_error_handler ${cmd_stat} "\nWarning: lofiadm -a ${ISO_FILE} failed"

/usr/sbin/mount -F hsfs ${lofi_dev} ${MNT_ISO}
cmd_stat=$?
vmc_error_handler ${cmd_stat} "\nWarning: failed to mount ISO"

#
# Unpacked the mounted ISO for write access.
#
cd ${MNT_ISO}
find . -print | cpio -pdum ${TMP_ISO}
cmd_stat=$?
vmc_error_handler ${cmd_stat}  "\nWarning: failed to unpack the ISO"

cd ${START_CWD}

#
# Make the needed changes to the GRUB menu.lst file.
#
print -u1 "\nMake the needed changes to the GRUB menu.lst file."
if [[ -f ${TMP_ISO}/boot/grub/menu.lst ]] ; then
	#
	# Preserve the min_mem64 entry from the initial menu.lst file.
	#
	min_mem64="$(fgrep min_mem64 ${TMP_ISO}/boot/grub/menu.lst)"

	#
	# Write the required contents to the menu.lst file
	# Note: The first line written is not doing an append
	# clearing the original contents of the file.
	#
	print "default=0" > ${TMP_ISO}/boot/grub/menu.lst
	print "timeout=5" >> ${TMP_ISO}/boot/grub/menu.lst
	print "${min_mem64}" >> ${TMP_ISO}/boot/grub/menu.lst

	print "\ntitle OpenIndiana Development Virtual Machine Constructor" \
	    "Automated Install" >> ${TMP_ISO}/boot/grub/menu.lst
	print "\tkernel$ /platform/i86pc/kernel/\$ISADIR/unix" \
	    "-B install=true -B auto-shutdown=enable" \
	    >> ${TMP_ISO}/boot/grub/menu.lst
	print "\tmodule$ /platform/i86pc/\$ISADIR/boot_archive" \
	    >> ${TMP_ISO}/boot/grub/menu.lst

	#
	# Make sure the file mode and owner are correct.
	#
	chmod 644 ${TMP_ISO}/boot/grub/menu.lst
	chown root:sys ${TMP_ISO}/boot/grub/menu.lst

else
	vmc_error_handler 1 "\nWarning: GRUB menu.lst file not found."
fi

#
# Place the contents of the modified GRUB menu.lst file in the log.
#
print -u1 "\nThe modified GRUB menu.lst file:"
cat ${TMP_ISO}/boot/grub/menu.lst
print -u1 "\n"

#
# The Volume ID and Volume set ID values needs to be specified on 
# the mkisofs command so the volume ID and volume set ID on the new 
# ISO this script generates matches them on the original ISO. 
#
vol_id=$(/usr/sbin/fstyp -v ${lofi_dev} | grep "Volume id:" | \
    cut -f2 -d: | /usr/bin/sed 's/^ *//;s/ *$//')
if [[ ${vol_id} == "" ]] ; then
        vmc_error_handler 1 \
	    "\nWarning: unable to identify the volume ID of the original ISO"
fi

vol_set_id=$(/usr/sbin/fstyp -v ${lofi_dev} | grep "Volume set id:" | \
    cut -f2 -d: | /usr/bin/sed 's/^ *//;s/ *$//')
if [[ ${vol_set_id} == "" ]] ; then
        vmc_error_handler 1 \
	    "\nWarning: unable to identify the volume set ID of the original ISO"
fi

#
# Replace the default AI Client Manifest (/auto_install/default.xml)
# with what the user supplied (if default is specified then nothing
# is replaced).
#
if [[ ${AI_MANIFEST} != "default" ]]; then
	print -u1 "\nReplacing default AI client manifest with user supplied manifest"
	cp ${AI_MANIFEST} ${TMP_ISO}/auto_install/default.xml
else
	print -u1 "\nImage will use default AI client manifest"
fi

#
# Recreate the ISO with mkisofs and the correct file permissions.
#
print -u1 "\nRecreate the ISO with mkisofs."
mkisofs -o "${VMC_NEW_ISO}" -b boot/grub/stage2_eltorito -c .catalog \
    -no-emul-boot -boot-load-size 4 -boot-info-table -N -l -R -U \
    -allow-multidot -no-iso-translate -cache-inodes -d -D \
    -volset "${vol_set_id}" -V "${vol_id}" "${TMP_ISO}"
cmd_stat=$?
vmc_error_handler ${cmd_stat} "\nWarning: failed to create the ISO"

chmod a+r ${VMC_NEW_ISO}
cmd_stat=$?
vmc_error_handler ${cmd_stat} \
    "\nFailed to set the file permissions of the new ISO ${VMC_NEW_ISO}"

#
# cleanup then exit with success status
#
cleanup
exit 0
