#!/sbin/sh -
# @(#)src/sol/cmd/vxvm/support/vxdisksetup.sh	1.3.21.6 09/12/00 04:27:31 - Copyright (c) 1999 VERITAS Software Corp.
#ident "@(#)unixvm:src/sol/cmd/vxvm/support/vxdisksetup.sh 1.3.21.6"

# 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


: ${VOLROOT_DIR:=$__VXVM_ROOT_DIR}
. ${VOL_SCRIPTS_LIB:-$VOLROOT_DIR/usr/lib/vxvm/lib}/vxcommon

set_OS_variables
exec 4>&2

# usage - print a short usage message
usage() {
	cat <<! >&2
`egettxt "\
Usage: vxdisksetup [-nie] disk-device-address [ attribute ... ]

For detailed help use: vxdisksetup -h
" vxvmshm:460`
!
}

# fullusage - print a verbose usage message
fullusage() {
	cat <<! >&2
`egettxt "\
vxdisksetup - setup a disk for use with the volume manager

Usage: vxdisksetup [-nie] disk-device-address [ attribute ... ]

Options:
    -n	Don't perform surface analysis
    -i	Initialize the private region
    -e	Allocate the private region at the end of the disk

Attributes:
    publen=<number>	   Length of public region (used to contain subdisks).
    privlen=<number>       Length of private region (used for VM private data).
    puboffset=<number>	   Offset to partition containing public region.
    privoffset=[-]<number> Offset to partition containing private region.
    noconfig		   Don't store configuration or log copies on the disk.
    config		   Do store configuration and log copies (default).
" vxvmshm:556`
!
}

# doit - execute a command, printing the command in verbose mode
doit() {
	[ "$verbose" ] && cat <<-% >&4
			! $*
			%
	"$@"
}

# errmsg - print an error message
errmsg() {
	cat <<-! >&2
	vxdisksetup: $*
	!
}

xerrmsg() {
	if [ "$1" = "-M" ]
	then
		_err_cat="$2"
		_err_def="$3"
		shift 3
		_err_msg="`egettxt \"$_err_def\" \"$_err_cat\" \"$@\"`"
	else
		_err_msg="$*"
	fi
	errmsg "$_err_msg"
}

# attrvalue - extract the value for an attribute argument

# Usage: attrvalue variable attribute regexp min-value match-error-message
attrvalue() {
	if [ "X$3" = Xlength ]
	then
		_val1=`expr "\$2" : "^[a-z]*=\(.*\)$"`
		if [ -z "$_val1" ]; then
			errmsg "$2: $5"
			exit 1
		fi
		if [ -n "$4" ]; then
			_val=`strtovoff -n -m $4 -- "\$_val1"`
		else
			_val=`strtovoff -n -- "\$_val1"`
		fi
		if [ -z "$_val" ]; then
			errmsg "$2: $5"
			exit 1
		fi
		[ "$_val" -eq 0 ] && {
			case $_val1 in
			-*)	_val=-$_val;;
			esac
		}
	else
		_val=`expr "\$2" : "^[a-z]*=\($3\)$"`
		if [ -z "$_val" ]; then
			errmsg "$2: $5"
			exit 1
		fi
	fi
	eval "$1=\$_val"
}


# argument processing

noanalyze=n
doinit=
privatend=
publen=
privlen=
puboffset=
privoffset=
noconfig=
initattrs=

while getopts :niefvh c
do
	case $c in
	n)	noanalyze=y;;
	i)	doinit=y;;
	e)	privatend=y;;
	v)	verbose=yes;;
	h)	fullusage; exit 1;;
	?)	usage; exit 1;;
	esac
done
shift `expr $OPTIND - 1`
if [ $# -lt 1 ]
then
	usage
	exit 1
fi
address=$1
shift


# The device address must be in the form of a SCSI disk address.
# The $VOL_FULL_SLICE suffix will be added to form the accessname, and 
# the appropriate raw disk directory path name will be prefixed to define
# the path to access the disk raw device.

if vxcheckda $address > /dev/null 2> /dev/null
then
	if not dogi_name_is_device $address
	then
		invalid_device=yes
	else
		dogi_name_daname $address accessname || invalid_device=yes
		dogi_whole_slice $address wholeaddr || invalid_device=yes
		dogi_device_rawpath $address rawpath || invalid_device=yes
	fi
else
		invalid_device=yes
fi

if [ "${invalid_device}" = "yes" ]
then
	export address; xerrmsg -M vxvmshm:869 "\
$address: Device address must be of the form cCtTdD or mcCtTdD where

    C = host bus adapter controller number
    T = target device controller number, if used
    D = logical unit (disk) number within target device controller"
	exit 1
fi

#dogi_whole_slice $address accessname

STAT_SDI_NAME=
eval `vxparms -s $rawpath`
if [ -z "$STAT_SDI_NAME" ]
then
	export address; xerrmsg -M vxvmshm:43 \
		"$address: Invalid disk device for vxdisksetup"
	exit 1
fi
if [ "X$STAT_SDI_NAME" != "X$accessname" ]
then
	export rawpath; xerrmsg -M vxvmshm:57 \
		"$rawpath: Device does not match the kernel configuration"
	exit 1
fi


# If any partitions on this disk are being used, or contain
# non-standard DA records, then fail.

if [ ! -f $mkdbfile ]
then
	dogi_darecs_on_device $address > $tmpfile1
	if [ -s $tmpfile1 ]
	then
		exec 3<&0 < $tmpfile1
		read da type dm dg stat
		if [ "X$dm" != "X-" ]
		then
			export da dm type dg address;  xerrmsg -M vxvmshm:134 \
"Disk $da is already being used as $type disk $dm in disk group $dg;
	Disk cannot be reinitialized."
			exit 1
		fi
		if [ "X$da" != "X$wholeaddr" ] ||
		   [ "X$type" != Xsliced ]
		then
			export da dm type dg address
			xerrmsg -M vxvmshm:133 \
"Disk $address contains $type DA record $da;
	Disk cannot be reinitialized by vxdisksetup."
			exit 1
		fi
		exec <&3 3<&-
	fi
fi

# scan through the list of attributes given on the command line

while [ $# -gt 0 ]
do
	form=length
	minvalue=
	msg=`egettxt "Numeric attribute value expected" vxvmshm:241`

	case $1 in
	publen=*)     tag=publen; minvalue=1;;
	privlen=*)    tag=privlen; minvalue=1;;
	puboffset=*)  tag=puboffset; minvalue=0;;
	privoffset=*) tag=privoffset; minvalue=;;
	noconfig)     noconfig=true; shift; continue;;
	config)	      noconfig=; shift; continue;;
	*)	          xerrmsg -M vxvmshm:34 \
		      "$1: Attribute unrecognized" $0 "$@"
		      exit 1;;
	esac
	if eval "[ ! -z \"\$$tag\" ]"
	then
		xerrmsg -M vxvmshm:35 \
			"$1: Duplicate attribute specified" $0 "$@"
		exit 1
	fi
	attrvalue $tag "$1" "$form" "$minvalue" "$msg"
	shift
done


# Call vxparms to get the tags to use for the public and private
# region slices.


VOL_PUB_SLICE_TAG=
eval `vxparms`
if [ -z "$VOL_PUB_SLICE_TAG" ]
then
	egettxt "$0: Invalid output from vxparms program." \
		vxvmshm:28 $0 "$@" >&2
	quit 1
fi
pubtag=$VOL_PUB_SLICE_TAG
privtag=$VOL_PRIV_SLICE_TAG



#  Remove all existing slices on given disk.

doit vxpartrmall $rawpath  || exit 1

#  Define the boundaries of the disk.  The definition below is for
#  Solaris, this will likely require changes for different operating
#  systems.

start=0
size=$STAT_DISKNUMSEC

# supply defaults for all attributes that were not specified on the
# command line

# if no configuration copies are being allocated, then only a minimal
# private region is required; otherwise allocate a liberal public
# region
[ ! -z "$privlen" ] || {
	if [ -n "$noconfig" ]
	then
		privlen=160
	else
		privlen=2048
	fi
}

# Adjust to next cylinder

balance_cyl=`expr $privlen % $STAT_SECPERCYL`
if [ $balance_cyl -gt 0 ]
then
	adjust_cyl=`expr $STAT_SECPERCYL - $balance_cyl`
	privlen=`expr $privlen + $adjust_cyl`	
fi

# Put the private region at the end of the disk, with -e,
# otherwise, put the private region at the beginning.
if [ -z "$privoffset" ]
then
	if [ -n "$privatend" ]
	then
		privoffset=`expr $size - $privlen`
	else
		privoffset=0
	fi
else
	case $privoffset in
	-*)	# offset is from the end, not the beginning
		if [ $privoffset -lt -$size ]
		then
			export size; xerrmsg -M vxvmshm:731 \
				'Disk is only $size sectors in length' $0
			exit 1
		fi
		privoffset=`expr $size - $privlen + $privoffset`

		# Adjust priv offset to previous cylinder
		privoffset=`expr $privoffset - $privoffset % $STAT_SECPERCYL`
		;;

	*)	# Adjust priv offset to next cylinder
		balance_cyl=`expr $privoffset % $STAT_SECPERCYL`
		if [ $balance_cyl -gt 0 ]
		then
			adjust_cyl=`expr $STAT_SECPERCYL - $balance_cyl`
			privoffset=`expr $privoffset + $adjust_cyl`	
		fi
		;;
	esac
fi

if [ -z "$puboffset" ]
then
	if [ "$privoffset" -eq 0 ]
	then
		puboffset=`expr $privoffset + $privlen`
	else
		puboffset=0
	fi
fi


# Adjust to next cylinder

balance_cyl=`expr $puboffset % $STAT_SECPERCYL`
if [ $balance_cyl -gt 0 ]
then
	adjust_cyl=`expr $STAT_SECPERCYL - $balance_cyl`
	puboffset=`expr $puboffset + $adjust_cyl`
fi


[ -z "$noconfig" ] || initattrs="$initattrs nlog=0 nconfig=0"


# On Solaris the pub partition will cover the priv too, if the priv
# is after the beginning of the public region.
# vxconfigd will adjust the real public region length so that it will
# not really overlap.

if [ -z "$publen" ]
then
	if [ $puboffset -lt $privoffset ]
	then
		publen=`expr $privoffset + $privlen - $puboffset`
	else
		publen=`expr $size - $puboffset`
	fi
fi

# Adjust the start of the public and private region partitions to be
# within the current partition full partition.

puboffset=`expr $puboffset + $start`
privoffset=`expr $privoffset + $start`


# partitions as partitions VOL_PRIV_SLICE and VOL_PRIV_SLICE.  
# Flag the partitions with our
# partition type tags, and indicate that they are valid, unmountable.

doit vxpartadd $rawpath $VOL_PUB_SLICE $pubtag 0x201 $puboffset $publen &&
doit vxpartadd $rawpath $VOL_PRIV_SLICE $privtag 0x201 $privoffset $privlen || {
	exit 1
}

# Initialize the public region.  Define the device just to make sure
# that it is defined.  (Re-)online it to make sure that the disk
# driver state is initialized with the new VTOC.


if [ "$doinit" ]
then
	doit vxdisk define $accessname 2> /dev/null
	[ $? -ne 0 ] && { doit vxdisk online $accessname || exit 1; }
	doit vxdisk -f init $accessname $initattrs 
fi
