#!/bin/sh
#
#ident "@(#)metacvt.sh   1.18     95/07/13 SMI"
#
# Copyright (c) 1992, 1993, 1994, 1995 by Sun Microsystems, Inc.
#

#
# Convert a previous version of disksuite to the current version of disksuite
#

#
# Function definitions
#

#
# Remove files
#
# Input:	_FTR(var) - a list of variable name, files or a combination
#
# e.g.- _FTR="${tfile} /tmp/xyzzy"
#
rmf() {
    if [ "${_FTR}" -a ${debug:-0} -eq 0 ]; then
	eval ${RM:-"/usr/bin/rm"} -f ${_FTR}
	return ${?}
    fi
    return 0
}

#
# Print an error and exit
#
# Input:	verbose(var) - when on die 1 prints Exiting message
#		$1 - single arg, exit code
#		$1 - double arg, user supplied message and $2 is the exit code
#		_ENDP(var) - list of commands to execute before exit processing
#
die() {
    trap 0
    if [ ${#} -gt 2 ]; then
	echo "${ProgName}: die() takes up to 2 arguments..."
	exit 1
    fi
    if [ "${_ENDP}" ]; then
	eval ${_ENDP}
    fi
    exitcode=0
    if [ ${#} -eq 2 ]; then
	echo "${ProgName}: ${1}"
	echo "Exit ${2}"
	exitcode=${2}
    elif [ ${#} -eq 1 ]; then
	if [ "${verbose}" -ne 0 ]; then
	    echo "${ProgName}: Exit ${1}"
	fi
	exitcode=${1}
    fi
    rmf
    exit ${exitcode}
}

#
# Initialize
#
# Inputs: None
#
# Function: Set the ProgName for use in errors, set up traps for cleanup
#
init() {
    ProgName=`basename ${0}`
    FullProgName=${0}

    trap 'die ${TRAPPING}' 0 1 2 3 15

    TRAPPING='Aborted 1'
}

#
# Terminate
#
# Inputs: None
#
# Function: exit gracefully and quietly
#
finit() {
    TRAPPING=
    exit 0
}

#
# Issue a usage message
#
# Inputs:	_USE(var) - user supplied usage message
#
usage() {
    if [ "${_USE}" ]; then
	die "Usage: ${ProgName} ${_USE}" 1
    else
	die "Usage: ${ProgName} ..." 1
    fi
}

#
# Print a warning
#
warn() {
    echo "\n*** WARNING: ${1}"
}

#
# Print a warning (continued)
#
warnc() {
    echo "             ${1}"
}

#
# Print a note
#
note () {
    echo "$1"
}

#
# Fix metastat continued lines
#
fix_lines() {
    ${AWK} '\
    BEGIN { \
	line = ""; \
    } \
    $NF == "\\" { \
	$NF = ""; \
	line = line $0; \
	next; \
    } \
    $NF != "\\" { \
	if ( line != "" ) { \
	    print line $0; \
	    line = ""; \
	} else { \
	    print $0; \
	} \
    } \
    ' | sed -e 's;/dev/dsk/;;g' -e 's;/dev/rdsk;;g'
}

#
# Check the devices at each level of the device
#
check_all_devs() {
    if [ ${#} -lt 3 ]; then
	echo "${ProgName}: check_all_devs() requires 3 arguments..."
	return 1
    fi
    mdtabfile=${1}; shift
    mp=${1}; shift

    while [ ! -z "${1}" ]; do
	comps=""
	for i in ${*}; do
	    case "${i}" in
		d*)
		    c=`is_simple "${mdtabfile}" ${mp} ${i}`
		    _status=${?}
		    if [ ${_status} -ne 0 ]; then
			break
		    fi
		    [ -z "${comps}" ] && comps="${c}" || comps="${comps} ${c}"
		    ;;

		c*)
		    continue
		    ;;

	    esac
	done
	if [ ${_status} -ne 0 ]; then
	    break
	fi
	if [ ! -z "${comps}" ]; then
	    set -- ${comps}
	else
	    break
	fi
    done
    if [ ${_status} -ne 0 ]; then
	return 1
    fi
    return 0
}

#
# Check to see if the argument passed in is mounted on a metadevice
#
check_osfs() {
    if [ ${#} -lt 1 ]; then
	echo "${ProgName}: check_osfs() requires 1 argument..."
	exit 1
    fi
    ckmp=${1}
    mdrootdev=""
    found=0
    _status=0
    exec <${vfstab}
    while read bdev rdev mp fsty fscp am mo
    do
	# Skip comments and blank lines
	case "${bdev}" in
	    '#'* | '')
		continue
		;;

	esac

	#
	# If we are dealing with swap, then do some fixups.
	#
	if [ "${ckmp}" = "swap" -a "${fsty}" = "swap" ]; then
	    rdev=`echo ${bdev} | ${SED} -e 's/dsk/rdsk/'`
	    mp="swap"
	fi

	#
	# If this is not one of the entries we care about, carry on.
	#
	if [ "${ckmp}" != "${mp}" ]; then
	    continue
	fi

	#
	# We found what we were looking for
	#
	found=1

	#
	# Is the block device a metadevice?
	#
	md_dev=`echo "${bdev}" | grep '/dev/md' 2>/dev/null`
	_status=${?}

	#
	# Is the character device a metadevice? (Just in case)
	#
	if [ ${_status} -ne 0 -o -z "${md_dev}" ]; then
	    md_dev=`echo "${rdev}" | grep '/dev/md' 2>/dev/null`
	    _status=${?}
	fi

	#
	# Neither is a metadevice, we are done.
	#
	if [ ${_status} -ne 0 -o -z "${md_dev}" ]; then
	    _status=0
	    break
	fi

	#
	# Found a metadevice
	#
	md_name=`basename ${md_dev}`
	check_all_devs "" ${mp} ${md_name}
	_status=${?}
	if [ ${_status} -ne 0 ]; then
	    break
	fi

	#
	# If this is "/" then we remember the metadevice for later.
	#
	if [ "${mp}" = "/" ]; then
	    mdrootdev=${md_name}
	fi

	#
	# If we aren't doing swap, then we are done.
	#
	if [ "${mp}" != "swap" ]; then
	    _status=0
	    break
	fi
    done

    #
    # If we had a problem, we can return now
    #
    if [ ${_status} -ne 0 ]; then
	return ${_status}
    fi

    #
    # If we didn't find the entry, return OK
    #
    if [ ${found} -eq 0 ]; then
	return 0
    fi

    #
    # If this was root, then return the name of the metadevice for use later.
    #
    if [ ! -z "${mdrootdev}" ]; then
	echo "mdrootdev=\"${mdrootdev}\";"
    fi

    return ${_status}
}

#
# Check to see if any hot spares are in use
#
check_metahs() {
    _ertxt=""

    hsp=`${METAHS} -i 2>/dev/null`
    if [ ${?} -ne 0 ]; then
	${METAHS} -i 2>&1 | grep 'no hotspare pools found' >/dev/null 2>&1
	if [ ${?} -eq 0 ]; then
	    return 0
	fi
	_ertxt=`${METAHS} -i 2>&1`
    elif [ -z "${hsp}" ]; then
	return 0
    else
	trouble=`${METAHS} -i |
	    ${AWK} '$0 !~ /^hsp/ { if ( $2 !~ /\(?Available\)?/ ) print $0 }'`
	if [ ! -z "$trouble" ]; then
	    et="\t\t- hot spare are not available -- run \"metahs\"\n"
	    [ -z "${_ertxt}" ] && _ertxt="${et}" || _ertxt="${_ertxt}\n${et}"
	fi
    fi

    if [ ! -z "${_ertxt}" ]; then
	echo "${_ertxt}"
	return 1
    else
	return 0
    fi
}

#
# Check to see if any devices are in a not Okay state.
#
check_not_okay() {
    if [ ${#} -lt 1 ]; then
	echo "${ProgName}: check_not_okay() requires 1 argument..."
	exit 1
    fi
    force=${1}

    _ertxt=""

    trouble=`${METADB} | tail +2 | ${AWK} '{ if ( $1 != "a" ) print $0 }'`
    if [ ! -z "$trouble" ]; then
	et="\t\t- database replicas are not active -- run \"metadb\"\n"
	[ -z "${_ertxt}" ] && _ertxt="${et}" || _ertxt="${_ertxt}\n${et}"
    fi

    trouble=`${METASTAT} | ${AWK} '/State:/ { if ( $2 != "Okay" ) print $0 }'`
    if [ ! -z "$trouble" ]; then
	if [ ${force} -ne 0 ]; then
	    trouble=`${METASTAT} |
		${AWK} '/State:/ { \
			if ($2 != "Okay" && $2 !~ /Detach(ed|ing)/ ) print $0 \
		    }'`
	fi
	if [ ! -z "${trouble}" ]; then
	    et="\t\t- metadevices are not okay -- run \"metastat\"\n"
	    [ -z "${_ertxt}" ] && _ertxt="${et}" || _ertxt="${_ertxt}\n${et}"
	fi
    fi

    if [ ! -z "${_ertxt}" ]; then
	echo "${_ertxt}"
	return 1
    else
	return 0
    fi
}

#
# Get the partition size in blocks
#
partition_size() {
    if [ ${#} -lt 1 ]; then
	echo "${ProgName}: partition_size() requires 1 argument..."
	return 1
    fi
    p_part=`basename ${1}`
    p_part_num=`expr ${p_part} : 'c[0-9]*.*d[0-9]*s\([0-9]*\)'`
    p_disk=/dev/rdsk/${p_part}

    VTOC_TMP=/tmp/vtoc.$$
    prtvtoc -h ${p_disk} >${VTOC_TMP} 2>&1
    if [ ${?} -ne 0 ]; then
	${CAT} ${VTOC_TMP}
	${RM} -f ${VTOC_TMP}
	return 1
    fi

    ${AWK} '$1 == '${p_part_num}' {print $5}' <${VTOC_TMP}

    ${RM} -f ${VTOC_TMP}
    return 0
}

#
# Get component size
#
comp_size() {
    if [ ${#} -lt 1 ]; then
	echo "${ProgName}: comp_size() requires 1 argument..."
	return 1
    fi
    _rval=0
    case "${1}" in

	d*)		# Metadevice
	    compsize=`${METASTAT} ${1} | \
		grep -i 'size:' | \
		${AWK} '{print $2}'`
	    _rval=${?}
	    ;;

	c*)		# Physical device cxtx[dx]sx
	    compsize=`partition_size ${1}`
	    _rval=${?}
	    ;;

	*)
	    compsize="Unknown component type \"${1}\""
	    _rval=1
	    ;;

    esac
    echo ${compsize}
    return ${_rval}
}

#
# Make sure a FS is a one way mirror, a logging metadevice device, or a single
# stripe/concat.
#
is_simple() {
    if [ ${#} -lt 3 ]; then
	echo "${ProgName}: is_simple() requires 3 arguments..."
	return 1
    fi
    mdtabfile=${1:-"${METASTAT_P_OUT}"}
    filesys="${2}"
    look_for="${3}"
    ${CAT} ${mdtabfile} | ${SED} -e '/^hsp/d' -e '/mddb/d' | fix_lines | \
    while read aline; do
	set -- ${aline}
	md_name=${1}; shift
	if [ ${md_name} != "${look_for}" ]; then
	    continue
	fi
	c=""
	md_type=${1}; shift
	case ${md_type} in
	    -m)	# Mirror metadevice
		nc=0
		while [ ! -z "${1}" ]; do
		    case ${1} in
			[cd]*)
			    [ -z "${c}" ] && c="${1}" || c="${c} ${1}"
			    nc=`expr $nc + 1`
			    ;;

		    esac
		    shift
		done

		#
		# Multi-way mirrors are only a problem on "/", since it is not
		# possible to determine the boot device accurately every time.
		# For this case, the user must detach the non-boot side of the
		# mirror by hand.
		#
		if [ ${nc} -gt 1 -a "${filesys}" = "/" ]; then
		    return 1
		fi
		;;

	    -r)	# Raid metadevice
		return 1
		;;

	    -t)	# Trans/Logging metadevice
		if [ ! -z "${filesys}" ]; then
		    if [ "${filesys}" = "/" ]; then
			return 1
		    fi
		fi
		while [ ! -z "${1}" ]; do
		    case "${1}" in
			[cd]*)
			    [ -z "${c}" ] && c="${1}" || c="${c} ${1}"
			    ;;

		    esac
		    shift
		done
		;;

	    [0-9]*)	# Stripe or Concat metadevice
		rows=${md_type}
		cols=${1}; shift
		if [ ${rows} -gt 1 -o ${cols} -gt 1 ]; then
		    return 1
		fi
		while [ ! -z "${1}" ]; do
		    case "${1}" in
			[cd]*)
			    [ -z "${c}" ] && c="${1}" || c="${c} ${1}"
			    ;;

		    esac
		    shift
		done
		;;

	    c*)		# Physical device cxtx[dx]sx
		return 0
		;;

	    *)	echo "Unknown metadevice type \"${md_type}\""
		return 1
		;;

	esac

	if [ ! -z "${c}" ]; then
	    echo ${c}
	fi
	return 0
    done

    if [ ${?} -ne 0 ]; then
	return 1
    else
	return 0
    fi
}

#
# Tear the md.tab file up for use at different stages of the game
#
make_scripts() {
    ${CAT} ${METASTAT_P_OUT} | fix_lines | \
    while read aline; do
	set -- ${aline}
	md_name=${1}; shift
	case ${md_name} in
	    hsp*)
		echo ${aline}					>>${MDTAB}
		continue
		;;

	esac
	md_type=${1}; shift
	case ${md_type} in
	    -m)	# Mirror metadevice
		min=""
		mind=""
		for i in ${*}; do
		    case ${i} in
			[cd]*)
			    cs=`comp_size ${i}`
			    if [ -z "${min}" ]; then
				min=${cs}
				mind=${i}
			    elif [ ${cs} -lt ${min} ]; then
				min=${cs}
				mind=${i}
			    fi
			    ;;

		    esac
		done

		#
		# Put out a line for the smallest component of the mirror.
		#
		echo "${md_name} -m ${mind} \c"			>>${MDTAB}

		#
		# Collect all the other components, excluding the smallest
		# component above.
		#
		toa=""
		while [ ! -z "${1}" ]; do
		    case "${1}" in
			[cd]*)
			    if [ "${1}" = "${mind}" ]; then
				shift
				continue
			    else
				[ -z "${toa}" ] &&
				    toa="${1}" || toa="${toa} ${1}"
			    fi
			    ;;

			*)
			    echo "${1} \c"			>>${MDTAB}
			    ;;

		    esac
		    shift
		done

		#
		# Complete the line for the smallest component
		#
		echo 						>>${MDTAB}

		#
		# If we need to detach mirror components, the following loop
		# could be used, which will add sub-mirror detaches to the
		# DETA_SCRIPT which will be invoked in the first pass.
		#
		# for i in ${toa}; do
		#     echo "\${METADETACH} -f ${md_name} ${i}"	>>${DETA_SCRIPT}
		# done

		#
		# Add the script lines to attach all sub-mirrors
		#
		if [ ! -z "${toa}" ]; then
		    echo "doattach ${md_name}\c"		>>${ATTA_SCRIPT}
		fi

		atc=0
		for i in ${toa}; do
		    echo " ${i}\c"				>>${ATTA_SCRIPT}
		    atc=`expr ${atc} + 1`
		done

		if [ ! -z "${toa}" ]; then
		    if [ ${atc} -gt 1 ]; then
			echo " &"				>>${ATTA_SCRIPT}
		    else
			echo " "				>>${ATTA_SCRIPT}
		    fi
		fi
		;;

	    -r)	# Raid metadevice
		echo ${aline}					>>${MDTAB}
		;;

	    -t)	# Trans/Logging metadevice
		mdm=${1}; shift
		mdl=""
		while [ ! -z "${1}" ]; do
		    case "${1}" in
			[cd]*)
			    [ -z "${mdl}" ] && mdl="${1}"
			    ;;

		    esac
		    shift
		done

		echo ${aline}					>>${MDTAB}

		if [ ! -z "${mdl}" ]; then
		    echo "\${METADETACH} -f ${md_name}"		>>${DETA_SCRIPT}
		fi
		;;

	    [0-9]*)	# Stripe or Concat metadevice
		echo ${aline}					>>${MDTAB}
		;;

	    *)	# Unknown metadevice
		echo "Unknown metadevice \"${md_name}\", type=\"${md_type}\""
		return 1
		;;

	esac
    done
    if [ ${?} -ne 0 ]; then
	return 1
    else
	return 0
    fi
}

#
# Handle the replica issues
#
process_dbs() {
    ${METADB} >/dev/null 2>&1
    _status=${?}
    if [ ${_status} -ne 0 ]; then
	echo "Unable to get replica information -- run \"${METADB}\""
	return 1
    fi
    ${METADB} | ${SED} -e '1d' | ${AWK} '{print $NF, $(NF - 1)}' | \
	${SED} -e 's/.*\///' | sort | ${AWK} '\
	BEGIN { savd = ""; savs = 0 } \
	{ \
	    curd = $1; \
	    curs = $2; \
	    if ( savd == "" ) { \
		savd = curd; \
		savs = curs; \
		cnt = 1; \
		next; \
	    } \
	    if ( savd == curd && savs == curs ) { \
		cnt++; \
		next; \
	    }
	    idx = cnt " " savs; \
	    if ( idx in mddb ) { \
		mddb[idx] = mddb[idx] " " savd; \
	    } else { \
		mddb[idx] = savd; \
	    } \
	    savd = curd; \
	    savs = curs; \
	    cnt = 1; \
	} \
	END { \
		idx = cnt " " savs; \
		if ( idx in mddb ) { \
		    mddb[idx] = mddb[idx] " " savd; \
		} else { \
		    mddb[idx] = savd; \
		} \
		cnt = 0; \
		printf "${METADB} -f -d " >>"'${DB_DEL_SCRIPT}'"; \
		first = 0; \
		for (i in mddb) { \
		    nsa = split(i, sa); \
		    ct = sa[1]; \
		    sz = sa[2]; \
		    printf "mddb%03d -l %d -c %d %s\n", cnt, sz, ct, mddb[i]; \
		    if ( first == 0 ) { \
			first = 1; \
		    } else { \
			printf " " >>"'${DB_DEL_SCRIPT}'"; \
		    } \
		    printf "%s", mddb[i] >>"'${DB_DEL_SCRIPT}'"; \
		    printf "${METADB} -f -a " >>"'${DB_ADD_SCRIPT}'"; \
		    printf "${METADBSZFLAG} %d -c %d %s\n", sz, ct, mddb[i] \
			>>"'${DB_ADD_SCRIPT}'"; \
		    cnt++; \
		} \
		printf "\n" >>"'${DB_DEL_SCRIPT}'"; \
	} \
	'							>>${MDTAB}
    return 0
}

#
# Get nmd from /kernel/drv/md.conf
#
get_md_conf_info() {
	if [ ! -f ${MDCONF} ]; then
	    return 0
	fi
	cline=`grep nmd ${MDCONF} | ${SED} -e 's/;//'`
	val=""
	for i in ${cline}; do
	    j=`echo ${i} | ${SED} -e 's/=/ /'`
	    set -- ${j}
	    case "${1}" in
		nmd)
		    if [ ${2} -gt 128 ]; then
			[ -z "${val}" ] &&
			    val="nmd=${2}" ||
			    val="${val}; nmd=${2}"
		    fi
		    ;;

		md_nsets)
		    if [ ${2} -gt 4 ]; then
			[ -z "${val}" ] &&
			    val="md_nsets=${2}" ||
			    val="${val}; md_nsets=${2}"
		    fi
		    ;;

	    esac
	done
	if [ ! -z "${val}" ]; then
		echo "${val}"
	fi
	return 0
}

#
# Fix up the version strings for comparison
#
fixver() {
    if [ ${#} -lt 1 ]; then
	echo "${ProgName}: fixver() requires 1 argument..."
	exit 1
    fi
    vers=`echo "${1}" | ${SED} -e 's/,.*$//'`
    case "${vers}" in
	2.0patch*)		# Has to be here to match before the 2.0* case
	    val=1
	    ;;

	2.0*)
	    val=0
	    ;;

	2.0.1*)
	    val=2
	    ;;

	3.0*)
	    val=3
	    ;;

	4.0*)
	    val=4
	    ;;

	4.1*)
	    val=5
	    ;;

	*)
	    echo "Unrecognized version \"${1}\""
	    return 1
	    ;;

    esac
    echo "${val}"
    return 0
}

#
# Check the versions of the packages, return an assignment of r_cv and a status
#
check_pkg_versions() {
    latest_pkg=`pkginfo ${MDPKGNAME}\* 2>/dev/null |
	${AWK} '{print $2}' |
	sort -r |
	head -1`

    if [ -z "${latest_pkg}" ]; then
	echo "Unable to locate any instances of ${MDPKGNAME}"
	return 1
    fi

    r_cv=`pkgparam ${latest_pkg} VERSION`
    if [ -z "${r_cv}" ]; then
	echo "Unable to determine the current ${MDPKGNAME} version."
	return 1
    fi

    r_nv=`pkgparam -d "${1}" ${MDPKGNAME} VERSION`
    if [ -z "${r_nv}" ]; then
	echo "Unable to determine the current ${MDPKGNAME} version."
	return 1
    fi


    cv=`fixver ${r_cv}`
    if [ ${?} -ne 0 ]; then
	echo "${cv}"			# return error string to caller
	return 1
    fi

    nv=`fixver ${r_nv}`
    if [ ${?} -ne 0 ]; then
	echo "${nv}"			# return error string to caller
	return 1
    fi

    if [ "${nv}" -eq "${cv}" ]; then
	echo "${r_nv}"			# return raw new version to caller
	return 2
    fi

    if [ ${revert} -eq 0 -a "${nv}" -lt "${cv}" ]; then
	echo "Reverting to \"${r_nv}\" is not permitted."
	return 1
    fi

    echo "${r_nv}"			# return raw new version to caller
    return 0
}

#
# Fix up the vfstab
#
fix_vfstab() {
    bd="/dev/dsk/"
    cd="/dev/rdsk/"
    ${CAT} /dev/null						>${nvfstab}
    while read bdev rdev mp fsty fscp am mo
    do
	# Handle comments and blank lines
	case "${bdev}" in
	    '#'* | '')
		echo "${bdev} ${rdev} ${mp} ${fsty} ${fscp} ${am} ${mo}"
		continue
		;;

	esac

	#
	# See if we are dealing with a metadevice
	#
	echo "${bdev}" | grep '/dev/md' >/dev/null 2>&1
	_status=${?}
	if [ ${_status} -ne 0 ]; then
	    echo "${rdev}" | grep '/dev/md' >/dev/null 2>&1
	    _status=${?}
	fi

	#
	# We are only interested in /, /opt, /usr, /var, and swap
	#
	if [ "${mp}" != "/" -a \
	     "${mp}" != "/export" -a \
	     "${mp}" != "/export/share" -a \
	     "${mp}" != "/opt" -a \
	     "${mp}" != "/usr" -a \
	     "${mp}" != "/var" -a \
	     "${fsty}" != "swap" ]; then
	    #
	    # If the FS is not one we are interested in, and it does not use
	    # a metadevice, just let it through.
	    #
	    if [ ${_status} -ne 0 ]; then
		echo "${bdev} ${rdev} ${mp} ${fsty} ${fscp} ${am} ${mo}"
	    fi
	    continue
	else
	    #
	    # Important FS, but no metadevice
	    #
	    if [ ${_status} -ne 0 ]; then
		echo "${bdev} ${rdev} ${mp} ${fsty} ${fscp} ${am} ${mo}"
		continue
	    fi
	fi

	#
	# We have a FS that is important to us, and it uses a simple metadevice,
	# so we convert the metadevice to a device.
	#
	md_name=`basename ${bdev}`
	subcomp=`is_simple "${MDTAB}" ${mp} ${md_name}`
	if [ ${?} -eq 0 ]; then
	    set -- ${subcomp}
	    case "${1}" in
		d*)		# Metadevice
		    comp=${1}
		    _status=`expr "${comp}" : '^d'`
		    while [ ${_status} -ne 0 ]; do
			comp=`is_simple "${MDTAB}" ${mp} ${comp}`
			_status=${?}
			if [ ${_status} -ne 0 ]; then
			    echo "Component \"${comp}\" was not simple."
			    return 1
			fi
			_status=`expr "${comp}" : '^d'`
		    done
		    if [ "${fsty}" != "swap" ]; then
			echo "${bd}${comp} ${cd}${comp} ${mp} \c"
			echo "${fsty} ${fscp} ${am} ${mo}"
		    else
			echo "${bd}${comp} - - \c"
			echo "${fsty} ${fscp} ${am} ${mo}"
		    fi
		    ;;

		c*)		# Physical device cxtx[dx]sx (pass thru)
		    if [ "${fsty}" != "swap" ]; then
			    echo "${bd}${1} ${cd}${1} ${mp} \c"
			    echo "${fsty} ${fscp} ${am} ${mo}"
		    else
			    echo "${bd}${1} - - \c"
			    echo "${fsty} ${fscp} ${am} ${mo}"
		    fi
		    ;;

	    esac
	else
	    echo "Component \"${subcomp}\" was not simple."
	    return 1
	fi
    done <${vfstab}						>>${nvfstab}
    return ${?}
}

#
# Create the script that will be installed in ${RCS_SCRIPT}
#
rcs_script() {
    #
    # Begin the generated script [no sh sub]
    #
    ${CAT} <<'EOF'						>${RCS_SCRIPT}
#!/bin/sh
#
#ident "@(#)S94SUNWmd.cvt   1.18     95/07/13 SMI"
#
# Copyright (c) 1992, 1993, 1994, 1995 by Sun Microsystems, Inc.
#
# **** WARNING: This script is machine generated! ****
#
# Script to convert from one version of DiskSuite to another.
#

EOF

    #
    # Check to see if debugging is enabled from the building script.
    #
    echo "#\n# Debugging state (set by generator script)\n#"	>>${RCS_SCRIPT}
    if [ ${debug} -gt 0 ]; then
	echo "set -x\ndebug=1\n"				>>${RCS_SCRIPT}
    else
	echo "debug=0\n"					>>${RCS_SCRIPT}
    fi

    #
    # Add the functions to the generated script [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# Spawn a shell
#
doshell() {
	echo "\n*** Starting a shell.\n"
	echo "Hit ^D to exit shell"
	/bin/sh
	_status=${?}
	if [ ${#} -eq 0 ]; then
		echo "\n*** Resuming script execution.\n"
	fi
	return ${_status}
}

#
# Update the state file, possibly creating it.
#
# The first argument is the current 'step' in the process, and is required.
#
# In the case only the required argument is passed, the state file is updated
# and the system is rebooted.
#
# If the user passes a second argument, and this argument has a 1 value, then
# a reboot will also occur, if the second argument is passed and has a 0
# value, then the script will exec a copy of itself allowing the normal state
# transition to occur without the reboot.
#
update_state() {
	if [ ${#} -lt 1 ]; then
		echo "${ProgName}: update_state() requires 1 argument..."
		doshell
	fi
	step=${1}
	doreboot=${2:-0}
	step=`expr ${step} + 1`
	echo "${step} ${debug} ${testing}"			>${STATE_FILE}
	if [ ${debug} -ne 0 ]; then
		doshell
	fi

	#
	# If we are testing, then we need to stop just before going to state
	# 2, we need to add the packages from the test script and then
	# force a reboot from the test script.
	#
	if [ ${testing} -eq 1 -a ${step} -eq 2 ]; then
		quit
	fi

	if [ ${#} -eq 2 -a ${doreboot} -eq 0 ]; then
EOF

    #
    # Complete update_state() [sh sub]
    #
    ${CAT} <<EOF						>>${RCS_SCRIPT}
		#
		# Find the script, and exec a copy instead of doing the reboot
		#
		if [ -f "${RCS_DIR}/${SCRIPT_NAME}" ]; then
			#
			# Found a copy of the script in ${RCS_DIR}
			#
			echo "*** No reboot required.\\n"
			exec ${RCS_DIR}/${SCRIPT_NAME}
		elif [ -f "\${FullProgName}" ]; then
			#
			# Since we did not find a copy in ${RCS_DIR}, we
			# execute the path that started us, should not happen.
			#
			echo "*** No reboot required.\\n"
			exec \${FullProgName}
		fi
	else
		echo "*** rebooting.\\n"
		trap 0 1 2 3 15
		reboot
	fi
}

EOF

    #
    # Add final_state() function [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# Cleanup the script and state file and exit
#
final_state() {
	if [ ${#} -lt 1 ]; then
		echo "${ProgName}: final_state() requires 1 argument..."
		doshell
	fi

EOF

    #
    # See if we need to issue a notice to the user
    #
    if [ ! -z "${mdrootdev}" ]; then
	#
	# Add an informational message to function. [sh sub]
	#
	${CAT} <<EOF						>>${RCS_SCRIPT}
	if [ \${1} -eq 0 ]; then
		echo "\\n*** Remember the metattach's for \\"/\\":\\n"
		echo "\\t${mdrootdev}\\n"
		echo "*** Cleaning up\\n"
	fi
EOF
    fi

    #
    # Complete final_state() [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
	${RM} -f /etc/rc2.d/${ProgName}
	${RM} -f ${STATE_FILE}
	[ ${1} -eq 0 ] && quit
}

#
# Wait for a metadevice to finish a resync
#
resyncwait() {
	if [ ${#} -lt 2 ]; then
		echo "${ProgName}: resyncwait() requires 2 arguments..."
		doshell
	fi

	echo "*** Waiting for ${1}(${2}) to complete the resync process.\n"

	_status=0
	while [ ${_status} -eq 0 ]; do
		${METASTAT} ${1} | grep -i resync >/dev/null 2>&1
		_status=${?}
		if [ ${_status} -eq 0 ]; then
			mso=`${METASTAT} ${1} 2>&1 | \
				grep -i resync | \
				grep -v -i state`
			if [ ! -z "${mso}" ]; then
				echo "*** ${1}(${2}): ${mso}.\n"
				sleep 60
			fi
		fi
	done
	echo "*** ${1}(${2}): resync complete.\n"
}

#
# Attach a sub-mirror to a mirror, waiting for the resync to complete before
# trying to attach another, if needed.
#
doattach() {
	if [ ${#} -lt 1 ]; then
		echo "${ProgName}: doattach() requires 1 argument..."
		doshell
	fi

	mirror=${1}; shift
	while [ ! -z "${1}" ]; do
		submirror="${1}"
		echo "*** ${METATTACH} ${mirror} ${submirror}\n"
		${METATTACH} ${mirror} ${submirror}
		shift

		#
		# If this was the last component, we do not need to wait.
		#
		if [ ${#} -eq 0 ]; then
			return 0
		fi

		#
		# We need to wait for the resync to complete (n-way) where n > 2
		#
		resyncwait ${mirror} ${submirror}
	done
	return 0
}

#
# Save the original md.tab file
#
orig_md_tab() {
	#
	# Make sure we have a place to put the md.tab file.
	#
	if [ ! -d ${MDETCDIR} ]; then
		mkdir -p ${MDETCDIR}
	elif [ -f ${MDETCDIR}/md.tab -a ! -f ${MDETCDIR}/md.tab.orig ]; then
		#
		# Save existing md.tab
		#
		echo "*** Original md.tab saved in md.tab.orig.\n"
		cp ${MDETCDIR}/md.tab ${MDETCDIR}/md.tab.orig
	fi

	echo "*** Restoring the original md.tab file.\n"

	#
	# Restore the original md.tab file. [no sh sub]
	#
	${CAT} <<-'EOF' >${MDETCDIR}/md.tab
EOF

    #
    # Add the contents of the orignal md.tab file, if it exists and has data.
    #
    if [ -s "${MDETCDIR}/md.tab" ]; then
	${SED} -e 's/^/	/' ${MDETCDIR}/md.tab			>>${RCS_SCRIPT}
    fi
    echo "\tEOF\n}\n"						>>${RCS_SCRIPT}

    #
    # Add a function to put the new md.tab file in place [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# Put the created version of md.tab in place.
#
new_md_tab() {
	#
	# Make sure we have a place to put the md.tab file.
	#
	if [ ! -d ${MDETCDIR} ]; then
		mkdir -p ${MDETCDIR}
	elif [ -f ${MDETCDIR}/md.tab -a ! -f ${MDETCDIR}/md.tab.orig ]; then
		#
		# Save existing md.tab
		#
		echo "*** Original md.tab saved in md.tab.orig.\n"
		cp ${MDETCDIR}/md.tab ${MDETCDIR}/md.tab.orig
	fi

	echo "*** Replacing the md.tab file with the generated md.tab.\n"

	#
	# Create the md.tab file we need to perform the conversion. [no sh sub]
	#
	${CAT} <<-'EOF' >${MDETCDIR}/md.tab
EOF

    #
    # Add the contents of the md.tab file
    #
    ${SED} -e 's/^/	/' ${MDTAB}				>>${RCS_SCRIPT}
    echo "\tEOF\n}\n"						>>${RCS_SCRIPT}

    #
    # Add a function to put the original /etc/system back [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# Put the original /etc/system file back
#
orig_system() {
	echo "*** Restoring /etc/system.\n"

	#
	# Restore the original /etc/system file. [no sh sub]
	#
	${CAT} <<-'EOF' >/etc/system
EOF

    #
    # Add the contents of the /etc/system file
    #
    ${SED} -e 's/^/	/' /etc/system				>>${RCS_SCRIPT}
    echo "\tEOF\n}\n"						>>${RCS_SCRIPT}

    #
    # Add a function to create a temporary admin file. [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# Create a temporary admin file in ${ADMIN}
#
admin_file() {
	echo "*** Creating temporary packaging admin file in ${ADMIN}.\n"
	#
	# Create the temporary admin file [no sh sub]
	#
	${CAT} <<-'EOF' >${ADMIN}
	mail=
	instance=overwrite
	partial=nocheck
	runlevel=nocheck
	idepend=nocheck
	rdepend=nocheck
	space=nocheck
	setuid=nocheck
	conflict=nocheck
	action=nocheck
	basedir=default
EOF

    #
    # Finish off the admin file creation
    #
    echo "\tEOF\n}\n"						>>${RCS_SCRIPT}

    #
    # Add a function to put a temporary vfstab in place. [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# Replace the vfstab with the version that has not metadevices
#
temp_vfstab() {
EOF

    #
    # Add another piece of temp_vfstab function. [sh sub]
    #
    ${CAT} <<EOF						>>${RCS_SCRIPT}
	echo "\\n*** Replacing ${vfstab} with a non-metadevice version.\\n"
EOF

    #
    # Add another piece of temp_vfstab function. [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}

	#
	# Replace the vfstab [no sh sub]
	#
	${CAT} <<-'EOF' >/etc/vfstab
EOF

    #
    # Add the contents of the ${nvfstab}
    #
    ${SED} -e 's/^/	/' ${nvfstab}				>>${RCS_SCRIPT}
    echo "\tEOF\n}\n"						>>${RCS_SCRIPT}

    #
    # Add function to put back the original vfstab. [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# Restore the original contents of the vfstab
#
orig_vfstab() {
EOF

    #
    # Add another small piece of the orig_vfstab function. [sh sub]
    #
    ${CAT} <<EOF						>>${RCS_SCRIPT}
	echo "\\n*** Restoring the original ${vfstab}.\\n"
EOF

    #
    # Add more of function to put back the original vfstab [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}

	#
	# Replace the vfstab [no sh sub]
	#
	${CAT} <<-'EOF' >/etc/vfstab
EOF

    #
    # Add the contents of the vfstab
    #
    ${SED} -e 's/^/	/' ${vfstab}				>>${RCS_SCRIPT}
    echo "\tEOF\n}\n"						>>${RCS_SCRIPT}

    #
    # Add a function to fix the version retrieved from the pkg. [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# Fix up the version strings for comparison
#
fixver() {
	if [ ${#} -lt 1 ]; then
		echo "fixver() requires 1 argument..."
		return 1
	fi
	pkg=${1}
	[ ${#} -gt 1 ] && ploc="-d ${2}" || ploc=""

	#
	# Find the latest version of the package to get the version.
	#
	latest_pkg=`pkginfo ${ploc} ${pkg}\* 2>/dev/null |
	    ${AWK} '{print $2}' | sort -r | head -1`

	if [ -z "${latest_pkg}" ]; then
	    echo "Unable to locate any instances of ${pkg}"
	    return 1
	fi

	r_cv=`pkgparam ${ploc} ${pkg} VERSION`
	if [ -z "${r_cv}" ]; then
		echo "Unable to determine the ${pkg} version."
		return 1
	fi

	vers=`echo "${r_cv}" | sed -e 's/,.*$//'`
	case "${vers}" in
	    2.0patch*)		# Has to be here to match before the 2.0* case
		val=1
		;;

	    2.0*)
		val=0
		;;

	    2.0.1*)
		val=2
		;;

	    3.0*)
		val=3
		;;

	    4.0*)
		val=4
		;;

	    4.1*)
		val=5
		;;

	    *)
		echo "Unrecognized version \"${1}\""
		return 1
		;;

	esac
	echo "${val}"
	return 0
}

EOF

    #
    # Add the contents of the create replicas script
    #
    if [ -s ${DB_ADD_SCRIPT} ]; then
	echo "#\n# Create the replicas\n#"			>>${RCS_SCRIPT}
	echo "create_replicas() {"				>>${RCS_SCRIPT}

    #
    # Add a function to fix the version retrieved from the pkg. [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
	cv=`fixver ${MDPKGNAME}`
	if [ ${?} -ne 0 ]; then
	    echo "${cv}"
	    quit 1
	fi

	if [ ${cv} -ge 4 ]; then
		METADBSZFLAG='-l'
	else
		METADBSZFLAG='-s'
	fi
	
EOF
	echo "\techo \"\\\\n*** Create the replicas.\\\\n\""	>>${RCS_SCRIPT}
	${SED} -e 's/^/	/' <${DB_ADD_SCRIPT}			>>${RCS_SCRIPT}
	echo "}\n"						>>${RCS_SCRIPT}
    fi

    #
    # Add the contents of the delete database script file
    #
    if [ -s ${DB_DEL_SCRIPT} ]; then
	echo "#\n# Remove the existing replicas\n#"		>>${RCS_SCRIPT}
	echo "remove_replicas() {"				>>${RCS_SCRIPT}
	echo "\techo \"*** Removing all database replicas.\\\\n\"" \
								>>${RCS_SCRIPT}
	${SED} -e 's/^/	/' ${DB_DEL_SCRIPT}			>>${RCS_SCRIPT}
	echo "}\n"						>>${RCS_SCRIPT}
    fi

    #
    # Create all the metadevices
    #
    echo "#\n# Create the metadevices\n#"			>>${RCS_SCRIPT}
    echo "create_metadevices() {"				>>${RCS_SCRIPT}
    echo "\techo \"*** Create the metadevices.\\\\n\""		>>${RCS_SCRIPT}
    echo "\t\${METAINIT} -af\n}\n"				>>${RCS_SCRIPT}

    #
    # If the root device was a metadevice, issue the metaroot command.
    #
    if [ ! -z "${mdrootdev}" ]; then
	echo "#\n# Put the root back on the original metadevice\n#" \
								>>${RCS_SCRIPT}
	echo "do_metaroot() {"					>>${RCS_SCRIPT}
	echo "\techo \"*** Making root a metadevice with metaroot.\\\\n\"" \
								>>${RCS_SCRIPT}
	echo "\t\${METAROOT} ${mdrootdev}\n}\n"			>>${RCS_SCRIPT}

	#
	# If the root device was a metadevice, issue a metaroot command to go
	# back to the underlying device.
	#
	echo "#\n# Restore root to a non-metadevice\n#"		>>${RCS_SCRIPT}
	echo "undo_metaroot() {"				>>${RCS_SCRIPT}
	echo "\techo \"*** Make root a non-metadevice temporarily.\\\\n\"" \
								>>${RCS_SCRIPT}
	#
	# Need to get the underlying device, again.
	#
	subcomp=`is_simple "${MDTAB}" "/" ${mdrootdev}`
	_status=${?}
	if [ ${_status} -eq 0 ]; then
	    simpledev=""
	    case "${subcomp}" in
		d*)			# Metadevice
		    comp=${subcomp}
		    _status=`expr "${comp}" : '^d'`
		    while [ ${_status} -ne 0 ]; do
			comp=`is_simple "${MDTAB}" "/" ${comp}`
			_status=${?}
			if [ ${_status} -ne 0 ]; then
			    echo "Component \"${comp}\" was not simple."
			    return 1
			fi
			_status=`expr "${comp}" : '^d'`
			if [ ${_status} -eq 0 ]; then
			    simpledev=${comp}
			fi
		    done
		    ;;

		c*)
		    simpledev=${subcomp}
		    ;;

	    esac
	else
	    echo "Component \"${mdrootdev}\" was not simple."
	    die 1
	fi
	if [ ! -z "${simpledev}" ]; then
	    echo "\t\${METAROOT} ${simpledev}\n}\n"		>>${RCS_SCRIPT}
	else
	    echo "Unexpected failure in generation of undo_metaroot"
	    die 1
	fi
    fi

    #
    # Add the contents of the attach script
    #
    if [ -s ${ATTA_SCRIPT} ]; then
	echo "#\n# Do all attaches\n#"				>>${RCS_SCRIPT}
	echo "doallattaches() {"				>>${RCS_SCRIPT}
	echo "\techo \"\\\\n*** Attach all the mirror components.\\\\n\"" \
								>>${RCS_SCRIPT}
	${SED} -e 's/^/	/' <${ATTA_SCRIPT}			>>${RCS_SCRIPT}
	echo "}\n"						>>${RCS_SCRIPT}
    fi

    #
    # See if we need to edit the newly installed ${MDCONF} file
    #
    sedexpr=""
    if [ ! -z "${nmd}" ]; then
	se="-e 's/nmd=128/nmd=${nmd}/'"
	[ -z "${sedexpr}" ] && sedexpr="${se}" || sedexpr="${sedexpr} ${se}"
    fi

    if [ ! -z "${md_nsets}" ]; then
	se="-e 's/md_nsets=4/md_nsets=${md_nsets}/'"
	[ -z "${sedexpr}" ] && sedexpr="${se}" || sedexpr="${sedexpr} ${se}"
    fi

    if [ ! -z "${sedexpr}" ]; then
	echo "#\n# Merge any ${MDCONF} changes\n#"		>>${RCS_SCRIPT}
	echo "merge_md_conf() {"				>>${RCS_SCRIPT}
	echo "\techo \"*** Merging md.conf file changes.\\\\n\"">>${RCS_SCRIPT}
	echo "\tcp -p \${MDCONF} \${MDCONF}.orig"		>>${RCS_SCRIPT}
	echo "\t\${SED} ${sedexpr} <\${MDCONF}.orig >\${MDCONF}">>${RCS_SCRIPT}
	echo "}\n"						>>${RCS_SCRIPT}
	mdconfdone=1
    else
	mdconfdone=0
    fi

    #
    # Add function to add the new packages [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# Function to add the packages back.
#
add_packages() {
	#
	# See if there is an expected version.
	#
	ex_vers="${1}"

	#
	# Check the package installation, silently
	#
	pkgok="ok"

	have_pkg=`pkginfo ${MDPKGNAME}\* 2>/dev/null`

	[ -z "${have_pkg}" ] && pkgok=""

	if [ "${pkgok}" = "ok" ]; then
		#
		# Get the highest instance of the package to check.
		#
		latest_pkg=`pkginfo ${MDPKGNAME}\* 2>/dev/null |
		    ${AWK} '{print $2}' |
		    sort -r |
		    head -1`

		#
		# Check the ${MDPKGNAME} package
		#
		pkgchk -n ${latest_pkg} 2>/dev/null
		[ ${?} -ne 0 ] && pkgok=""

		if [ "${pkgok}" = "ok" ]; then
			#
			# If we are interested in checking the version.
			#
			if [ ! -z "${ex_vers}" ]; then
				#
				# Make sure the version is the expected version
				#
				r_cv=`pkgparam ${MDPKGNAME} VERSION`

				[ "${r_cv}" != "${ex_vers}" ] && pkgok=""
			fi
		fi
	fi

	[ "${pkgok}" != "ok" ] &&
	    echo "\n*** Entering interactive mode to add the new packages.\n"

	while [ -z "${pkgok}" ]; do
		echo "Please type the required sequence of commands"
		echo "to add the DiskSuite package(s) to the system."
		echo
		echo "i.e.:"
		echo "# pkgadd -d <PathName> SUNWmd"
		echo "\twhere <PathName> is a path to the location of the"
		echo "\tnew DiskSuite packages, as specified in the '-d'"
		echo "\toption to \"metacvt\" initially."
		echo
		echo "For this conversion to complete, the only required"
		echo "package is: ${MDPKGNAME}\n"
		echo
		echo "After the package(s) has(have) been added.  The"
		echo "packaging commands will print a message similar to the"
		echo "one below:"
		echo
		echo "\t*** IMPORTANT NOTICE ***"
		echo "\t\tThis machine must now be rebooted..."
		echo
		echo "IGNORE this message and exit the shell, the script will"
		echo "validate the required package and initiate the"
		echo "\"reboot\" automatically."
		echo 
		echo "Hit Ctrl-D to exit shell after adding the new packages."
		echo "(may require 2 Control-D's)"
		echo
		echo "# \c"
		while read cmd args; do
			if [ -z "${cmd}" ]; then
				echo "# \c"
				continue
			fi
			cn=`basename ${cmd}`
			case ${cn} in
			    pkg*)
				${CATU} | eval ${cmd} ${args} 2>&1 | ${CATU}
				;;

			    reboot|shutdown)
				echo "\n*** Please exit the shell. ***\n"
				;;

			    *)
				eval ${cmd} ${args}
				;;

			esac
			echo "# \c"
		done
		echo "\n*** Validating package installation.\n"

		have_pkg=`pkginfo ${MDPKGNAME}\* 2>/dev/null`
		if [ -z "${have_pkg}" ]; then
			continue
		fi

		#
		# Get the highest instance of the package to check.
		#
		latest_pkg=`pkginfo ${MDPKGNAME}\* 2>/dev/null |
		    ${AWK} '{print $2}' |
		    sort -r |
		    head -1`

		#
		# Check the ${MDPKGNAME} package
		#
		pkgchk -n ${latest_pkg} 2>/dev/null
		if [ ${?} -ne 0 ]; then
			echo "Package check failed -- \c"
			echo "run \"pkgchk -n ${MDPKGNAME}\""
			continue
		fi

		#
		# If we are interested in checking the version.
		#
		if [ ! -z "${ex_vers}" ]; then
			#
			# Make sure the version is the expected version
			#
			r_cv=`pkgparam ${MDPKGNAME} VERSION`

			if [ "${r_cv}" != "${ex_vers}" ]; then
				echo "Package version mismatch - need \c"
				echo "\"${ex_vers}\" packages"
				continue
			fi
		fi

		pkgok="ok"
	done
}

EOF

    #
    # Function to remove the packages
    #
    echo "#\n# Remove the packages\n#"				>>${RCS_SCRIPT}
    echo "remove_packages() {"					>>${RCS_SCRIPT}
    echo "\tif [ -f \${RMCALOC}/\${MDRMCANM} ]; then"		>>${RCS_SCRIPT}
    echo "\t\techo \"*** Fixing up \${RMCALOC}/\${MDRMCANM}.\\\\n\"" \
								>>${RCS_SCRIPT}
    echo "\t\tcp \${RMCALOC}/\${MDRMCANM} /tmp/\${MDRMCANM}"	>>${RCS_SCRIPT}
    echo "\t\tsed -e '/^exec/d' /tmp/\${MDRMCANM} >\${RMCALOC}/\${MDRMCANM}" \
								>>${RCS_SCRIPT}
    echo "\tfi\n"						>>${RCS_SCRIPT}
    echo "\t#\n\t# Create a temporary admin file\n\t#"		>>${RCS_SCRIPT}
    echo "\tadmin_file\n"					>>${RCS_SCRIPT}
    echo "\techo \"*** Removing the old packages.\\\\n\""	>>${RCS_SCRIPT}
    pkgcmd="pkgrm -n -a \${ADMIN} ${curpkgs} 2>&1"
    echo "\t\${CATU} | ${pkgcmd} | \${CATU}"			>>${RCS_SCRIPT}
    echo "\techo\n}\n"						>>${RCS_SCRIPT}

    #
    # Function to remove the logging metadevice logs, if any.
    #
    if [ -s ${DETA_SCRIPT} ]; then
	echo "#\n# Detach any logging metadevice logs\n#"	>>${RCS_SCRIPT}
	echo "detach_trans_logs() {"				>>${RCS_SCRIPT}
	echo "\techo \"*** Detaching all logging metadevice logs.\\\\n\"" \
								>>${RCS_SCRIPT}
	${SED} -e 's/^/	/' <${DETA_SCRIPT}			>>${RCS_SCRIPT}
	echo "}\n"						>>${RCS_SCRIPT}
    fi

    #
    # Function to install script
    #
    echo "#\n# Function to copy ${SCRIPT_NAME} to ${RCS_DIR}\n#">>${RCS_SCRIPT}
    echo "install_script() {"					>>${RCS_SCRIPT}
    echo "\tif [ -f ${RCS_SCRIPT} ]; then"			>>${RCS_SCRIPT}
    echo "\t\techo \"\\\\n*** cp ${RCS_SCRIPT} ${RCS_DIR}\\\\n\"">>${RCS_SCRIPT}
    echo "\t\tcp ${RCS_SCRIPT} ${RCS_DIR}"			>>${RCS_SCRIPT}
    echo "\t\tchmod 755 ${RCS_DIR}/${SCRIPT_NAME}"		>>${RCS_SCRIPT}
    echo "\telif [ -f \"\${FullProgName}\" ]; then"		>>${RCS_SCRIPT}
    echo "\t\techo \"*** cp \${FullProgName} ${RCS_DIR}/${SCRIPT_NAME}\\\\n\"" \
								>>${RCS_SCRIPT}
    echo "\t\tcp \${FullProgName} ${RCS_DIR}/${SCRIPT_NAME}"	>>${RCS_SCRIPT}
    echo "\t\tchmod 755 ${RCS_DIR}/${SCRIPT_NAME}"		>>${RCS_SCRIPT}
    echo "\tfi\n}\n"						>>${RCS_SCRIPT}

    #
    # Next part of the static part of the script. [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# function to clear traps and exit
#
quit() {
	#
	# Remove trap on exit
	#
	trap 0
	exit ${1:-0}
}

#
# Read the state file.
#
read_state() {
	#
	# If the state file exists and has a non-zero size
	#
	if [ -s "${STATE_FILE}" ]; then
		set -- `${CAT} ${STATE_FILE} 2>/dev/null`
		if [ ${#} -ne 3 ]; then
			echo "\n*** Illegal format detected in ${STATE_FILE}.\c"
			echo " -- ignored\n"
			return 1
		fi

		t=`expr ${1} : '\([0-9][0-9]*\)'`
		if [ -z "${t}" ]; then
			echo "\"step\" must be numeric -- zero used."
		fi
		step=${t:-0}

		t=`expr ${2} : '\([01]\)'`
		if [ -z "${t}" ]; then
			echo "\"debug\" must be 0 or 1 -- ${debug} used."
		fi
		debug=${t:-${debug}}

		t=`expr ${3} : '\([01]\)'`
		if [ -z "${t}" ]; then
			echo "\"testing\" must be 0 or 1 -- ${testing} used."
		fi
		testing=${t:-${testing}}

	else
		step=0
	fi
	return 0
}

EOF

    #
    # If we are tracking the package version, note it.
    #
    if [ ! -z "${r_cv}" ]; then
	#
	# Add the next part of the header.
	#
	echo "#\n# Keep track of the version of packages we expect\n#" \
								>>${RCS_SCRIPT}
	echo "EVERS=\"${r_nv}\"\n"				>>${RCS_SCRIPT}
    fi

    #
    # Store the nodename to make sure it doesn't get carried from one host to
    # another.
    #
    echo "#\n# Keep track of where the script was run.\n#"	>>${RCS_SCRIPT}
    echo "NODENAME=\"`uname -n`\"\n"				>>${RCS_SCRIPT}

    #
    # Next part of the header [sh sub]
    #
    ${CAT} <<EOF						>>${RCS_SCRIPT}
#
# Imported from the generator script
#

#
# Some heavily used paths.
#
CAT=${CAT}
CATU="${CATU}"
SED=${SED}
RM=${RM}
AWK=${AWK}

#
# Command locations and file names.
#
MDBIN=${MDBIN}
MDCONF=${MDCONF}
MDETCDIR=${MDETCDIR}
MDPKGNAME=${MDPKGNAME}
METADB=${METADB}
METADETACH=${METADETACH}
METAINIT=${METAINIT}
METAROOT=${METAROOT}
METASTAT=${METASTAT}
METATTACH=${METATTACH}
STATE_FILE=${STATE_FILE}
RMCALOC=${RMCALOC}
MDRMCANM=${MDRMCANM}

EOF

    #
    # Next part of the header [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
#
# Runtime variables
#
ADMIN=/tmp/admin
FullProgName=${0}
ProgName=`basename ${0}`
PATH=${PATH}:${MDBIN}; export PATH

#
# Usage message
#
_USE="[-r|-u|-s <step>] [-E <shell function name list>]
\t-E <sfnl> - specifies a list of shell functions to call (';' seperated)
\t-d        - enable debugging trace
\t-r        - rebuild mode
\t-s <step> - start at step <step>"

#
# main (Generated)
#

#
# Handle traps
#
trap 'echo "*** Error/Interrupt caught"; doshell 1; quit' 0 1 2 3 15

#
# Force the locale to be C
#
LC_ALL=C; export LC_ALL

#
# Default options
#
entry=""
rebuild=0
startstep=""
restore=0
step=""
testing=0

#
# Make sure that we are being run on the machine that ran metacvt
#
if [ "${NODENAME}" != "`uname -n`" ]; then
	echo "Host name mismatch - expected \"${NODENAME}\", got \"`uname -n`\""
	quit 1
fi

#
# Try to read in the state file
#
read_state

#
# If the state file indicated that debug trace was on, re-enable it.
#
if [ ${debug} -ne 0 ]; then
	set -x
fi

#
# Process arguments
#
while [ ! -z "${1}" ]; do
	case "${1}" in
	    -E)
		entry="${2}"
		shift; shift
		;;

	    -R)
		restore=1
		shift
		;;

	    -d)
		debug=1
		set -x
		shift
		;;

	    -r)
		rebuild=1
		shift
		;;

	    -t)
		testing=1
		shift
		;;

	    -s)
		t=`expr ${2} : '\([0-9][0-9]*\)'`
		if [ ! -z "${t}" ]; then
			step="${t}"
			startstep=${step}
		else
			echo "Step value must be numeric - exiting."
			quit 1
		fi
		shift; shift
		;;

	    start|stop)
		shift
		;;

	    *)
		echo "Usage: ${ProgName} ${_USE}"
		quit 1
		;;

	esac
done

#
# See if we have a semicolon separated list of functions to execute.
#
if [ ! -z "${entry}" ]; then
	OIFS=${IFS}
	IFS=";"
	set -- ${entry}
	IFS=${OIFS}
	for i in ${*}; do
		if [ -z "${i}" ]; then
			continue
		fi
		echo "*** Executing \"${i}\"."
		eval ${i}
		_status=${?}
		if [ ${_status} -ne 0 ]; then
			echo "\"${i}\" returned ${_status}"
			quit ${_status}
		fi
	done
	quit
fi

#
# If the restore option is specified, then we restore the following and exit.
#	/etc/vfstab
#	/etc/opt/${MDPKGNAME}/md.tab
#	/etc/system
#	replicas
#
if [ ${restore} -eq 1 ]; then
	orig_vfstab
	orig_system
	orig_md_tab
	create_replicas
	quit
fi

#
# If we are run in "rebuild" mode (put the configuration back), then we
# start at step 2, adding the packages back.
#
if [ ${rebuild} -eq 1 ]; then
	#
	# Set the step to 2, since we need to be at the stage of adding the
	# packages.
	#
	step=2
fi

#
# See if the invoker is running this from the console, only important initially
#
if [ ${testing} -eq 0 ]; then
	if [ ${step} -eq 0 -o \( ${step} -eq 2 -a ${rebuild} -eq 1 \) ]; then
		x=`tty`
		x=`basename ${x}`
		if [ "${x}" != "console" ]; then
			echo "This script must be run from the systems console."
			quit 1
		fi
	fi
fi

#
# Determine what to do next.
#
case "${step}" in
	0)
EOF

    #
    # Add the contents of the log detach script
    #
    if [ -s ${DETA_SCRIPT} ]; then
	echo "\t\t#\n\t\t# Detach all the logs from logging metadevices\n\t\t#"\
								>>${RCS_SCRIPT}
	echo "\t\tdetach_trans_logs"				>>${RCS_SCRIPT}
	echo "\t\tdoreboot=1\n"					>>${RCS_SCRIPT}
    else
	echo "\t\t#\n\t\t# No reboot needed if no logging metadevices\n\t\t#" \
								>>${RCS_SCRIPT}
	echo "\t\tdoreboot=0\n"					>>${RCS_SCRIPT}
    fi

    #
    # Add a line to copy this script to the correct location. [sh sub]
    #
    ${CAT} <<EOF						>>${RCS_SCRIPT}
		#
		# Copy ${SCRIPT_NAME} to ${RCS_DIR}
		#
		install_script

EOF

    #
    # Complete case 0 and start case 1 [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
		#
		# Increment the step and store it for next phase
		#
		update_state ${step} ${doreboot}
		;;

	1)
		#
		# Replace the vfstab with the non-metadevice version.
		#
		temp_vfstab

		#
		# Put the new md.tab in place
		#
		new_md_tab

EOF

    #
    # If the root device was a metadevice, call undo_metaroot()
    #
    if [ ! -z "${mdrootdev}" ]; then
	echo "\t\t#\n\t\t# Restore root to a non-metadevice\n\t\t#" \
								>>${RCS_SCRIPT}
	echo "\t\tundo_metaroot\n"				>>${RCS_SCRIPT}
    fi

    #
    # Invoke the remove_replicas function if needed.
    #
    if [ -s ${DB_DEL_SCRIPT} ]; then
	#
	# Remove replicas, if not upgrading. [no sh sub]
	#
	${CAT} <<'EOF'						>>${RCS_SCRIPT}
		#
		# Remove the existing replicas
		#
		remove_replicas

EOF
    fi

    #
    # Handle removal of the packages [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
		#
		# Remove the packages
		#
		remove_packages

EOF

    #
    # Complete case 1 and start case 2 [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
		#
		# Increment the step and store it for next phase
		#
		update_state ${step}
		;;

	2)
		#
		# We only need to validate the package version if we are doing
		# the DiskSuite to DiskSuite conversion.
		#
		if [ ${rebuild} -eq 0 ]; then
			#
			# Add the new packages to the system
			#
			add_packages "${EVERS}"
		else
			#
			# Install the script, since it will not be there
			#
			install_script

			#
			# Add the new packages to the system
			#
			add_packages
		fi

		#
		#
		# Put the new md.tab in place
		#
		new_md_tab

		if [ ${testing} -eq 0 ]; then
			#
			# Make sure that the device space is cleaned up.
			#
			echo "*** Removing metadevice /dev and /devices \c"
			echo "entries. (This may take a while.)\n"
			${RM} -rf /dev/md
			/usr/bin/ls /devices/pseudo 2>/dev/null | \
			    grep 'md@' | xargs -l10 ${RM} -f

			#
			# Make sure a reconfiguration will occur on reboot
			#
			echo "*** Making sure a reconfiguration will occur \c"
			echo "on reboot.\n"
			touch /reconfigure
			doreboot=1
		else
			doreboot=0
		fi

EOF

    #
    # See if we need to edit the newly installed ${MDCONF} file
    #
    if [ ${mdconfdone} -ne 0 ]; then
	#
	# Merge md.conf changes [sh sub]
	#
	${CAT} <<EOF						>>${RCS_SCRIPT}
		#
		# Fix up the ${MDCONF} file
		#
		merge_md_conf
		doreboot=1

EOF
    fi

    #
    # Complete case 2 and start case 3 [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
		#
		# Increment the step and store it for next phase
		#
		update_state ${step} ${doreboot}
		;;

	3)
EOF

    #
    # Add the contents of the create replicas script
    #
    if [ -s ${DB_ADD_SCRIPT} ]; then
	${CAT} <<'EOF'						>>${RCS_SCRIPT}
		#
		# Create the replicas
		#
		create_replicas

		#
		# Create the metadevices
		#
		create_metadevices

EOF
    fi

    #
    # Restore the original /etc/vfstab
    #
    echo "\t\t#\n\t\t# Restore the original ${vfstab}\n\t\t#"	>>${RCS_SCRIPT}
    echo "\t\torig_vfstab\n"					>>${RCS_SCRIPT}

    #
    # If the root device was a metadevice, issue the metaroot command.
    #
    if [ ! -z "${mdrootdev}" ]; then
	echo "\t\t#\n\t\t# Issue the metaroot command.\n\t\t#"	>>${RCS_SCRIPT}
	echo "\t\tdo_metaroot\n"				>>${RCS_SCRIPT}
    fi

    #
    # Complete case 3 and start case 4 [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}
		#
		# Increment the step and store it for next phase
		#
		update_state ${step}
		;;

	4)
EOF

    #
    # Add the contents of the attach script
    #
    if [ -s ${ATTA_SCRIPT} ]; then
	#
	# Do all the attaches [no sh sub]
	#
	${CAT} <<'EOF'						>>${RCS_SCRIPT}
		#
		# Attach sub-mirrors
		#
		doallattaches

EOF
    fi

    #
    # Complete case 4 and the script [no sh sub]
    #
    ${CAT} <<'EOF'						>>${RCS_SCRIPT}

		#
		# Wait for the doattach's to finish
		#
		wait

		#
		# Final state is to clean up the state file and ourselves
		# and exit
		#
		final_state 0
		;;

esac

quit
EOF
    return 0
}

#
# Force the locale to be C
#
LC_ALL=C; export LC_ALL

#
# main (Generator)
#
init

#
# Some heavily used paths.
#
AWK=/usr/bin/nawk
CAT=/usr/bin/cat
CATU="/usr/bin/cat -u"
SED=/usr/bin/sed
RM=/usr/bin/rm

#
# Name of the DiskSuite package
#
MDPKGNAME=SUNWmd

#
# Command locations and file names.
#
ATTA_SCRIPT=/tmp/attach.sh
DB_ADD_SCRIPT=/tmp/adddb.sh
DB_DEL_SCRIPT=/tmp/deldb.sh
DETA_SCRIPT=/tmp/detach.sh
MDBIN=/usr/opt/${MDPKGNAME}/sbin
MDCONF=/kernel/drv/md.conf
MDETCDIR=/etc/opt/${MDPKGNAME}
MDRMCANM=r.preserve
MDTAB=/tmp/md.tab
METADB=${MDBIN}/metadb
METADETACH=${MDBIN}/metadetach
METAHS=${MDBIN}/metahs
METAINIT=${MDBIN}/metainit
METASTAT=${MDBIN}/metastat
METAROOT=${MDBIN}/metaroot
METASTAT_P_OUT="/tmp/mc$$msp.out"
METATTACH=${MDBIN}/metattach
RMCALOC=/var/sadm/pkg/${MDPKGNAME}/install	# knowledge of pkg structure
RCS_DIR=/etc/rc2.d
SCRIPT_NAME=S94${MDPKGNAME}.cvt
RCS_SCRIPT=/tmp/${SCRIPT_NAME}		# if it ends in .sh it is source'ed
STATE_FILE=/etc/metacvt.state
VTOC_TMP="/tmp/mc$$vtoc.out"
nvfstab=/tmp/vfstab.new
vfstab=/etc/vfstab

#
# List of temporary files to remove
#
_FTR='${METASTAT_P_OUT}
    ${VTOC_TMP}
    ${MDTAB}
    ${ATTA_SCRIPT}
    ${DETA_SCRIPT}
    ${DB_DEL_SCRIPT}
    ${DB_ADD_SCRIPT}
    ${nvfstab}
    ${STATE_FILE}
    ${RCS_DIR}/${SCRIPT_NAME}'

#
# Usage message
#
_USE="[-D] -d <pathname of new pkgs> [-f] [-v]
\t-D    - turn debugging on in ${SCRIPT_NAME} (optional)
\t-D -D - turn debugging on in ${ProgName} (optional)
\t-d P  - specify the path to the new packages (required)
\t-f    - allow ${ProgName} to run with detached or detaching logs (optional)
\t-v    - display a copy of ${SCRIPT_NAME} on stdout (optional)"

#
# For now clear tmp files we keep for looking at
#
${RM} -f ${RCS_SCRIPT}

#
# Clean up tmp files
#
rmf

#
# Initialize some globals
#
verbose=0
pkgdir=""
debug=0
error=0
errtxt=""
errcnt=0
revert=0
force=0
testing=0

#
# Process arguments
#
while [ ! -z "${1}" ]; do
    case "${1}" in
	-D)
	    debug=`expr ${debug} + 1`
	    if [ ${debug} -gt 1 ]; then
		set -x
	    fi
	    shift
	    ;;

	-R)
	    revert=1
	    shift
	    ;;

	-d)
	    pkgdir=${2}
	    shift; shift
	    ;;

	-f)
	    force=1
	    shift
	    ;;

	-t)
	    testing=1
	    shift
	    ;;

	-v)
	    verbose=1
	    shift
	    ;;

	*)
	    usage
	    ;;

    esac
done

#
# Check required argument
#
if [ -z "${pkgdir}" ]; then
    die "-d <pathname of new packages> required." 1
fi

#
# Make sure that the package is installed, since we need to be able to tear
# things down using some of the meta* utilities.
#
echo "Checking installed DiskSuite packages..."
have_pkg=`pkginfo ${MDPKGNAME}\* 2>/dev/null`
if [ -z "${have_pkg}" ]; then
    die "No ${MDPKGNAME} found on the system." 1
fi

#
# Get a list of current ${MDPKGNAME} packages installed on the system
#
p=`pkginfo 2>/dev/null | grep ${MDPKGNAME} | ${AWK} '{ print $2 }' | sort`
curpkgs=""
for i in ${p}; do
    [ -z "${curpkgs}" ] && curpkgs="${i}" || curpkgs="${curpkgs} ${i}"
done

#
# Validate the path to the new packages
#
echo "Checking new DiskSuite packages..."
if [ ! -d "${pkgdir}" ]; then
    die "${pkgdir}: No such directory." 1
fi

if [ ! -d "${pkgdir}/${MDPKGNAME}" ]; then
    die "${pkgdir}/${MDPKGNAME}: No such directory." 1
fi

#
# Check versions
#
echo "Checking DiskSuite package versions..."
r_nv=`check_pkg_versions "${pkgdir}"`
case "${?}" in
    1)
	echo "${r_nv}"
	die 1
	;;

    2)
	echo "\n*** Version \"${r_nv}\" is currently installed."
	if [ ${testing} -ne 0 ]; then
	    ans="Y"
	else
	    ans=""
	fi
	while [ -z "${ans}" ]; do
	    echo "Are you sure you want to convert to the same version? \c"
	    read ans
	    ans=`echo $ans | ${SED} -e 's/\(.\).*$/\1/' | tr [a-z] [A-Z]`
	    case "${ans}" in
		Y)
		    break
		    ;;

		N)
		    finit
		    ;;

		*)
		    echo "Please enter Y or N"
		    ans=""
		    ;;

	    esac
	done
	;;

    *)
	;;

esac

#
# Check to see if we need to make changes to the newly install md.conf
#
eval `get_md_conf_info`

#
# Get the metastat -p output and save it for later use
#
${METASTAT} -p >${METASTAT_P_OUT}
if [ ${?} -ne 0 ]; then
    die "metastat failed." 1
fi

#
# Check /, /opt, /usr, /var, and swap for metadevice
#
echo "Checking system file systems..."
for i in / /export /export/share /opt /usr /var swap; do
    eval `check_osfs ${i}` _status=${?}
    if [ ${_status} -ne 0 ]; then
	errcnt=`expr ${errcnt} + 1`
	et="\t${errcnt}) \"${i}\" is mounted on a complex metadevice.\n"
	[ -z "${errtxt}" ] && errtxt="${et}" || errtxt="${errtxt}\n${et}"
	error=1
    fi
done

#
# Check to see if any hot spares need to be cleaned up
#
echo "Checking hot spare pools..."
xet=`check_metahs`
if [ ${?} -ne 0 ]; then
    errcnt=`expr ${errcnt} + 1`
    et="\t${errcnt}) No hot spares can be in use.\n"
    [ -z "${errtxt}" ] && errtxt="${et}" || errtxt="${errtxt}\n${et}"
    errtxt="${errtxt}\n${xet}"
    error=1
fi

#
# See if any error/resync/needs maintenance conditions exist
#
echo "Checking for not \"Okay\" conditions..."
xet=`check_not_okay ${force}`
if [ ${?} -ne 0 ]; then
    errcnt=`expr ${errcnt} + 1`
    et="\t${errcnt}) No metadevices/replicas can be in a not \"Okay\" state.\n"
    [ -z "${errtxt}" ] && errtxt="${et}" || errtxt="${errtxt}\n${et}"
    errtxt="${errtxt}\n${xet}"
    error=1
fi

#
# Let the user know that logging metadevices in the detached state will not
# be automatically attached.
#
if [ ${force} -eq 1 ]; then
    trouble=`${METASTAT} | ${AWK} '/State:/ { \
	if ($2 == "Detached" ) print $0 }'`
    if [ ! -z "${trouble}" ]; then
	warn "Logging metadevices in the \"Detached\" state detected."
	warnc "If the log is not attached at the time \"${ProgName}\" is run,"
	warnc "\"${SCRIPT_NAME}\", the generated script, will not be able to"
	warnc "automatically re-attach the log."
	warnc "To resolve this problem, manually attach the log and re-run"
	warnc "\"${ProgName}\".\n"
    fi
fi

#
# See if any errs have occurred.
#
if [ ${error} -ne 0 ]; then
    echo
    warn "Errors in the configuration have been detected.  The list that"
    warnc "follows details the items that must be corrected before this"
    warnc "script can be run.\n"
    echo "${errtxt}"
    if [ ${force} -eq 0 ]; then
	die 1
    fi
fi

#
# Create an md.tab file for use later, as well as the other scripts
#
echo "Creating md.tab from current configuration..."
make_scripts
if [ ${?} -ne 0 ]; then
    die 1
fi

#
# Handle the replica's
#
echo "Collecting replica information..."
x=`process_dbs`
if [ ${?} -ne 0 ]; then
    if [ -z "${x}" ]; then
	die "${x}" 1
    else
	die 1
    fi
fi

#
# Fix up the vfstab
#
echo "Creating a temporary non-metadevice ${vfstab}..."
fix_vfstab
if [ ${?} -ne 0 ]; then
    die 1
fi

#
# Generate RCS_SCRIPT
#
echo "Creating ${RCS_SCRIPT} to do the work..."
rcs_script
if [ ${?} -ne 0 ]; then
    die 1
fi

if [ ${verbose} -ne 0 ]; then
    note "\n*** The script ${RCS_SCRIPT}, listed below, will be run to perform"
    note "the conversion.\n"
    ${CAT} ${RCS_SCRIPT}
fi

#
# If the user wishes to execute immediately, the -G flag is used.
#
note "\n*** Copy ${RCS_SCRIPT}} to a non-volatile location."
note "    (i.e. - a remote file system or a floppy)\n"
note "*** ${RCS_SCRIPT} contains the current DiskSuite configuration state"
note "and has the built-in ability to reconstruct this configuration."
warn "The ability to rebuild the DiskSuite configuration is based on"
warnc "the DISK DRIVE configuration at the time \"${ProgName}\" is executed,"
warnc "if DISK DRIVES have been REMOVED or MOVED, this script MAY NOT be"
warnc "able to rebuild the DiskSuite configuration.\n"
note "*** Type the following to initiate the conversion process.\n"
note "\t\"sh ${RCS_SCRIPT}\c"
echo "\"\n"

#
# Cleanup and exit 0
#
finit
