#!/sbin/sh -
# %W% %G% %U% - %Q%
#ident "%Z%unixvm:%M% %I%"

# 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 [-ief] disk-device-address [ attribute ... ]

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

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

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

Options:
    -i	Initialize the private region
    -e	Allocate the private region at the end of the disk
    -f	Force	

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:866`
!
}

# 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

doinit=
privatend=
publen=
privlen=
puboffset=
privoffset=
noconfig=
initattrs=
force=

while getopts :iefvh c
do
	case $c in
	f)	force=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

		primary_node=$address
             
		if [ -f $DISKDIR/$address/primary_node ] 	
		then   
		        exec 3<&0 < $DISKDIR/$address/primary_node 
                        read node
		else 
		        get_primary_path $address node
			dogi_slice_to_device $node node
		fi
		
		dogi_device_rawpath $node primary_node || 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;  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 type 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

# Look for import shared tag. If so, break out. For we may accidentally
#  initialize a disk that is "shared" by another host
# "vxdisk online" re-scans the disk header, to ensure we get the latest
# status infomation.
vxdisk online $address 2>/dev/null

# If "vxdisk online" succeeded, then we have detected a disk
# that is VM formatted. Now we need to make sure that the disk
# is NOT marked "shared" by another host.
#
# If "vxdisk online" fails, we can simply ignore the errors since
# the sole purpose of "vxdisk online" was just to refresh a
# valid VM header.
if [ $? -eq 0 ]
then
	vxdisk -s list $address > ${tmpfile1}  2>/dev/null
	[ $? -ne 0 ] && {
		export address; xerrmsg -M vxvmshm:1118 \
		"$address: Can not get disk information."
		exit 1
	}
	exec 3<&0 < ${tmpfile1}
	while read tag value
	do
		if [ "$tag" = "flags:" ]
		then
			for i in $value
			do
				if [ "$i"  = "shared" ]
				then
					export address; xerrmsg -M vxvmshm:1120 \
	"$address: Disk is tagged as imported to a shared disk group. Can not proceed."
					exit 1
				fi
			done
		fi
		if [ "$tag" = "dgname:" ]
		then
			for i in $value
			do
				if [ -n "$i" ] && [ -z "$force" ]
				then
					export address; xerrmsg -M vxvmshm:1120 \
	"$address: Disk is part of $i disk group, use -f option to force setup."
					exit 1
				fi
			done
		fi
	done
        exec 0<&3 3<&-
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;;
	*)		cmd=$1
			progname=$0
			export cmd progname; xerrmsg -M vxvmshm:1016 \
		      "$cmd: Attribute unrecognized" $progname "$@"
		      exit 1;;
	esac
	if eval "[ ! -z \"\$$tag\" ]"
	then
		cmd=$1
		progname=$0
		export cmd progname; xerrmsg -M vxvmshm:1017 \
			"$cmd: Duplicate attribute specified" $progname "$@"
		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
	progname=$0
	export progname; egettxt "$progname: Invalid output from vxparms program." \
		vxvmshm:1018 $progname "$@" >&2
	quit 1
fi
pubtag=$VOL_PUB_SLICE_TAG
privtag=$VOL_PRIV_SLICE_TAG



#  Remove all existing slices on given disk.

doit vxpartrmall $primary_node  || 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
		privatend=y
		if [ $privoffset -lt -$size ]
		then
			progname=$0
			export size; xerrmsg -M vxvmshm:731 \
				'Disk is only $size sectors in length' $progname
			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 [ -n "$privatend" ]
	then
		puboffset=0
	else
		puboffset=`expr $privoffset + $privlen`
	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 $primary_node $VOL_PUB_SLICE $pubtag 0x201 $puboffset $publen &&
doit vxpartadd $primary_node $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
