#!/bin/ksh -p
#
# 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, 2012, Oracle and/or its affiliates. All rights reserved.
#

#
# image_install is used when installing a zone in a p2v or v2v scenario.
# This script is invoked by pkgcreatezone due to the use of the -a or -d
# option to zoneadm install.
#
# For both p2v and v2v, data is transferred into the zone's dataset
# hierarchy - either from an archive or a directory.  In the case of
# p2v, additional processing is performed to convert the global zone
# image into a non-global zone image.  This additional processing is
# performed by the brand's p2v script.
#

. /usr/lib/brand/solaris/common.ksh

# Allows developer to override some things like PATH and PYTHONPATH
. /usr/lib/brand/solaris/developerenv.ksh
m_usage=$(gettext "\n        install {-a archive|-d path} {-p|-u} [-s|-v] [-c profile.xml | dir]")

# If not doing p2v, m_postnote3 is cleared.
m_postnote3=$(gettext "              Make any other adjustments, such as disabling SMF services\n              that are no longer needed.")

media_missing=\
$(gettext "%s: you must specify an installation source using '-a' or '-d'.")
cfgchoice_missing=\
$(gettext "you must specify -u (configure) or -p (preserve identity).")

# Clean up on interrupt
trap_cleanup()
{
	log "$m_interrupt"

	trap_exit
}

# If the install failed then clean up the ZFS datasets we created.
trap_exit()
{
	# trap_cleanup calls trap_exit.  Don't make multiple passes.
	trap - INT EXIT

	# umount any mounted file systems
	[[ -n "$fstmpfile" ]] && umnt_fs

	if (( $EXIT_CODE != $ZONE_SUBPROC_OK )); then
		delete_unpinned_datasets "${zone.path.ds}"
		#
		# If cleanup completed, don't force the use of zoneadm
		# uninstall, as it will have no work to do.
		#
		if (( $? == 0 && $EXIT_CODE == $ZONE_SUBPROC_FATAL )); then
			EXIT_CODE=$ZONE_SUBPROC_TRYAGAIN
		fi
		unpin_datasets "${zone.path.ds}" || error "$f_unpin"
	fi

	vlog "Exiting with exit code $EXIT_CODE"
	finish_log zone

	exit $EXIT_CODE
}

#
# The main body of the script starts here.
#
# This script should never be called directly by a user but rather should
# only be called by pkgcreatezone to install an OpenSolaris system image into
# a zone.
#

#
# Exit code to return if install is interrupted or exit code is otherwise
# unspecified.
#
EXIT_CODE=$ZONE_SUBPROC_USAGE

# Used by start_log
set -A save_args "$0" "$@"

# If we weren't passed at least two arguments, exit now.
(( $# < 2 )) && exit $ZONE_SUBPROC_USAGE

init_zone zone "$1" "$2"
eval $(bind_legacy_zone_globals zone)
shift; shift	# remove zonename and zonepath from arguments array

unset inst_type
unset msg
unset silent_mode
unset verbose_mode
sc_config=
allow_update=min

#
# It is worth noting here that we require the end user to pick one of
# -u (configure) or -p (preserve config).  This is because we can't
# really know in advance which option makes a better default.  Forcing
# the user to pick one or the other means that they will consider their
# choice and hopefully not be surprised or disappointed with the result.
#
unset unconfig_zone
unset preserve_zone

#
# If extracting an archive that contains multiple BEs, it is possible that
# we won't be able to automatically select which BE to set as the active
# zbe.  In such a case, discover_active_be() will suggest the use of this
# command.  It may be augmented in getopts processing.
#
set -A ATTACH_Z_COMMAND zoneadm -z "${zone.name}" attach -z "<zbe>" -u

while getopts "a:c:d:psuUv" opt
do
	case "$opt" in
		a)
			if [[ -n "$inst_type" ]]; then
				fatal "$both_kinds" "zoneadm install"
			fi
			# [[ -f ... ]] does not trigger the automounter
			ls "$OPTARG" >/dev/null 2>&1
			[[ -f $OPTARG ]] || fatal "$f_arg_not_file" "$OPTARG"
		 	inst_type="archive"
			install_media="$OPTARG"
			;;
		c)	sc_config=$OPTARG
			a_push ATTACH_Z_COMMAND "-c" "$OPTARG"
			;;
		d)
			if [[ -n "$inst_type" ]]; then
				fatal "$both_kinds" "zoneadm install"
			fi
			# [[ -d ... ]] does not trigger the automounter
			ls "$OPTARG" >/dev/null 2>&1
			[[ -d $OPTARG ]] || fatal "$f_arg_not_dir" "$OPTARG"
		 	inst_type="directory"
			install_media="$OPTARG"
			;;
		p)	preserve_zone="-p";;
		s)	silent_mode=1;;
		u)	unconfig_zone="-u"
			#
			# attach doesn't have an "unconfigure" option, so if
			# attach -z will be needed, provide an appropriate
			# option for a sysconfig profile that will do the
			# unconfigure.
			#
			a_push ATTACH_Z_COMMAND "-c" \
			    /usr/share/auto_install/sc_profiles/enable_sci.xml
			;;
		U)	allow_update=all ;;
		v)	verbose_mode="-v"
			a_push ATTACH_Z_COMMAND "-v"
			;;
		*)	exit $ZONE_SUBPROC_USAGE;;
	esac
done
shift OPTIND-1

# The install can't be both verbose AND silent...
[[ -n $silent_mode && -n $verbose_mode ]] &&
    fail_usage "$f_incompat_options" "-s" "-v"

# Cannot preserve the config and apply a config.
[[ -n $preserve_zone && -n $sc_config ]] &&
    fail_usage "$f_incompat_options" "-p" "-c"

[[ -z $install_media ]] && fail_usage "$media_missing" "zoneadm install"

# The install can't both preserve and unconfigure
[[ -n $unconfig_zone && -n $preserve_zone ]] &&
    fail_usage "$f_incompat_options" "-u" "-p"

# Must pick one or the other.
[[ -z $unconfig_zone && -z $preserve_zone ]] && fail_usage "$cfgchoice_missing"

#
# From here on out, an unspecified exit or interrupt should exit with
# ZONE_SUBPROC_FATAL, meaning a user will need to do an uninstall before
# attempting another install, as we've modified the directories we were going
# to install to in some way.  Note, however, that this is influenced by
# pin_datasets() and trap_exit().
#
trap trap_cleanup INT
trap trap_exit EXIT
EXIT_CODE=$ZONE_SUBPROC_FATAL

start_log zone attach "${save_args[@]}"
vlog "Starting pre-installation tasks."
pin_datasets "${zone.path.ds}" || fatal "$f_pin"

#
# Create the ZBE and transfer data to it.
#
vlog "Installation started for zone \"%s\"" "${zone.name}"
attach_datasets -t "$inst_type" -m "$install_media" zone || exit $EXIT_CODE
log "$m_active_zbe" "${zone.active_ds}"

set -- $(pkg -R "${zone.root}" variant -H variant.opensolaris.zone)
if [[ $2 == nonglobal ]]; then
	# Disable this message - it is only relevant for p2v.
	m_postnote3=
fi

# We've made it far enough that attach can fix it.
EXIT_CODE=$ZONE_SUBPROC_UNAVAILABLE

enable_zones_services 1 || exit $EXIT_CODE

# Attach the image, perhaps with updates.
attach_image zone "$allow_update"

# Be sure that shared data that shouldn't be in in the ZBE isn't in the ZBE.
migrate_export zone
migrate_rpool zone

#
# Unconfigure or reconfigure the zone.
#
[[ -n $unconfig_zone ]] && reconfigure_zone "$sc_config"

EXIT_CODE=$ZONE_SUBPROC_OK

# Do not leave the BE mounted for labeled zones.
[[ ${zone.brand} == labeled ]] && unmount_be zone

unpin_datasets "${zone.path.ds}" || error "$f_unpin"

log "\n$m_complete_seconds" ${SECONDS}
printf "$m_postnote\n"
printf "$m_postnote2\n"
[[ -n $m_postnote3 ]] && printf "$m_postnote3\n"

finish_log zone logfile

trap - EXIT
exit $ZONE_SUBPROC_OK
