#! /usr/bin/ksh 
#
# 17 Apr 2002 : initial
#
# Comments to erik.vandenmeersch@sun.com or kristien.hens@sun.com
# Thanks!


slice_metadb=7      # slice to create metadb on (change if necessary)
slice_dumpdevice=4  # slice to configure as dump device (change if necessary)

sdmdir=/opt/SUNBEsdm


function newscript {
 sdmscript=$1   # script that will be generated
 rm -rf $sdmscript 2>/dev/null
 P "#! /bin/ksh -x"
 P
}

function manual {
more <<EOF

 'sdmsetup' helps you in putting your boot disk under SDS.
 It includes mirroring , hot sparing and creation of a contingency disk.
 The 'sdmsetup' script GENERATES THE SCRIPTS to implement SDS on the boot disk.
 Running 'sdmsetup' does not make any modifications to your system. 

 Before running sdmsetup, verify the following :

   - Solstice DiskSuite must be installed
   - an unused slice must exist for the metadb. Default is 7. 
   - An unused slice must exist as dedicated dump partition. Default is 4.
     You need to modify the script (first lines) to change the defaults
     for these two slice numbers.
   - No metadb's or metadevices should already exist
   - The currently mounted partitions should correspond to entries in 
     /etc/vfstab. The script does not check this.

 There is no restriction on which partitions are used for /, swap or 
 any other file systems.

 'sdmsetup' generates the following scripts :
 
   /sdmsetup.ksh  : 
        Replicates VTOC, creates metadb and metadevices.
   /sdmsetup-after-reboot.ksh :
        Creates OBP aliases for mirror and contingency disk, attaches
        submirrors.
   /sdmclone.ksh :
        Partitions the contingency disk and copies the boot disk file 
        systems to the contingency disk
        This script is created only when -c is specified.
          sdmclone.ksh without options will do a full ufsdump
          sdmclone.ksh -i   will do an incremental ufsdump 

 To use sdmsetup, follow the steps below:

    1. Run sdmsetup
    2. Verify the commands in /sdmsetup.ksh and run it.
    3. reboot
    4. Verify the commands in /sdmsetup-after-reboot.ksh and run it.
    5. Only if a contingency disk was specified:
       Verify the commands in /sdmclone.ksh, move it to a local bin 
       directory, and run it  manually or via cron at appropriate intervals.

EOF
}


function usage {
cat <<EOF

Usage : sdmsetup -b cXtXdX [ -m cXtXdX ] [ -c cXtXdX ] [ -s cXtXdX ] [-h]

   -h : display detailed instructions on using sdmsetup
   -b : the current boot disk
   -m : disk to become the mirror system disk
   -c : disk to become the contingency system disk
   -s : disk to become the hot spare disk 

EOF
}

function P { 
echo $* >> $sdmscript
}

function E {
echo $* >&2
}

bootdisk=
mirrdisk=
clondisk=
spardisk=

b=false
m=false
c=false
s=false

help=false

d=0
while getopts b:m:c:s:d:h i
do
        case $i in
        b) bootdisk=$OPTARG ; b=true ; ((d=d+1)) ;;
        m) mirrdisk=$OPTARG ; m=true ; ((d=d+1)) ;;
        c) clondisk=$OPTARG ; c=true ; ((d=d+1)) ;;
        s) spardisk=$OPTARG ; s=true ; ((d=d+1)) ;;
        h) help=true ;;
        \?)     usage;
                exit 1;;
        esac
done

if $help
then
 manual
 exit
fi

if ((d<2))
then
 echo
 echo You must specify the boot disk and at least one other option.
 usage
 exit
fi

dryrun=false
dfcommand="df -k"
swapcommand="swap -l"

if [[ -r df-k ]]
then
dfcommand="cat df-k"
E Warning : using the contents of the file df-k
dryrun=true
fi

if [[ -r swap-l ]]
then
swapcommand="cat swap-l"
E Warning : using the contents of the file swap-l
dryrun=true
fi

function invalid_disk {
 echo
 echo Invalid or non existing disk name : $1 . Exiting if not dry run...
 echo
 ! $dryrun && exit
}

function slice_used {
echo $slices_root $slices_otherfs $slices_swap | grep $1 > /dev/null 2>&1
}

function slice_available {
echo $slices_other | grep $1 > /dev/null 2>&1
}

# Exit if the specified disks do not exist

$b && ! ls /dev/rdsk/${bootdisk}s2 >/dev/null && invalid_disk $bootdisk
$m && ! ls /dev/rdsk/${mirrdisk}s2 >/dev/null && invalid_disk $mirrdisk
$c && ! ls /dev/rdsk/${clondisk}s2 >/dev/null && invalid_disk $clondisk
$s && ! ls /dev/rdsk/${spardisk}s2 >/dev/null && invalid_disk $spardisk

# Determine slice numbers

root_ok=false
slice_root=          # slice with root file system
slices_otherfs=      # slices with a file system that is not root
slices_swap=         # slices used as swap
slices_other=        # slices defined in vtoc but none of the above

for i in 0 1 3 4 5 6 7
do
 $dfcommand | grep /dev/dsk/${bootdisk}s$i | read dev x x x x fs
 if [[ $dev = /dev/dsk/${bootdisk}s$i ]]
 then
  # this is an existing and mounted file system
  if [[ $fs = / ]]
  then
   root_ok=true
   slice_root=$i
  else
   slices_otherfs="$slices_otherfs $i"
  fi
 else
  $swapcommand | grep /dev/dsk/${bootdisk}s$i  > /dev/null
  if [[ $? = 0 ]] 
  then
   slices_swap="$slices_swap $i"
  else
   # test if slice exists by reading a block from it
   dd if=/dev/rdsk/${bootdisk}s$i of=/dev/null count=1 >/dev/null 2>&1 
   if [[ $? = 0 ]]
   then
    slices_other="$slices_other $i"
   fi
  fi
 fi
done
 
E
E Info : slice with root file system = $slice_root
E Info : slices with non-root file systems = $slices_otherfs
E Info : slices used as swap = $slices_swap
E Info : slices not in use but defined in VTOC = $slices_other
E


if ! $root_ok 
then
 E 
 E Could not find a slice on $bootdisk for /
 E Exiting...
 E
EOF
 exit
fi

if ! slice_available $slice_metadb
then
 E 
 E The slice $slice_metadb for metadb replicas does not exist
 E Exiting...
 E
EOF
 exit
fi

# Exit if Solstice DiskSuite is not installed

if ! pkginfo -q SUNWmdr || \
   ! pkginfo -q SUNWmdu 
then
 echo SDS is not installed. Exiting...
 exit
fi

#==================================================================
# create /sdmsetup.ksh
#==================================================================

newscript /sdmsetup.ksh

P
P "# Copy VTOC and bootblock to the other disks"
P

$m && P dd if=/dev/rdsk/${bootdisk}s2 of=/dev/rdsk/${mirrdisk}s2 count=16
$c && P dd if=/dev/rdsk/${bootdisk}s2 of=/dev/rdsk/${clondisk}s2 count=16
$s && P dd if=/dev/rdsk/${bootdisk}s2 of=/dev/rdsk/${spardisk}s2 count=16

P
P "# Create state database replicas"
P

if ((d==4))
then
 P metadb -a -f ${bootdisk}s$slice_metadb
 P metadb -a ${mirrdisk}s$slice_metadb
 P metadb -a ${clondisk}s$slice_metadb
 P metadb -a ${spardisk}s$slice_metadb
fi


if ((d==3))
then
 P metadb -a -f ${bootdisk}s$slice_metadb
 for disk in `echo $mirrdisk $clondisk $spardisk`
 do
  P metadb -a ${disk}s$slice_metadb
 done
fi

if ((d==2))
then
 P metadb -a -f -c 2 ${bootdisk}s$slice_metadb
 for disk in `echo $mirrdisk $clondisk $spardisk`
 do
  P metadb -a -c 2 ${disk}s$slice_metadb
 done
fi

P
P # Exit if the state database creation failed.
P

cat <<EOF >> $sdmscript
if ! metadb > /dev/null
then
 echo metadb creation failed: Exiting...
 exit
fi
EOF

P
P "# Create the metadevices for all used slices"
P

for i in $slice_root $slices_otherfs $slices_swap
do
 P metainit -f d1$i 1 1 ${bootdisk}s$i
 P metainit d$i -m d1$i
done

if $m
then
 for i in $slice_root $slices_otherfs $slices_swap
 do
  P metainit d2$i 1 1 ${mirrdisk}s$i
 done
fi

P
P cp /etc/vfstab /etc/vfstab.presds
P
P metaroot d$slice_root

# list the slices that must be replaced by metadevices in vfstab
# The root slice is already done by metaroot.

x=
for i in $slice_root $slices_otherfs $slices_swap
do
x=$x$i
done

if [[ $x != "" ]]
then
 P
 P "# Change the partitions to metadevices in /etc/vfstab"
 P
 cat <<EOF >> $sdmscript
cat /etc/vfstab.presds | \
  sed "s,/dev/dsk/${bootdisk}s\([$x]\),/dev/md/dsk/d\1," | \
  sed "s,/dev/rdsk/${bootdisk}s\([$x]\),/dev/md/rdsk/d\1," > /etc/vfstab
EOF
fi

P
P "# Disable the quorum rule in a 2-disk configuration"
P

if  ((d<3)) 
then
 P "echo set md:mirrored_root_flag=1 >> /etc/system"
fi

if ! slice_available $slice_dumpdevice
then
 E 
 E Warning: The slice $slice_dumpdevice does not exist
 E Warning: No dedicated dump slice will be defined
 E
else
 P
 P "# Configure dedicated dump device"
 P
 P dumpadm -d /dev/dsk/${bootdisk}s$slice_dumpdevice
fi

echo
echo Script created : $sdmscript

#==================================================================
# create /sdmsetup-after-reboot.ksh
#==================================================================

newscript /sdmsetup-after-reboot.ksh

# Create the OBP aliases

function bootpath {
disk=$1
ls -l /dev/rdsk/${disk}s0 | sed 's|^.*/devices\(.*\),raw|\1|' | read devpath
ctrlname=$(dirname $devpath)
diskname=$(basename $devpath)

change=false
echo $devpath | grep '/ide@' > /dev/null && change=true
echo $devpath | grep '/scsi@' > /dev/null && change=true
$change && diskname=disk@${diskname#*@}

bootpath=$ctrlname/$diskname
}


      bootpath $bootdisk ; bdisk=$bootpath
$m && bootpath $mirrdisk ; mdisk=$bootpath
$c && bootpath $clondisk ; cdisk=$bootpath
$s && bootpath $spardisk ; sdisk=$bootpath

eeprom nvramrc | \
  grep -v 'data not available' | \
  sed 's/nvramrc=//g' > /tmp/nvramrc$$

      echo devalias bootdisk $bdisk  >> /tmp/nvramrc$$
$m && echo devalias mirrdisk $mdisk  >> /tmp/nvramrc$$
$c && echo devalias clonedisk $cdisk >> /tmp/nvramrc$$
$s && echo devalias sparedisk $sdisk >> /tmp/nvramrc$$

bootables='bootdisk'
$m && bootables="$bootables mirrdisk"
$c && bootables="$bootables clonedisk"
$s && bootables="$bootables sparedisk"

cat << PPP >> $sdmscript
eeprom nvramrc="$(cat /tmp/nvramrc$$)"
eeprom use-nvramrc?=true
eeprom boot-device='$bootables'
PPP

# Attach the submirrors

if $m
then
 P
 for i in $slice_root $slices_otherfs $slices_swap
 do
  P metattach d$i d2$i
 done
fi

# Create the hot spare pools

if $s
then
 for i in $slice_root $slices_otherfs $slices_swap
 do
  P 
  P metahs -a hsp00$i ${spardisk}s$i
  P metaparam -h hsp00$i d1$i
  P metaparam -h hsp00$i d2$i
 done
fi

# Wait until mirrors are synchronized

cat << PPP >> $sdmscript

while metastat | grep %
do
 echo
 sleep 10
done
PPP


echo
echo Script created : $sdmscript
echo


#==================================================================
# create /sdmclone.ksh
#==================================================================

newscript /sdmclone.ksh

! $c && exit

cat <<PPP >>$sdmscript

if [[ "\$1" == -i ]] then
 newfs=false
 opt=1f
else
 newfs=true
 opt=0uf
fi
# create a dedicated mount point 
[[ ! -d /mnt_backup ]] && mkdir /mnt_backup

PPP

for i in $slice_root $slices_otherfs
do
 P
 P "#-------- backup of slice $i ------------------"
 P
 P umount -f /dev/dsk/${clondisk}s$i
 P "\$newfs && echo y | newfs /dev/rdsk/${clondisk}s$i"
 P umount -f /mnt_backup
 P mount /dev/dsk/${clondisk}s$i /mnt_backup
 P "ufsdump \$opt - /dev/md/dsk/d$i | ( cd /mnt_backup ; ufsrestore rf - )"


 if ((i==slice_root))
 then
  P "# modify files on root for bootability"

  x=
  for j in $slice_root $slices_otherfs $slices_swap
  do
   x=$x$j
  done

  cat <<PPP >>$sdmscript
expand /etc/vfstab | \
  sed "s,/dev/md/dsk/d\([$x]\) ,/dev/dsk/${clondisk}s\1 ,"  | \
  sed "s,/dev/md/rdsk/d\([$x]\) ,/dev/rdsk/${clondisk}s\1 ," > /mnt_backup/etc/vfstab
grep -v rootdev /etc/system > /mnt_backup/etc/system
sed "s,$bootdisk,$clondisk," /etc/dumpadm.conf > /mnt_backup/etc/dumpadm.conf 
PPP

 fi

 P umount /mnt_backup
 P umount -f /dev/dsk/${clondisk}s$i
 P
done

echo
echo Script created : $sdmscript
echo

