#!/usr/bin/ksh
#
# 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) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
#

# =============================================================================
# =============================================================================
# boot_archive_configure - Configure a populated boot archive area
#				into a usable boot archive, less archiving.
# =============================================================================
# =============================================================================

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
create_sym_links()
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Make symbolic links from the boot archive out to all files not existing in the
# boot archive.  Create any needed directories as well..
#
# Args:
#   Package Image Area Filelist: file containing names of all files/dirs in
#	package image area.
#
#   Boot archive Filelist: file containing names of all files/dirs in the boot archive
#
#   Mount Point: Copies of actual files exist in a lofi-mounted filesystem.
#	This argo represents the lofi-mount point of that filesystem.
#
# Note: Assumes current directory is $BA_BUILD
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
        PKG_IMG_FILELIST=$1
        BOOT_ARCHIVE_FILELIST=$2
        MNT_PT=$3

	# Create a fresh empty list of processed files.
        PROC_FILELIST=${TMP_DIR}/plist
        rm -f ${PROC_FILELIST}
        $TOUCH ${PROC_FILELIST}

	# Loop through all files in the package image area
        while read -r pi_file
        do
		# Quote refs to pi_file as needed to accommodate filenames
		# with spaces in them
		#
                # Skip this file if it has already been processed or it
                # already exists in the boot archive
                #
                $GREP "^${pi_file}\$" ${PROC_FILELIST} > /dev/null
                [ $? -eq 0 ] && continue
                $GREP "^${pi_file}\$" ${BOOT_ARCHIVE_FILELIST} > /dev/null
                [ $? -eq 0 ] && continue

		#
		# Create any missing directory path to the file and
		# add it to the list of processed files/dirs.
		#
                dir=$(dirname "$pi_file")
                if [ ! -d $dir ]; then
                        mkdir -p $dir
                        echo $dir >> ${BOOT_ARCHIVE_FILELIST}
                fi

		# If the file is a directory, append a / to the end of the name.
                [ -d "${BOOT_ARCHIVE_FILELIST}/${pi_file}" ] && \
		    pi_file="${pi_file}"/

		# Create the link from the boot archive to the actual file.
                ln -sf ${MNT_PT}/"${pi_file}" "${pi_file}"

		# Add the file to the list of processed files/dirs.
                echo "$pi_file" >> ${PROC_FILELIST}
        done < ${PKG_IMG_FILELIST}

}


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Main
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Configure a populated boot archive area into a usable boot archive, less archiving.
# 
# Args:
#   MFEST_SOCKET: Socket needed to get manifest data via ManifestRead object
#
#   PKG_IMG_PATH: Package image area
#
#   TMP_DIR: Temporary directory to contain the boot archive file
#
#   BA_BUILD: Area where boot archive is put together.
#
#   MEDIA_DIR: Area where the media is put. (Not used)
#
#   IMG_TYPE_MARKER_FILE: Denotes the type of image.
#
# Note: This assumes a populated boot archive area exists at $BA_BUILD.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# Verify argument count
if [ $# != 6 ] ; then
	print -u2 -f "%s: Requires 6 args: Reader socket, pkg_image area,\n" \
	    "$0"
	print -u2 "    tmp dir, boot archive build area, media area,"
	print -u2 "    img_type_file."
	exit 1
fi

# Get commandline args.  First 5 are passed to all finalizer scripts.
MFEST_SOCKET=$1
PKG_IMG_PATH=$2
if [ ! -d $PKG_IMG_PATH ] ; then
	print -u2 -f "%s: Image package area %s is not valid\n" \
	    "$0" "$PKG_IMG_PATH"
	exit 1
fi

TMP_DIR=$3
if [ ! -d $TMP_DIR ] ; then
	print -u2 -f "%s: Temporary area %s is not valid\n" "$0" "$TMP_DIR"
	exit 1
fi

BA_BUILD=$4
if [ ! -d $BA_BUILD ] ; then
	print -u2 -f "%s: Boot archive build area is not valid\n" "$0"
	exit 1
fi

IMG_TYPE_MARKER_FILE=$6

builtin cd
builtin cp
builtin rm
builtin mkdir
builtin chmod
builtin chown
builtin ln

# Define a few commands.
CHROOT=/usr/sbin/chroot
DEVFSADM=/usr/sbin/devfsadm
ED=/usr/bin/ed
FIND=/usr/bin/find
GREP=/usr/xpg4/bin/grep
MAKEUUID=/usr/bin/makeuuid
TOUCH=/usr/bin/touch
TR=/usr/bin/tr
SED=/usr/bin/sed
SVCCFG_CMD=$PKG_IMG_PATH/usr/sbin/svccfg

# These commands are not delivered with the core OS.
MANIFEST_READ=/usr/bin/ManifestRead
MKREPO=/usr/share/distro_const/mkrepo

# Name of volume set ID file in the boot archive
VOLSETID_FILENAME=.volsetid

# hostname name for the image
HOSTNAME="openindiana"

print "Configuring boot archive..."

if [ ! -x $SVCCFG_CMD ] ; then
        echo "$SVCCFG_CMD is not executable" >& 2
        exit 1
fi


# Configure devices
${BA_BUILD}/${DEVFSADM} -r $BA_BUILD

# Set marker so that every boot is a reconfiguration boot
${TOUCH} $BA_BUILD/reconfigure

# Set up /etc/coreadm.conf.  Calling coreadm affects the host system by calling
# into SMF services.  This is to have coreadm take affect on the live system.
# It is safe to just create the coreadm.conf file for live_CD as there is no
# live system which would miss the SMF changes.
#
# Below creates a coreadm.conf as if the following is run:
#	$COREADM -g /tmp/core -G default -i core -I default -e process
#
cat << \COREADM_CONF_EOF > $BA_BUILD/etc/coreadm.conf
#
# coreadm.conf
#
# Parameters for system core file configuration.
# Do NOT edit this file by hand -- use coreadm(1) instead.
#
COREADM_GLOB_PATTERN=/tmp/core
COREADM_GLOB_CONTENT=default
COREADM_INIT_PATTERN=core
COREADM_INIT_CONTENT=default
COREADM_GLOB_ENABLED=no
COREADM_PROC_ENABLED=yes
COREADM_GLOB_SETID_ENABLED=no
COREADM_PROC_SETID_ENABLED=no
COREADM_GLOB_LOG_ENABLED=no
COREADM_CONF_EOF
# Note: end of coreadm.conf

# Setup the /etc/rtc_config file, assuming it is GMT.
# We couldn't use "/usr/sbin/rtc" command because even doing it
# with chroot seem to still affect the host on which chroot is run.
cat << \RTC_CONFIG_EOF > $BA_BUILD/etc/rtc_config
#
#       This file (/etc/rtc_config) contains information used to manage the
#       x86 real time clock hardware.  The hardware is kept in
#       the machine's local time for compatibility with other x86
#       operating systems.  This file is read by the kernel at
#       boot time.  It is set and updated by the /usr/sbin/rtc
#       command.  The 'zone_info' field designates the local
#       time zone.  The 'zone_lag' field indicates the number
#       of seconds between local time and Greenwich Mean Time.
#
zone_info=GMT
zone_lag=0
RTC_CONFIG_EOF

# Set timezone to GMT
printf "/^TZ=.*/\ns/^TZ=.*/TZ=GMT/\nw" | \
        $ED -s $BA_BUILD/etc/default/init > /dev/null

# Set nodename to HOSTNAME, and add HOSTNAME as an alias for localhost
# in /etc/inet/hosts
echo $HOSTNAME > $BA_BUILD/etc/nodename

$SED "s/127.*$/& ${HOSTNAME}/" $BA_BUILD/etc/inet/hosts > $TMP_DIR/hosts.mod
if [ "$?" != "0" ] ; then
	print -u2 -f "%s: Failed to modify %s/etc/inet/hosts.\n" \
	    "$0" "$BA_BUILD"
	exit 1
fi
cp $TMP_DIR/hosts.mod $BA_BUILD/etc/inet/hosts
rm $TMP_DIR/hosts.mod

print "Preloading SMF repository..."

$MKREPO $BA_BUILD $PKG_IMG_PATH

export SVCCFG_REPOSITORY=${BA_BUILD}/etc/svc/repository.db
export LD_LIBRARY_PATH=$PKG_IMG_PATH/lib:$PKG_IMG_PATH/usr/lib:$LD_LIBRARY_PATH

emi=true
[ -f ${PKG_IMG_PATH}/lib/svc/manifest/system/early-manifest-import.xml ] || \
	emi=false

# Apply the list of SMF service profiles specified in the manifest
PROF_NODE_PATH="distro_constr_params/output_image/boot_archive/\
smf_service_profile/profile"

SVC_PROFS=$($MANIFEST_READ $MFEST_SOCKET ${PROF_NODE_PATH}/path)

for PROF in $($MANIFEST_READ $MFEST_SOCKET ${PROF_NODE_PATH}/path) ; do
	USE_SYS_NODE=${PROF_NODE_PATH}"[path=\""${PROF}"\"]/use_build_sys_file"
	USE_SYS=$($MANIFEST_READ $MFEST_SOCKET ${USE_SYS_NODE}|\
	    ${TR} '[:upper:]' '[:lower:]')
	if [ "${USE_SYS}" != "true" ] ; then
		DTD_ROOT=${BA_BUILD}
		SVC_PROF=${PKG_IMG_PATH}/${PROF}

		#
		# Before Early Manifest Import (EMI) integration,
		# profiles in the package image area should exist in /var/svc.
		# After EMI integration, profiles in the package image area
		# should exist in /etc/svc.  If a specified a profile
		# is in /etc/svc, and the image to be built is a pre-EMI
		# image, it will be skipped.  If a specified profile
		# is in /var/svc, and the image to be built is a post-EMI
		# image, it will be skipped.  This guarantees 
		# correct profiles are being applied regardless EMI
		# functionality exists or not.
		#
		echo $SVC_PROF | ${GREP} -q "/etc/svc/"
		etc_profile=$?
		[ "${emi}" == "true" -a ${etc_profile} -ne 0 ] && continue
		[ "${emi}" == "false" -a ${etc_profile} -eq 0 ] && continue
	else
		DTD_ROOT="/"
		SVC_PROF=${PROF}
	fi

	print "Applying SMF profile: ${SVC_PROF}"

        # Set the DTD reference for every profile applied so that it is
        # consistent with the profile that's being applied.
	export SVCCFG_DTD=${DTD_ROOT}/usr/share/lib/xml/dtd/service_bundle.dtd.1
	${SVCCFG_CMD} apply ${SVC_PROF}
	if [ "$?" != "0" ] ; then
		print -u2 -f "%s: Failed to apply %s.\n" "$0" "${SVC_PROF}"
		exit 1
	fi
done


cd $BA_BUILD

# create ./bin -> ./usr/bin symlink
ln -s ./usr/bin

# Create mount points for misc and pkg zlibs.
mkdir mnt/misc
chmod 0755 mnt/misc
mkdir mnt/pkg
chmod 0755 mnt/pkg

# create volume set id file
VOLSETID=$($MAKEUUID)

echo $VOLSETID > $VOLSETID_FILENAME
chmod 0444 $VOLSETID_FILENAME
chown root:root $VOLSETID_FILENAME

# create the file marking the image type (e.g. .autoinstall or .livecd)
$TOUCH $IMG_TYPE_MARKER_FILE

# create ./.cdrom directory
mkdir .cdrom
chmod 0755 .cdrom

# create a symlink in the boot archive to the opt directory in the misc archive
ln -s /mnt/misc/opt opt

#
# Additional /var /etc setup. A bunch of files in /var and /etc
# are left out of the ramdisk otherwise they will increase ramdisk
# size substantially. The code below automatically populates the
# ramdisk with symlinks to another mountpoint where the rest of
# /var and /etc are mounted from another compressed lofi file.
#

print "Creating additional symlinks in ramdisk ..."

$FIND * > ${TMP_DIR}/boot_archive_filelist

# /mnt/misc will contain pkg_image area /etc and /var contents
(cd $PKG_IMG_PATH; $FIND etc var) > ${TMP_DIR}/mlst
create_sym_links ${TMP_DIR}/mlst  ${TMP_DIR}/boot_archive_filelist "/mnt/misc"

exit 0
