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

# 0a  Initialization.

[ -f /lib/svc/share/smf_include.sh ] || exit 1

. /lib/svc/share/smf_include.sh

activity=false

EMI_SERVICE="svc:/system/early-manifest-import:default"
PROFILE_DIR_SITE="/etc/svc/profile/site"

X=
ALT_REPOSITORY=
ALT_MFST_DIR=
early=false
[ "$SMF_FMRI" == "$EMI_SERVICE" ] && early=true

usage()
{
	echo "Usage: /lib/svc/method/manifest-import [-n]" \
	    "[-f repository-file -d manifest-directory]"
	echo "\nOptions:"
	echo "-n dryrun"
	echo "-f and -d specify alternate repository and" \
	    "manifest directory for import\n"
	exit 2
}

while getopts "nd:f:" opt; do
	case $opt in
		n)	X=echo;;
		d)	ALT_MFST_DIR=$OPTARG;;
		f)	ALT_REPOSITORY=$OPTARG;;
		?)	usage;;
	esac
done

#
# Both -f and -d options must be specified together or not specified at all
#
[ -n "$ALT_REPOSITORY" -a -z "$ALT_MFST_DIR" ] && usage
[ -n "$ALT_MFST_DIR" -a -z "$ALT_REPOSITORY" ] && usage

function svccfg_apply {
    if [ -e $1 ]; then
        $X /usr/sbin/svccfg apply $1
        if [ $? -ne 0 ]; then
            echo "WARNING: svccfg apply $1 failed" | tee /dev/msglog
        fi
    fi
}

#
# If the smf/manifest table has file entries that are missing
# then there is work to be done by the cleanup process.
#
function cleanup_needwork {
	if [ "$early" == true ]; then
		smfmfiles=`/usr/bin/svcprop smf/manifest | \
		    awk '(/^lib_/ && /\/manifestfile /) {print $3}'`
	else
		smfmfiles=`/usr/bin/svcprop smf/manifest | \
		    awk '/\/manifestfile / {print $3}'`
	fi

	nw=`/lib/svc/bin/mfstscan $smfmfiles 2>&1 1>/dev/null`
	[ "$nw" ] && return 1

	return 0
}

#
# 2.  Manifest import.  Application directories first, then
# site-specific manifests.
#
function import_manifests {
	typeset basedir=$1
	typeset console_print=$2
	typeset logf="/etc/svc/volatile/manifest_import.$$"

    [ -d "$basedir" ] || return 0;

	rm -f $logf

	nonsite_dirs=`/usr/bin/find $basedir/* -name site \
	    -prune -o -type d -print -prune`

	if [ -n "$_MFST_DEBUG" ]; then
		nonsite_manifests=`/lib/svc/bin/mfstscan $nonsite_dirs`
		site_manifests=`/lib/svc/bin/mfstscan $basedir/site`

		manifests="$nonsite_manifests $site_manifests"

		echo "Changed manifests to import:"
		for m in $manifests; do echo "  $m"; done
	fi

	#
	# Upon boot, attempt to move the repository to tmpfs.
	#
	if [ -z "$ALT_REPOSITORY" -a -z "$ALT_MFST_DIR" ]; then 
		/usr/sbin/svcadm _smf_repository_switch fast
	fi

	#
	# Import the manifests while giving a running display of imports on
	# console, and a final count in the logfile.
	#
	dirs="$nonsite_dirs"
	[ -d "$basedir/site" ] && dirs="$dirs $basedir/site"

	if [ "$console_print" = "true" ]; then
		$X /usr/sbin/svccfg import -p /dev/msglog $dirs > $logf 2>&1
	else
		$X /usr/sbin/svccfg import $dirs > $logf 2>&1
	fi

	grep "Loaded .*. smf(5) service descriptions" $logf > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		activity=true
	fi

	if [ -s $logf ]; then
		grep "smf(5) service descriptions failed to load" $logf > /dev/null 2>&1
		failures=$?
		if [ $failures -eq 0 ]; then
			echo "svccfg warnings:"
		fi
		cat $logf

		if [ $failures -eq 0 -a "$console_print" = "true" ]; then
			msg="svccfg import warnings.  See"
			msg="$msg /var/svc/log/system-manifest-import:default.log ."
			echo $msg > /dev/msglog
		fi
	fi
	rm -f $logf
}

#
# 0b Cleanup deathrow
#
if [ "$early" = "false" ];then
	deathrow=/etc/svc/deathrow
	if [ -s $deathrow ];then
		#
		# svc.startd has unconfigured the services found in deathrow,
		# clean them now.
		#
		while read fmri mfst pkgname; do
			# Delete services and instances from the deathrow file.
			/usr/sbin/svccfg delete -f $fmri >/dev/null 2>&1
			# Remove deathrow manifest hash.
			/usr/sbin/svccfg delhash -d $mfst >/dev/null 2>&1
		done < $deathrow
		/usr/bin/mv $deathrow $deathrow.old
	fi
fi

SVCCFG_CHECKHASH=1 export SVCCFG_CHECKHASH

#
# If the alternate repository and directory are specified, simply set
# SVCCFG_REPOSITORY env, run svccfg import on the given directory, and
# exit.
#
if [ -n "$ALT_REPOSITORY" -a -n "$ALT_MFST_DIR" ]; then 
	SVCCFG_REPOSITORY=$ALT_REPOSITORY export SVCCFG_REPOSITORY
	import_manifests "$ALT_MFST_DIR" false
	unset SVCCFG_REPOSITORY
	exit 0
fi

#
# Call import and apply profiles here
#
import_manifests "/lib/svc/manifest" true

#
# 6.  Final actions.
#

if $activity; then
	/usr/sbin/svcadm _smf_backup "manifest_import" || true
fi

#
# If the filesystem is NOT read only then move the repo back to perm
# There is no care wether the switch was made or not, but just want
# to move it.  If it is already perm this does not affect anything
# at least on the surface.  REALLY want to improve on this...
#
touch /etc/svc/smf_rwtest.$$ > /dev/null 2>&1
if [ $? -eq 0 ]; then
	rm -f /etc/svc/smf_rwtest.$$
	/usr/sbin/svcadm _smf_repository_switch perm || { \
	    echo "Repository switch back operation failed, \c"
	    echo "please check the system log for the"
	    echo "possible fatal error messages."
	    exit $SMF_EXIT_ERR_FATAL
	    }
fi

if $activity; then
	/usr/sbin/svccfg cleanup | /usr/bin/tee /dev/msglog
else
	cleanup_needwork
	if [ $? -ne 0 ]; then
		/usr/sbin/svccfg cleanup -a | /usr/bin/tee /dev/msglog
	fi
fi

exit 0
