#!/sbin/sh -
# $Id: vxadm_syslib.sh,v 1.21.30.7 2002/08/19 01:14:17 misha Exp $
#ident "$Source: /project/unixvm-cvs/src/sol/cmd/vxvm/voladm/vxadm_syslib.sh,v $"

# Copyright (c) 2000 VERITAS Software Corporation.  ALL RIGHTS RESERVED.
# UNPUBLISHED -- RIGHTS RESERVED UNDER THE COPYRIGHT
# LAWS OF THE UNITED STATES.  USE OF A COPYRIGHT NOTICE
# IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
# OR DISCLOSURE.
# 
# THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND
# TRADE SECRETS OF VERITAS SOFTWARE.  USE, DISCLOSURE,
# OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR
# EXPRESS WRITTEN PERMISSION OF VERITAS SOFTWARE.
# 
#               RESTRICTED RIGHTS LEGEND
# USE, DUPLICATION, OR DISCLOSURE BY THE GOVERNMENT IS
# SUBJECT TO RESTRICTIONS AS SET FORTH IN SUBPARAGRAPH
# (C) (1) (ii) OF THE RIGHTS IN TECHNICAL DATA AND
# COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013.
#               VERITAS SOFTWARE
# 1600 PLYMOUTH STREET, MOUNTAIN VIEW, CA 94043


#
# vxadm_syslib.sh -- library of routines that need to be ported
#		     for each platform
#

#
# For the 'add' operation check for any inuse devices. The user will
# decide whether these inuse partitions should be encapsulated.
#

xcmd()
{
	if [ ! -z "$VOL_VERBOSE" ]
	then
		echo "!$VOL_XCMD $@" >&2
	fi
	$VOL_XCMD "$@"
	[ $? = 0 ] || bail
}

inuse_check()
{
	mount_outfile=$tmpfile2

	mount > $mount_outfile

	inuse_list=
	not_inuse_list=

	shift $#	# Reset argument count to zero.
	set -- $dev_list
	while [ $# -gt 0 ]
	do
		device=$1
		daname=$2

# 		egrep -s /dev/dsk/$device $mount_outfile 2>/dev/null
#		egrep -s  "/dev(/|/ap/)dsk/$device" $mount_outfile 2>/dev/null
		egrep -s  "/dev(/|/ap/)(vx/dmp|dsk)/$device" $mount_outfile 2>/dev/null
		if [ $? -eq 0 ]
		then
			append_list inuse_list $device $daname
		else
			append_list not_inuse_list $device $daname
		fi
		shift $dev_num
	done

	if [ -n "$inuse_list" ]
	then
		if [ `list_count $inuse_list` -eq $dev_num ]
		then
			ewritemsg -f $disp_file -M vxvmshm:242 \
"One or more partitions of the following disk device are in use as
  a mounted file system. The disk cannot be initialized, but you can
  encapsulate the existing disk partitions as volumes.
  Output format: [Device_Name]"
		else
			ewritemsg -f $disp_file -M vxvmshm:243 \
"One or more partitions of the following disk devices are in use as
  a mounted file system. The disks cannot be initialized, but you can
  encapsulate the existing disk partitions as volumes.
  Output format: [Device_Name]"
		fi

		voladm_yorn_batch -h \
		-g $dev_num -p $dev_index -d $dev_index \
		-f $disp_file -M vxvmshm:1004 -m vxvmshm:1005 \
		"Encapsulate these devices?" Y \
		"Encapsulate this device?" y \
		inuse_list encap_list ignore_list

		if [ -n "$encap_list" ]
		then
			append_list ckinit_encap $encap_list
		fi
	fi

	# If any not-inuse disks were found, then set dev_list to
	# the not-inuse list and continue. Otherwise if no not-inuse
	# disks were found all other disks have been set-up for
	# encapsulation or have been ignored so return.
	if [ -n "$not_inuse_list" ]
	then
		dev_list="$not_inuse_list"
	fi
}

#
# get_mountdevice dir basevarname dgvarname
#
# Locate dir in the vfstab file and set the following variables as
# appropriate:
#
#	basevarname_bdev	- the block device for the file system
#	basevarname_rdev	- the raw device for the file system
#	basevarname_disk	- the standard form disk (cNtNdN), if the
#				  root file system is on a regular disk
#	basevarname_vol		- the volume containing the file system,
#				  if the file system is on a volume
#
# If the optional third arg is given, then volumes in disk groups other
# than rootdg are allowed, and the disk group name will be stuffed in
# the variable named in $dgvarname.
#
get_mountdevice()
{
	# On Solaris read the /etc/vfstab to get mount information.
	__bdev=
	__cdev=
	__disk=
	__vol=
	__dg=
	exec 9<&0 < $SYSROOT/etc/vfstab
	while read _special _fsckdev _mountp _fstype _fsckpass _automnt _mntopts
	do
		case ${_special} in
		'#'* | '')	#  Ignore comments, empty lines
				continue ;;
		'-')		#  Ignore no-action lines
				continue ;;
		esac

		if [ "${_mountp}" = "$1" ]
		then
			__bdev=$_special
			__cdev=$_fsckdev
			dogi_path_to_slice ${__bdev} slc
			#echo "Slice: $slc"
			dogi_slice_to_device $slc __disk
			#echo "Disk: ${__disk}"
			#__disk=`expr "\${__bdev}" : '^/dev/dsk/\(.*\)s.\$'`
			__vol=`expr "\${__bdev}" : '^/dev/vx/dsk/\(.*\)'`
			case $__vol in
			*"/"*"/"*) __vol=;;
			*"/"*)	__dg="`expr "\$__vol" : '\(.*\)/.*'`"
				__vol="`expr "\$__vol" : '.*/\(.*\)'`";;
			*)	__dg=rootdg;;
			esac
			break
		fi
	done
	exec <&9 9<&-
	# rootdisk will  be empty if the root is defined as a volume in
	# the /etc/vfstab file.

	eval "${2}_bdev=$__bdev ${2}_cdev=$__cdev ${2}_disk=$__disk"
	if [ $# -eq 2 ] && [ "X$__dg" != Xrootdg ]
	then
		eval "${2}_vol="
	elif [ $# -eq 2 ]
	then
		eval "${2}_vol=$__vol"
	else
		eval "${2}_vol=$__vol ${3}=$__dg"
	fi
}

#
# set_bootdisk - set parameters for the root file system
#
set_rootdisk()
{
	mpdev=
	rootslice=
	get_mountdevice / root
	# for backward compatibility, set rootdisk

	# DMP:
	# Check if rootdisk is part of a multipath
	# DMP device, then return name of the actual
	# DMP device rather than the subpath

	if [ -f /usr/sbin/vxdmpadm ]
	then
		dogi_whole_slice $root_disk rootslice
		rootdmpdisk=`/usr/sbin/vxdmpadm getdmpnode nodename=$rootslice 2> /dev/null | tail +3 | awk '{print $1}'`
		dogi_slice_to_device $rootdmpdisk mpdev
		rootdisk=$mpdev
		if [ -z "$rootdisk" ]
		then
			rootdisk=$root_disk
		fi

	else
		rootdisk=$root_disk
	fi
}

get_drv_list() 
{
	dir_entry="`ls -ld \$1`"
	path=`expr "$dir_entry" : ".*\/devices\(.*\)"`
	[ -n "$path" ] || {
		file=$1
		export file; egettxt >&2 \
			'get_drv_list: Invalid device file: $file' vxvmshm:1027 $file
		return 1
	}

	node=`basename $path`
	path=`dirname $path`

	while [ -n "$path" -a "X$node" != "X/" ]; do
		case $node in
			*@*)	drv=`expr $node : "\(.*\)@.*"`
				if [ "X$drv" = "XSUNW,ifp" ]
				then
					drv=`echo ifp`
				fi
				;;
			*)	drv=$node
				;;
		esac
		echo $drv
		node=`basename $path`
		path=`dirname $path`
	done
}

forceload_drv()
{
	file=$SYSROOT/etc/system
	cp $file $file.sav
	drv=$1
	grep "^ *forceload: *drv/$drv *$" $file 2>&1 > /dev/null
	if [ $? -eq 0 ] ; then
		return 0
	fi

	end_line=`grep -n vxvm_END $file`
	if [ -z "$end_line" ] ; then
	sed \
	-e '$ a\
* vxvm_START (do not remove)\
* vxvm_END (do not remove)' $file > $file.sav 
	cp $file.sav $file
	end_line=`grep -n vxvm_END $file`
	fi

	end_line=`expr "$end_line" : "\(.*\):.*"`
	end_line=`expr $end_line - 1`
	sed \
	-e ''$end_line' a\
forceload: 'drv/$drv'' $file > $file.sav
	cp $file.sav $file
}

#
# Routines to comment/uncomment "rootdev:" lines from /etc/system
#

# Common pattern variables
rpattern='^rootdev:'
block="*(vxvm rootability)*"
eblock='\*(vxvm rootability)\*'
cpattern="${eblock} rootdev:.*"

#
# Name:	comment_out_rootdev()
#
# Purpose: Any line matching $rpattern will be replaced by one line
# 	   composed of the matching line preceded by $block.
#
comment_out_rootdev()
{
	if [ $# -gt 1 ]
	then
		file=$1
	else
		file=$SYSROOT/etc/system
	fi

	# Return if no "rootdev" specs are found
	grep "${rpattern}" $file 2>&1 > /dev/null
	if [ $? -ne 0 ]; then
		return 0
	fi

	# Comment each one 
	sed -e "/${rpattern}/s,.*,${block} &," $file > $file.cor.save

	mv $file.cor.save $file

	return 0
}

#
# Name: restore_commented_rootdev()
#
# Purpose: Any line matching $cpattern will be replaced by one line
# 	   composed of the matching line with $block removed.  
#
restore_commented_rootdev()
{
	if [ $# -gt 1 ]
	then
		file=$1
	else
		file=$SYSROOT/etc/system
	fi

	# Return if no "rootdev" specs are found
	grep "${cpattern}" $file 2>&1 > /dev/null
	if [ $? -ne 0 ]; then
		return 0
	fi

	# Uncomment each one 
	sed -e "/${cpattern}/s,${eblock} \(.*\),\1," $file > $file.rcr.save

	mv $file.rcr.save $file

	return 0
}

#
# Set OS specific variables
#
set_OS_variables()
{
	VOL_FULL_SLICE=s2
	VOL_PRIV_SLICE=3
	VOL_PUB_SLICE=4
	VOL_GHOST_LEN=1
	VOL_PRIV_OFFSET=1
	EDVTOC=vxedvtoc
	PRTVTOC=vxprtvtoc
        VOLD=vxconfigd

	DISK_RAWPATH="/dev/rdsk"
	DISK_BLKPATH="/dev/dsk"
	VOL_DISK_RAWPATH="/dev/vx/rdmp"
	VOL_DISK_BLKPATH="/dev/vx/dmp"
	VOL_AP_DISK_RAWPATH="/dev/ap/rdsk"
	VOL_AP_DISK_BLKPATH="/dev/ap/dsk"

	VOL_ROOTABLE_FILESYSTEMS="/ /usr /var"
	VOL_KEEPER_FILESYSTEMS="/ /opt /usr /usr/kvm /var /var/adm"

	VOL_VFSTAB_PATH="/etc/vfstab"

	export VOL_FULL_SLICE VOL_PRIV_SLICE VOL_PUB_SLICE VOL_PRIV_OFFSET 
	export EDVTOC PRTVTOC VOLD
	export VOL_GHOST_LEN
	export VOL_DISK_RAWPATH VOL_DISK_BLKPATH
	export VOL_AP_DISK_RAWPATH VOL_AP_DISK_BLKPATH
	export VOL_ROOTABLE_FILESYSTEMS
	export VOL_VFSTAB_PATH
}

voladm_mounted_filesystems()
{
	fslist=`/sbin/mount | sed 's/ .*//'`
	if [ $# -gt 0 ]
	then
		eval "${1}=\"$fslist\""
	else
		echo $fslist
	fi
}

#
# voladm_mount_table - output (or copy to a file) the
# table of "filesystems to be moutned". On some unix systems,
# root (/) is not part of the vfstab, so it may need to
# be represented explicitly.

voladm_mount_table()
{
	if [ $# -gt 0 ]
	then
		xcmd cp $SYSROOT/$VOL_VFSTAB_PATH ${1}
	else
		cat $SYSROOT/$VOL_VFSTAB_PATH
	fi
}

voladm_disk_in_use()
{
	disk=`basename $1`

	if [ -f /usr/sbin/vxdmpadm ]
	then
		/usr/sbin/vxdmpadm getsubpaths dmpnodename=$disk 2> /dev/null | \
		tail +3 | grep -v "=" | awk '{print $1}' | \
		while read subpath
		do
			if [ "X${subpath}" = X ]
			then
				dogi_slice_blkpath $disk diskpath
				mount | grep $diskpath  > /dev/null 2> /dev/null
				if [ $? = 0 ] ; then
					return 0
				else
					return 1
				fi	
			fi
			dogi_slice_blkpath $subpath diskpath
			mount | grep $diskpath  > /dev/null 2> /dev/null
			if [ $? = 0 ] ; then
				return 0
			else
				return 1	
			fi
		done

		if [ "X${subpath}" = X ]
		then
			dogi_slice_blkpath $disk diskpath
			mount | grep $diskpath  > /dev/null 2> /dev/null
			if [ $? = 0 ] ; then
				return 0
			else
				return 1
			fi	
		fi
	else
		dogi_slice_blkpath $disk diskpath
		mount | grep $diskpath  > /dev/null 2> /dev/null
		if [ $? = 0 ] ; then
			return 0
		else
			return 1
		fi	
	fi
}

#
# is_std_disk - test if a disk is standard format
#
is_std_disk()
{
	_isd_base="m\{0,1\}c[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*"
	_isd_slice=s[0-9][0-9]*
	case $1 in
	"/dev/dsk/"*s*)	expr "$1" : "^/dev/dsk/$_isd_base$_isd_slice\$";;
	"/dev/rdsk/"*s*) expr "$1" : "^/dev/rdsk/$_isd_base$_isd_slice\$";;
	"/dev/vx/dmp/"*s*)	expr "$1" : "^/dev/vx/dmp/$_isd_base$_isd_slice\$";;
	"/dev/vx/rdmp/"*s*) expr "$1" : "^/dev/vx/rdmp/$_isd_base$_isd_slice\$";;
	*s*)		expr "$1" : "^$_isd_base$_isd_slice";;
	*)		expr "$1" : "^$_isd_base$_isd_slice";;
	esac
}

chroot_to_vol()
{
	file=$SYSROOT/etc/system
	grep "vxvm_END" $file 1>&2 > /dev/null
	if [ $? -ne 0 ] ; then
		egettxt \
		 "VxVM Information in /etc/system missing or corrupted." \
		 vxvmshm:986 >&2
		return 1
	fi

	# First, comment out any "old" rootdev specs
	comment_out_rootdev $file

	end_line=`grep -n vxvm_END $file`
	end_line=`expr "$end_line" : "\(.*\):.*"`
	end_line=`expr $end_line - 1`
	sed \
	-e ''$end_line' a\
rootdev:/pseudo/vxio@0:0\
set vxio:vol_rootdev_is_volume=1' $file > $file.sav
	mv $file.sav $file
	return 0
}

#
# This is used by some if the init.d scripts
#
set_pub_attr()
{

	#
	# Find the len and offset of the public region. 
	# If priv at start it is straightforward
	# else It should be the 
	# len of pub partition - len of priv partition - pub offset + priv
	# offset + priv offset because pub should enter the priv for the
	# ghost sd For an encapsulated root disk with priv carved out of swap,
	# the priv will be lying in the middle of pub. In this case return 
	# len of pub partition - pub offset
	#

	dogi_slice_rawpath $1 rawpath
	eval `vxparms`
	eval `vxtaginfo -s $rawpath $VOL_PUB_SLICE_TAG 2> /dev/null`
	pub_start=$PART_START
	pub_size=$PART_SIZE
	pub_end=`expr $pub_start + $pub_size`
	eval `vxtaginfo -s $rawpath $VOL_PRIV_SLICE_TAG 2> /dev/null`
	priv_start=$PART_START
	priv_size=$PART_SIZE
	eval `vxpartinfo -s $rawpath 2 2> /dev/null`
	full_start=$PART_START
	full_size=$PART_SIZE
	priv_end=`expr $priv_start + $priv_size`
	if [ $priv_start -eq 0 ] 
	then
		VOL_PUB_OFFSET=0
		VOL_PUB_LEN=$pub_size
	elif [ $priv_end -eq $full_size ] 
	then
		VOL_PUB_OFFSET=1
		if [ $pub_end -gt $priv_start ] ; then
			VOL_PUB_LEN=`expr $pub_size - $priv_size - \
			     $VOL_PUB_OFFSET + $VOL_PRIV_OFFSET`
		else
			VOL_PUB_LEN=`expr $pub_size - $VOL_PUB_OFFSET`
		fi
	else
		VOL_PUB_OFFSET=1
		VOL_PUB_LEN=`expr $pub_size - $VOL_PUB_OFFSET`
	fi
	export VOL_PUB_LEN VOL_PUB_OFFSET
}

#
# THESE ARE NOT USED
#

vol_add_slice()
{
	#
	# If device specified as cCtTdD then  add s2 
	#
	VOL_FULL_DISK=$1

	if vxcheckda $1
	then
		VOL_FULL_DISK=$VOL_FULL_DISK$VOL_FULL_SLICE
	fi
	export VOL_FULL_DISK
}

pipe_escape()
{
	echo $1 | sed -e 's/\|/\\|/g'
}
#
# add_cntrlr_expression -- add the given controller name to the
# expression to egrep out controller names. The second argument should
# be the variable name of the expression to be used.
#
add_cntrlr_expression()
{
	cntrlr=$1

	eval "expression=\${${2}}"

	if [ -z "$expression" ]
	then
		expression="${cntrlr}t"
	else
		expression="${expression}|${cntrlr}t"
	fi

	expression=`pipe_escape $expression`

	eval "${2}=$expression"
}

#
# add_device_expression -- add the given disk name to the
# expression to egrep out disk access names. The second argument should
# be the variable name of the expression to be used.
#
add_device_expression()
{
	dogi_whole_slice $1 device

	eval "expression=\${${2}}"

	if [ -z "$expression" ]
	then
		expression="${device}"
	else
		expression="${expression}|${device}"
	fi

	expression=`pipe_escape $expression`
	eval "${2}=$expression"
}

#
# extr_list_info -- extract information from a long listing of a device file.
#
extr_list_info()
{
	listing=$1
	diskname=$2

	cinfo=`expr "$listing" : '.* -> .*/devices/\(.*\)/[^/]*$'`
	cntrlr=`expr "$diskname" : "\(m\{0,1\}c[0-9][0-9]*\)t\{0,1\}[0-9]*d[0-9][0-9]*${VOL_FULL_SLICE}"`

	eval "${3}=${cinfo}"
	eval "${4}=${cntrlr}"
}

extr_plninfo()
{
	info=$1
	ssa_id=`expr "$info" : '.*/SUNW,pln@[ab]\([0-9,a-fA-F]*\).*'`
	[ -n "$ssa_id" ] || return 1
	eval "${2}=${ssa_id}"
}

tchar="-"
twirl()
{
	/bin/echo "$tchar\b\c"
	case $tchar in
		"-") tchar="/";;
		"/") tchar="|";;
		"|") tchar="\\\\";;
		"\\\\") tchar="-";;
	esac
}

#
# controllers_on_system -- list all controllers on the system
#
controllers_on_system()
{
	xcmd cd $VOL_DISK_RAWPATH
	ls | egrep "c[0-9][0-9]*t?[0-9]*d[0-9][0-9]*${VOL_FULL_SLICE}" | \
	 while read disk
	 do
		 twirl >&2
		 cntr_info=`ls -l $disk`
		 case $cntr_info in
			 l*" -> "*)	: ;;
			 *)		: ;;
		 esac

		extr_list_info "$cntr_info" $disk cntr_info cntr
		list_member $cntr $ctl_temp && continue
		append_list ctl_temp $cntr

		if [ -f $VOL_CONFIG_DIR/vxvm.exclude ]
		then
			vxdmpadm checkexclude vxvm ctlr=$cntr:$cntr 2>/dev/null
			ret=$?
			if [ $ret -eq 0 -o $ret -eq 3 ]
			then
				cntr="$cntr" egettxt "<excluding $cntr>" vxvmshm:67 >&2
				continue
			fi
		fi

		if [ -f $CNTRL_EXCLUDE_FILE ]
		then
			if fgrep -x "$cntr" $VOL_CONFIG_DIR/cntrls.exclude \
			> /dev/null 2>&1
			then
				cntr="$cntr" egettxt "<excluding $cntr>" vxvmshm:67 >&2
				continue
		fi
		fi
		echo "$cntr $cntr_info"
	 done
}

#
# disks_on_controller -- given a controller number, list all disks
# that we can find on that controller to stdout.

disks_on_controller()
{
	cntrlr=$1

	(cd $VOL_DISK_RAWPATH;
	ls;
	) | egrep "m?${1}t?[0-9]*d[0-9][0-9]*${VOL_FULL_SLICE}"
}

#
# expand_device_wildcard -- expand a disk specification into all
# matching devices. This is used in voladm_disk_device_list. It honors
# controller/device exclusion patterns.
#
expand_device_wildcard()
{
	list_var=$1
	eval "disklist=\${${list_var}}"
	excl_disks=$2
	excl_cntrlr=$3
	disk_excluded_var=$4
	eval "disk_excl=\${$disk_excluded_var}"
	cntrlr_excluded_var=$5
	eval "cntrlr_excl=\${$cntrlr_excluded_var}"
	shift 5

	# The string "${VOL_FULL_SLICE}\$" must be appended to each disk 
	# device string in the egrep pattern list to ensure that only the 
	# specified disk(s) is filtered out.
	if [ -n "$excl_disks" ]
	then

           excl_disks=`echo $excl_disks | sed "s/\|/${VOL_FULL_SLICE}\$\|/g" | \
				sed "s/$/${VOL_FULL_SLICE}\$/"`

	fi

	if list_member allc $@
	then
		ewritemsg -M vxvmshm:767 "Input not recognized: \"allc\""
		return 1
	elif list_member allm $@
	then
		ewritemsg -M vxvmshm:768 "Input not recognized: \"allm\""
		return 1
	fi
	if list_member all $@
	then
		if [ $# -gt 1 ]
		then
			ewritemsg -M vxvmshm:63 \
			 "'all' should appear alone, enter ?? for help"
			return 1
		fi
		set -- allc allm
	fi

	while [ $# -gt 0 ]
	do
		spec=$1
		pattern=

		# Verify that it's valid
		slen=`strlen $spec`
		ldir=
		case "$spec" in
			c[0-9]*d[0-9]*)
			    mlen=`expr $spec : \
			     'c[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*'`
			    [ $mlen -eq $slen ] && pattern="$spec"
			    ldir=$VOL_DISK_RAWPATH
			    ;;
			mc[0-9]*d[0-9]*)
			    mlen=`expr $spec : \
			     'mc[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*'`
			    [ $mlen -eq $slen ] && pattern="$spec"
			    ldir=$VOL_AP_DISK_RAWPATH
			    ;;

			c[0-9]*t[0-9]*)
			    mlen=`expr $spec : \
			     'c[0-9][0-9]*t\{0,1\}[0-9]*'`
			    [ $mlen -eq $slen ] && pattern="${spec}d*"
			    ldir=$VOL_DISK_RAWPATH
			    ;;
			mc[0-9]*t[0-9]*)
			    mlen=`expr $spec : \
			     'mc[0-9][0-9]*t\{0,1\}[0-9]*'`
			    [ $mlen -eq $slen ] && pattern="${spec}d*"
			    ldir=$VOL_AP_DISK_RAWPATH
			    ;;

			c[0-9]*)
			    mlen=`expr $spec : \
			     'c[0-9][0-9]*'`
			    [ $mlen -eq $slen ] && pattern="${spec}t*"
			    ldir=$VOL_DISK_RAWPATH
			    ;;
			mc[0-9]*)
			    mlen=`expr $spec : \
			     'mc[0-9][0-9]*'`
			    [ $mlen -eq $slen ] && pattern="${spec}t*"
			    ldir=$VOL_AP_DISK_RAWPATH
			    ;;
			allc)
			    pattern="c*"
			    ldir=$VOL_DISK_RAWPATH
			    ;;
			allm)
			    pattern="mc*"
			    ldir=$VOL_AP_DISK_RAWPATH
			    ;;
			*) pattern=
			   ldir=
			   ;;
		esac

		if [ -z "$pattern" ]
		then
			export spec; ewritemsg -M vxvmshm:766 \
"Input not recognized: \"$spec\""
			return 1
		fi

		push_list disklist \
		 `ls -1 ${ldir}/${pattern}${VOL_FULL_SLICE} 2>/dev/null | \
			tee $_vdskd_rawmatch |
			if [ -n "$excl_cntrlr" ]
			then
				egrep -v -e "$excl_cntrlr"
			else
				cat
			fi |
			tee $_vdskd_cntrlmatch |
			if [ -n "$excl_disks" ]
			then
				egrep -v -e "$excl_disks"
			else
				cat
			fi |
			tee $_vdskd_diskmatch |
			sed "s%${ldir}/\(.*\)${VOL_FULL_SLICE}$%\1%"`

		# Add excluded controllers and disks to the lists
		append_list $cntrlr_excluded_var \
		 `comm -3 $_vdskd_rawmatch $_vdskd_cntrlmatch`
		append_list $disk_excluded_var \
		 `comm -3 $_vdskd_cntrlmatch $_vdskd_diskmatch`

		shift
	done

	eval "$list_var=\"$disklist\""
	return 0
}

extr_devicepath()
{
	wholepath=$1

	devicepath=`expr "$wholepath" : '.*\(/devices/.*\)'`

	eval "${2}=${devicepath}"
}

# usage: subdisk_to_partition diskgroup volume dm_name
# if an sd takes up a whole partition, return the blkpath to the partition.

subdisk_to_partition()
{
	_ckdg=$1
	_ckvol=$2
	_fdumpdm=$3
	[ -n "$_ckdg" -a -n "$_ckvol" -a -n "$_fdumpdm" ] || return

	vxprint -g $_ckdg -se \
		"sd_pl_offset=0 && sd_dmname=\"$_fdumpdm\" &&
		 assoc.assoc=\"$_ckvol\" && len >= assoc.assoc.len" \
		-F "%path %dev_offset %len" |
	{
	    found=
	    while [ -z "$found" ] && read path devoffset sdlen
	    do
		[ "X$path" != "X-" -a "X$devoffset" != "X-" ] || continue

		# get the diskoffset of the subdisk
		dogi_path_to_slice $path base_slice

		[ -n "$base_slice" ] || continue
		dogi_slice_rawpath $base_slice base_rawpath
		STAT_PSTARTSEC=
		STAT_DISK_TYPE=
		eval "`vxparms -s $base_rawpath 2> /dev/null`"
		[ -n "$STAT_PSTARTSEC" ] || continue
		[ "X$STAT_DISK_TYPE" = Xdisk ] || continue
		diskoffset=`expr $devoffset + $STAT_PSTARTSEC`

		# locate a partition that matches the beginning of that
		# subdisk, and that is not longer than the subdisk
		dogi_slice_to_device $base_slice base_device
		old_device=$base_device
		path=`vxdisk -g $_ckdg list $base_device 2>/dev/null | \
			egrep "^m?c[0-9]+t[0-9]+d[0-9]+" | \
			awk '$2 == "state=enabled" {print $1}'`
		path=`echo $path`
		if [ "X$path" != "X" ]
		then
			base_device=`echo $path | cut -d "s" -f 1`
		fi

		if [ -z "$base_device" ]
		then
			base_device=$old_device
		fi
		for slice_num in 1 0 2 3 4 5 6 7
		do
			dogi_device_slice $base_device $slice_num try_slice 
			dogi_slice_rawpath $try_slice try_rawpath
			STAT_PSTARTSEC=
			STAT_PNUMSEC=
			eval "`vxparms -s $try_rawpath`"
			[ -n "$STAT_PSTARTSEC" -a -n "$STAT_PNUMSEC" ] || continue
			[ $STAT_PSTARTSEC -eq $diskoffset ] || continue
			[ $STAT_PNUMSEC -le $sdlen ] || continue
			[ -n "$base_device" ] || continue

			# set the dump device
			dogi_slice_blkpath $try_slice dumpdev
			found=yes
			echo $dumpdev
			break
		done
	    done
	}
}


#
# These are the dogi_* routines used by the rest of the administrative
# scripts. These should mask out any system-specific DA-naming or
# disk-related dependencies.
#

#
# dogi_name_is_device -- returns true if the (single) argument is
# in the form of a device name.
#
dogi_name_is_device()
{
	#
	# return true if the name is a valid device name
	#
	name=`basename $1`
	case "$name" in
		mc*)
		     name_len=`strlen $name`;
		     match_len=`expr $name : \
		      'mc[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*'`
		     [ "$name_len" -eq "$match_len" ]
		     ;;
		c*)
		    name_len=`strlen $name`;
		    match_len=`expr $name : \
		     'c[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*'`
		    [ "$name_len" -eq "$match_len" ]
		    ;;
		*) false;;
	esac
}

#
# dogi_name_is_slice -- returns true if the (single) argument is in
# the form of a slice name.
#
dogi_name_is_slice()
{
	#
	# return true if the name looks like a slice of a disk
	#
	name=`basename $1`
	case "$name" in
		mc*)
		     name_len=`strlen $name`;
		     match_len=`expr $name : \
		      'mc[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*s[0-9][0-9]*'`
		     [ "$name_len" -eq "$match_len" ]
		     ;;
		c*)
		    name_len=`strlen $name`;
		    match_len=`expr $name : \
		     'c[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*s[0-9][0-9]*'`
		    [ "$name_len" -eq "$match_len" ]
		    ;;
		*) false;;
	esac
}

#
# dogi_slice_num -- echo the slice part of the complete slice name
#
#	If optional second argument is provided, will set a variable by
#	that name to the slice portion of the first argument
#
dogi_slice_num()
{
	name=`basename $1`
	case "$name" in
		mc*)
		     s=`expr $name : \
		      'mc[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*\(s[0-9][0-9]*\)'`
		     ;;
		c*)
		    s=`expr $name : \
		     'c[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*\(s[0-9][0-9]*\)'`
		    ;;
		*)
		   s="";;
	esac
	if [ $# -gt 1 ]
	then
		eval "${2}=$s"
	else
		echo $s
	fi
}

#
# dogi_is_whole_slice -- return true if the slice names the special "whole"
# slice for the disk
#
dogi_is_whole_slice()
{
	if not dogi_name_is_slice "$1"
	then
		return 1
	fi

	dogi_slice_num $1 slice_name
	[ "$slice_name" = "${VOL_FULL_SLICE}" ]
}

#
# dogi_device_slice -- create a slice name out of the given device
# name and slice
dogi_device_slice()
{
	eval "${3}=${1}s${2}"
}

#
# dogi_slice_to_device -- given a slice name, return the device it names
#
#
dogi_slice_to_device()
{
	name=`basename $1`
	if not dogi_name_is_slice $name
	then
		return 1
	fi

	case "$name" in
		mc*)
		     d=`expr $name : \
		      '\(mc[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*\)s[0-9][0-9]*'`
		     ;;
		c*)
		    d=`expr $name : \
		     '\(c[0-9][0-9]*t\{0,1\}[0-9]*d[0-9][0-9]*\)s[0-9][0-9]*'`
		    ;;
		*) d="";;
	esac

	if [ $# -gt 1 ]
	then
		eval "${2}=$d"
	else
		echo $d
	fi
}

#
# dogi_name_to_device -- return the device name, given a name
#
dogi_name_to_device()
{
	name=`basename $1`
	if dogi_name_is_device $name
	then
		d=$name
	else
		dogi_slice_to_device $name d
	fi

	if [ $# -gt 1 ]
	then
		eval "${2}=$d"
	else
		echo $d
	fi
}

#
# dogi_slice_from_path -- given a disk pathname, strip off everything
# but the slice name.
#
dogi_path_to_slice()
{
	case $1 in
		"/dev/dsk/"*s*) d=`expr "$1" : '^/dev/dsk/\(.*s.\)\$'`;;
		"/dev/rdsk/"*s*) d=`expr "$1" : '^/dev/rdsk/\(.*s.\)\$'`;;
		"/dev/vx/dmp/"*s*) d=`expr "$1" : '^/dev/vx/dmp/\(.*s.\)\$'`;;
		"/dev/vx/rdmp/"*s*) d=`expr "$1" : '^/dev/vx/rdmp/\(.*s.\)\$'`;;
		"/dev/ap/dsk/"*s*)
			d=`expr "$1" : '^/dev/ap/dsk/\(.*s.\)\$'`;;
		"/dev/ap/rdsk/"*s*)
			d=`expr "$1" : '^/dev/ap/rdsk/\(.*s.\)\$'`;;
	esac

	if [ $# -gt 1 ]
	then
		eval "${2}=$d"
	else
		echo $d
	fi
}

#
# dogi_whole_slice -- given a device, return the slice name of the
# "whole slice"
#
# This is not necessarily a real DOGI interface function; it's a shortcut
# for solaris since the whole path is the device manipulation interface (i.e.,
# for prtvtoc, disk ioctls, etc.)
#
dogi_whole_slice()
{
	name=`basename $1`
	if not dogi_name_is_device $name
	then
		return 1
	fi

	p="${name}${VOL_FULL_SLICE}"
	if [ $# -gt 1 ]
	then
		eval "${2}=${p}"
	else
		echo $p
	fi
}
#
# dogi_device_vxpath -- return the path from the dmp directory to the 
# character node for the device
#

dogi_device_vxpath()
{
	if not dogi_name_is_device $1
	then
		return 1
	fi
	
	dogi_whole_slice "$1" w || return 1
	dogi_slice_vxpath $w pth

	if [ $# -gt 1 ]
	then
		eval "${2}=${pth}";
	else
		echo "$pth";
	fi
}

#
# dogi_device_rawpath -- return the path to the character node for the device
#

dogi_device_rawpath()
{
	if not dogi_name_is_device $1
	then
		return 1
	fi
	
	dogi_whole_slice "$1" w || return 1
	dogi_slice_rawpath $w pth

	if [ $# -gt 1 ]
	then
		eval "${2}=${pth}";
	else
		echo "$pth";
	fi
}

dogi_slice_rawpath()
{
	name=`basename $1`

	if not dogi_name_is_slice $name
	then
		return 1
	fi

	case $name in
		mc*)
		     p="${VOL_AP_DISK_RAWPATH}/${name}";;
		c*)
		    p="${DISK_RAWPATH}/${name}";;
		*) return 1;;
	esac

	if [ $# -gt 1 ]
	then
		eval "${2}=${p}";
	else
		echo "$p";
	fi
}

dogi_slice_vxpath()
{
	name=`basename $1`

	if not dogi_name_is_slice $name
	then
		return 1
	fi

	case $name in
		mc*)
		     p="${VOL_AP_DISK_RAWPATH}/${name}";;
		c*)
		    p="${VOL_DISK_RAWPATH}/${name}";;
		*) return 1;;
	esac

	if [ $# -gt 1 ]
	then
		eval "${2}=${p}";
	else
		echo "$p";
	fi
}

#
# dogi_device_blkpath -- return the path to the block node for the device
#
dogi_device_blkpath()
{
	if not dogi_name_is_device $1
	then
		return 1
	fi
	
	dogi_whole_slice "$1" w || return 1
	dogi_slice_blkpath $w pth
	if [ $# -gt 1 ]
	then
		eval "${2}=${pth}"
	else
		echo "$pth"
	fi
}


dogi_slice_blkpath()
{
	name=`basename $1`

	if not dogi_name_is_slice $name
	then
		return 1
	fi

	case $name in
		mc*)
		     p="${VOL_AP_DISK_BLKPATH}/${name}";;
		c*)
		    p="${DISK_BLKPATH}/${name}";;
		*) return 1;;
	esac

	if [ $# -gt 1 ]
	then
		eval "${2}=${p}";
	else
		echo "$p";
	fi
}

#
# dogi_name_daname -- return an appropriate DA record name for the
# given device name
#
dogi_name_daname()
{
	name=`basename $1`

	if not dogi_name_is_device $name
	then
		return 1
	fi

	dogi_whole_slice "$name" daname || return 1

	if [ $# -gt 1 ]
	then
		eval "${2}=${daname}"
	else
		echo "$daname"
	fi
}

#
# dogi_root_device -- return true if the named device is the boot disk
#
dogi_root_device()
{
	dname=$1
	if not dogi_name_is_device $dname
	then
		return 1
	fi
	
	set_rootdisk
	[ "$dname" = "$rootdisk" ]
}

#
# dogi_name_is_cntrlr -- returns true if the argument is in the form
# of a controller name.
#
dogi_name_is_cntrlr()
{
	name=`basename $1`
	case "$name" in
		mc*)
		     name_len=`strlen $name`;
		     match_len=`expr $name : \
		      'mc[0-9][0-9]*'`
		     [ "$name_len" -eq "$match_len" ]
		     ;;
		c*)
		    name_len=`strlen $name`;
		    match_len=`expr $name : \
		     'c[0-9][0-9]*'`
		    [ "$name_len" -eq "$match_len" ]
		    ;;
		*) false;;
	esac
}

#
# dogi_darecs_on_device -- list any DA records that are defined on
# the named device. The form of the list is "<da> <tm> <type>". The
# list is put into the variable named by the second argument. If any
# are found, return true.
#
dogi_darecs_on_device()
{
	name=`basename $1`

	> $tmpfile3
	LANG= vxdisk list | grep "^${name}s" > $tmpfile4

	xlist=`cat $tmpfile4`
	rm $tmpfile4

	if [ $# -gt 1 ]
	then
		eval "${2}=\"${xlist}\""
	else
		if [ "$xlist" != "" ]
		then
			echo "$xlist"
		fi
	fi
	[ `list_count $xlist` -ne 0 ]
}

#
# dogi_valid_vtoc -- return false if the disk does not have a valid
# table of contents.
#
dogi_valid_vtoc()
{
	name=`basename $1`
	if dogi_name_is_slice $name
	then
		dogi_slice_to_device $name name
	elif not dogi_name_is_device $name
	then
		return 1
	fi

	dogi_device_rawpath $name diskpath

	#
	# Get the vtoc - if error then return immediately
	#
	# Return 0 if there is a valid vtoc, else return 1.
	# There is a valid vtoc if the flags value indicates
	# there is a mountable partition, or there are VM public and
	# private regions.
	#

	$PRTVTOC -f /dev/stdout $diskpath | egrep "0x200|0x210" > /dev/null 2>&1
	[ $? -eq 0 ] && return 0
	$PRTVTOC -f /dev/stdout $diskpath | egrep "0xe" > /dev/null 2>&1
	if [ $? -eq 0 ]
	then
	    $PRTVTOC -f /dev/stdout $diskpath | egrep "0xf" > /dev/null 2>&1
	    [ $? -eq 0 ] && return 0
	fi
	return 1
}

#
# dogi_is_boot_device -- return true if the named device or disk media 
#                      record is the boot disk
#                      disk names are in the cNtNdN form
#
dogi_is_boot_device()
{
      dname=`basename $1`
      get_mountdevice / root

      #
      # If the aegument is a real disk device then check 
      # to see if it matches the root_disk var set by the
      # get_mountdevice call
      #
      if dogi_name_is_device $dname
      then
              [ "$dname" = "$rootdisk" ] && return 1
              return 0
      fi

      #
      # The argument must be a dm name
      #
      dm=$dname

      dmlist=`vxprint -F %dm -e as.as=\"$root_vol\" | sort -u`

      for bootdm in $dmlist
      do
              [ "$bootdm" = "$dm" ] && return 1
      done

      return 0
}

#
# dogi_get_prompath -- For systems that support setting their eeproms,
# determine correct path independent of disk name spaces.  Given a
# slice name for the new root device return the appropriate block path
# name.  
#
dogi_get_prompath()
{
	name=`basename $1`

	if not dogi_name_is_slice $name
	then
		return 1
	fi

	# 
	# Return the block path for slices that are NOT from AP
	# metadisks.  
	#
	# Otherwise, here's the deal with AP metadisk devices:  What
	# the eeprom needs is the raw disk path name of the active
	# alternate path.
	#
	# EXACT METHOD: Get alternate path group for metadisk and 
	# then determine which of the two is the active alternate.
	# 
	# GUESS METHOD: AP metadisks map to at most two alternate 
	# paths and the naming is coordinated:  e.g., mc3t4d0 refers to
	# alternate path c3t4d0 and cXt4d0 where "X" is unknown at this
	# point. So, just strip the 'm' off and you have at least one
	# alternate path.
	#

	case $name in
		mc*)
			#
			# EXACT METHOD -- not implemented
			#
			# dogi_get_ap $name ap1 ap2
			# One of these two should be the primary ap
			# if dogi_is_ap_primary $ap1
			# then
			# ap_primary=$ap1
			# else if dogi_is_ap_primary $ap2
			# then
			# ap_primary=$ap2
			# else
			# return 1        
			# fi

			#
			# GUESS METHOD
			#
			ap_primary=`expr $name : '^m\(.*\)'`

			# Get the block node for this primary ap
			dogi_slice_blkpath $ap_primary blkpath
			;;
		c*)
			dogi_slice_blkpath $name blkpath
			;;
		*)
			return 1
			;;
	esac

	# Return information to caller
	if [ $# -gt 1 ]
	then
		eval "${2}=${blkpath}"
	else
		echo "$blkpath"
	fi
}
