#!/bin/sh
#
#ident "@(#)metacvt.sh   1.33     99/09/23 SMI"
#
# Copyright (c) 1992, 1993, 1994, 1995, 1996, 1998 by Sun Microsystems, Inc.
#

#
# Write a shell script that can restore the current metadevice
# configuration after it's been removed.  Then remove the metadevice
# configuration.
#

#
# Functions that simplify the scriptwriting and removal tasks
#

device_size()
{
    device=$1
    case $device in
	d*)
	    metastat $device | egrep -i 'size:' | awk '{print $2}'
	    ;;
	c*)
	    slice_size $device
	    ;;
    esac
}

get_boot_slice()
{
    device=$1
    metastat -p $device | merge_continued_lines | awk '{print $2;}' | \
    while read device_type ; do
        case $device_type in
            1)
                 get_stripe_mount_slice $device
                 ;;
            -m)
                 get_mirror_mount_slice $device
                 ;;
        esac
        break
    done
}

get_mirror_mount_slice()
{
    device=$1
    metastat -p $device | merge_continued_lines | while read line ; do
         set -- $line
         shift
         shift
         smallest_submirror=""
         min_submirror_size=""
         while [ $# -ne 0 ] ; do
            case $1 in
                d*)
                    submirror=$1
                    submirror_size=`device_size $submirror`
                    if [ -z "$smallest_submirror" ] ; then
                        smallest_submirror=$submirror
                        min_submirror_size=$submirror_size
                    elif [ $submirror_size -lt $min_submirror_size ] ; then
                        smallest_submirror=$submirror
                        min_submirror_size=$submirror_size
                    fi
                    ;;
            esac
            shift
        done
        get_stripe_mount_slice $smallest_submirror
        break
    done
}
 
get_mount_slice()
{
    device=$1
    metastat -p $device | merge_continued_lines | awk '{print $2;}' | \
    while read device_type ; do
        case $device_type in
            1)
                 get_stripe_mount_slice $device
                 ;;
            -m)
                 get_mirror_mount_slice $device
                 ;;
            -t)
                 get_trans_mount_slice $device
                 ;;
        esac
        break
    done
}

get_stripe_mount_slice()
{
    device=$1
    metastat -p $device | merge_continued_lines | egrep -e '^d[0-9]* 1 1 ' | \
    sed -e 's/^d[0-9]* 1 1 //'
}

get_trans_mount_slice()
{
    device=$1
    metastat -p $device | merge_continued_lines | awk '{print $3;}' | \
    while read master_device ; do
        case $master_device in
            c*)
                echo $master_device
                ;;
            d*)
                device_type=`metastat -p $master_device | awk '{print $2;}'`
                case $device_type in
                    1)
                        get_stripe_mount_slice $device
                        ;;
                   -m)
                        get_mirror_mount_slice $device
                        ;;
                esac
                ;;
        esac
        break
    done
}

merge_continued_lines()
{
    awk '\
    BEGIN { line = ""; } \
    $NF == "\\" { \
	$NF = ""; \
	line = line $0; \
	next; \
    } \
    $NF != "\\" { \
	if ( line != "" ) { \
	    print line $0; \
	    line = ""; \
	} else { \
	    print $0; \
	} \
    }'
}

slice_size()
{
    device=$1
    raw_device_path=/dev/rdsk/$device
    slice_number=`$expr $device : 'c[0-9]*.*d[0-9]*s\([0-9]*\)'`
    $prtvtoc -h $raw_device_path 2>&1 | \
        awk '$1 == '$slice_number' {print $5}'
}

#
# MAIN
#

PATH=/usr/sbin:$PATH
export PATH

userid=`id | sed -e 's/^uid=[0-9][0-9]*(//' -e 's/).*//'`
if [ "$userid" != "root" ] ; then
    echo "Only root can run this command."
    echo "Exiting."
    exit 1
fi

run_level=`who -r | sed -e 's/^.*run-level[ ]*//' -e 's/[ ].*$//'`
if [ "$run_level" != "S" ] ; then
    echo "You must run this command in single-user mode."
    echo "Exiting."
    exit 1
fi

echo "                    ***** CAUTION *****"
echo ""
echo "Back up all file systems before executing this command."
echo "This command removes all metadevices from the system."
echo ""
echo "If you don't want to do that, exit now."
echo ""
echo "Exit? y/n"


exit_choice=""
while [ -z "$exit_choice" ] ; do
    read exit_choice
    case $exit_choice in
        y)
            echo "Exiting."
            exit 0
            ;;
        n)
            : 
            ;;
        *)
            echo "Please enter y or n."
            exit_choice=""
            ;;
    esac
done


echo "Checking for error conditions that might lead to data loss "
echo "on restoration of the metadevice configuration."

metasync -r

metastat -p > /dev/null 2>&1
if [ $? -ne 0 ]; then
    echo "metastat detected one or more error conditions."
    echo "Check for configuration errors and failed devices."
    echo "Exiting."
    exit 1
fi

trouble=""
hsp=`metahs -i 2>/dev/null`
if [ $? -ne 0 ]; then
    metahs -i 2>&1 | grep 'no hotspare pools found' >/dev/null 2>&1
    if [ $? -ne 0 ] && [ ! -z "$hsp" ]; then
        trouble=`metahs -i | \
	    awk '$0 !~ /^hsp/ { if ( $2 !~ /\(?Available\)?/ ) print $0 }'`
    fi
    if [ ! -z "$trouble" ]; then
        echo ""
        echo "               ***** ERROR *****"
        echo ""
        echo "One or more of the hot spare drives is in use."
        echo "Correct that situation before rerunning this command."
        echo "Exiting."
        exit 1
    fi
fi

trouble=`metadb | tail +2 | awk '{ if ( $1 != "a" ) print $0 }'`
if [ ! -z "$trouble" ]; then
    echo ""
    echo "               ***** ERROR *****"
    echo ""
    echo "At least one metadb replica is not active."
    echo "Correct the situation before rerunning this command."
    echo "Exiting."
    exit 1
fi

trouble=`metastat | awk '/State:/ { if ( $2 != "Okay" ) print $0 }'`
if [ ! -z "$trouble" ]; then
    echo ""
    echo "               ***** ERROR *****"
    echo ""
    echo "At least one metadevice is in an error state."
    echo "Correct the situation before rerunning this command."
    echo "Exiting."
    exit 1
fi

cat /etc/vfstab | \
while read bdev rdev mp fsty fscp am mo; do
   case $bdev in
      "#"* | "")
         :
         ;;
      *)
         case $mp in
             "/")
                 echo $bdev | egrep '/dev/md' > /dev/null 2>&1
                 if [ $? -eq 0 ]; then
	            root_device=`echo $bdev | sed -e 's;/dev/md/dsk/;;'`
                    boot_slice=`get_boot_slice $root_device`
                    if [ -z "$boot_slice" ] ; then
                        echo ""
                        echo "             ***** ERROR *****"
                        echo ""
                        echo "Cannot convert the mount of $root_device on"
                        echo "the root file system into a single-slice mount."
                        echo "Convert $root_device to a mirror with simple"
                        echo "single-slice submirrors before rerunning this"
                        echo "command."
                        echo "Exiting."
                        exit 1
                    fi
                    metadb | sed -e '1d' | awk '{print $NF}' | \
                        sed -e 's;.*/;;' | sort | \
                        uniq | while read slice ; do
                            if [ "$slice" = "$boot_slice" ]; then
                                echo ""
                                echo "                      ***** ERROR *****"
                                echo ""
                                echo "Found metadb replicas on $slice, \c"
                                echo "which is the system boot slice."
                                echo "No metadb replicas may be located \c"
                                echo "on the system boot slice."
                                echo "Remove all replicas from $slice \c"
                                echo "before rerunning this command."
                                echo "Exiting."
                                exit 1
                            fi
                        done
                 fi
                 ;;
        esac
        ;;
   esac
done


if [ -f /etc/vfstab.slice ] ; then
    rm -f /etc/vfstab.slice
fi

export_root_mounted=no
if cat /etc/vfstab | egrep -e '/export/root' > /dev/null 2>&1 ; then
    export_root_mounted=yes
fi
export export_root_mounted

export_exec_mounted=no
if cat /etc/vfstab | egrep -e '/export/exec' > /dev/null 2>&1 ; then
    export_exec_mounted=yes
fi
export export_exec_mounted

cat /etc/vfstab | while read bdev rdev mp fsty fscp am mo ; do
    echo $bdev | grep '/dev/md' >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        echo "$bdev $rdev $mp $fsty $fscp $am $mo"
    elif [ "$mp" = "/" -o \
           "$mp" = "/usr" -o \
           "$mp" = "/usr/openwin" -o \
           "$mp" = "/var" -o \
           "$mp" = "/opt" -o \
           "$mp" = "/export/root" -o \
           "$mp" = "/export/exec" -o \
           \( "$mp" = "/export" -a -d /export/root -a \
              "$export_root_mounted" = "no" \) -o \
           \( "$mp" = "/export" -a -d /export/exec -a \
              "$export_exec_mounted" = "no" \) -o \
           "$fsty" = "swap" ]; then

        device=`basename $bdev`
        mount_slice=`get_mount_slice $device`
        if [ -z "$mount_slice" ] ; then
            echo ""
            echo "                  ***** ERROR *****"
            echo ""
            echo "Cannot convert the mount of metadevice $device on $mp"
            echo "into a single-slice mount.  Before rerunning this command,"
            echo "convert $device to a mirror with simple single-slice"
            echo "submirrors, a logging device with a simple single-slice"
            echo "master device, or a logging device whose master device"
            echo "is a mirror with simple single-slice submirrors."
            echo "Exiting."
            exit 1
        fi
        metadb | sed -e '1d' | awk '{print $NF}' | \
            sed -e 's;.*/;;' | sort | uniq | while read slice ; do

            if [ "$slice" = "$mount_slice" ]; then
                echo ""
                echo "                     ***** ERROR *****"
                echo ""
                echo "Found metadb replicas on slice ${slice}, \c"
                echo "which is mounted on $mp."
                echo "No metadb replicas may be located \c"
                echo "on slices containing system files."
                echo "Remove all replicas from $slice \c"
                echo "before rerunning this command."
                echo "Exiting"
                exit 1
            fi
        done
        bdev=/dev/dsk/$mount_slice
        rdev=/dev/rdsk/$mount_slice
        echo "$bdev $rdev $mp $fsty $fscp $am $mo"
    fi
done					>> /etc/vfstab.slice

save_dir=/etc/lvm
if [ ! -d $save_dir -o ! -w $save_dir ]; then
    echo ""
    echo "               ***** ERROR *****"
    echo ""
    echo "Can't write the restore script to $save_dir;"
    echo "$save_dir either doesn't exist or is not writable."
    echo "Exiting."
    exit 1
fi

restore_script=${save_dir}/S94SUNWmd.cvt
export restore_script
if [ -f $restore_script ] ; then
    rm -f $restore_script
fi


echo "Writing"
echo ""
echo "$restore_script,"
echo ""
echo "which can be used to restore the metadevice configuration."
echo ""


cat <<'EOF'						>> $restore_script
#!/bin/sh

PATH=/usr/sbin:$PATH
export PATH

EOF

remove_host=`uname -n`
echo "remove_host=$remove_host"  			>> $restore_script
echo ""							>> $restore_script


echo "Writing the permission checks."


cat <<'EOF'       					>> $restore_script
echo "Checking permissions."

restore_host=`uname -n`
if [ $restore_host != $remove_host ] ; then
    echo "This script restores the DiskSuite configuration of $remove_host."
    echo "It must be run on that machine."
    echo "Exiting."
    exit 1
fi

userid=`id | sed -e 's/^uid=[0-9][0-9]*(//' -e 's/).*//'`
if [ "$userid" != "root" ] ; then
    echo "Only root can run this command."
    echo "Exiting."
    exit 1
fi

run_level=`who -r | sed -e 's/^.*run-level[ ]*//' -e 's/[ ].*$//'`
if [ "$run_level" != "S" ] ; then
    echo "You must run this command in single-user mode."
    echo "Exiting."
    exit 1
fi

EOF


echo "Writing commands that recreate /kernel/drv/md.conf."


cat <<'EOF'						>> $restore_script
echo "Recreating /kernel/drv/md.conf."

cat <<'EOF'		> /kernel/drv.md.conf
EOF

cat /kernel/drv/md.conf					>> $restore_script
echo "EOF"						>> $restore_script
echo ""							>> $restore_script


echo "Writing commands that recreate the metadb replicas."


cat <<'EOF'      					>> $restore_script
echo "Recreating the metadb replicas."

EOF

metadb | sed -e '1d' | awk '{print $NF, $(NF - 1)}' | \
    sed -e 's;.*/;;' | sort | awk ' \
    BEGIN { replica = ""; force = "f"; } \
    { \
	if ( replica == "" ) { \
	    replica = $0; \
	    count = 1; \
	    next; \
	} else if ( $0 == replica ) { \
	    count++; \
	    next; \
	} \
        n = split(replica, slice_and_size); \
        slice = slice_and_size[1]; \
        size = slice_and_size[2]; \
        printf "metadb -a%s -l %d -c %d %s\n", force, size, count, slice; \
        force = ""; \
        replica = $0; \
        count = 1; \
    } \
    END { \
        n = split(replica, slice_and_size); \
        slice = slice_and_size[1]; \
        size = slice_and_size[2]; \
        printf "metadb -a%s -l %d -c %d %s\n", force, size, count, slice; \
    } '							>> $restore_script

echo ""                                                 >> $restore_script


echo "Writing commands that recreate the metadevices."


cat <<'EOF'						>> $restore_script
echo "Recreating the metadevices."

cat <<'EOF'	> /etc/lvm/md.tab
EOF

metastat -p | sed -e '/^WARNING:/d' | merge_continued_lines | \
sed -e 's;/dev/dsk/;;g' -e 's;/dev/rdsk;;g' | \
while read line; do
    set -- $line
    device_name=$1
    shift
    device_type=$1
    shift
    case $device_type in
        [0-9]*)
	    echo $line					>> $restore_script
	    ;;
        c*)
	    echo $line					>> $restore_script
	    ;;
	-m)
            hot_spare_option=""
	    min_subdevice_size=""
	    smallest_subdevice=""
	    while [ $# -ne 0 ]; do
		case $1 in
		    d*)
                        subdevice=$1
			subdevice_size=`device_size $subdevice`
			if [ -z "$min_subdevice_size" ]; then
			    min_subdevice_size=$subdevice_size
			    smallest_subdevice=$subdevice
			elif [ $subdevice_size -lt $min_subdevice_size ]; then
			    min_subdevice_size=$subdevice_size
			    smallest_subdevice=$subdevice
			fi
			;;
                    -h)
                        shift
                        hot_spare_option="-h $1"
                        ;;
		esac
                shift
	    done
	    echo "$device_name -m $smallest_subdevice $hot_spare_option" \
						 	>> $restore_script
            ;;
	-r)
	    parameters=""
	    while [ $# -ne 0 ]; do
	        case $1 in
		    -k)
                        :
			;;
                    *)
			[ -z "$parameters" ] && parameters=$1 || 
                        parameters="$parameters $1"
			;;
		esac
		shift
            done
            echo "$device_name -r $parameters -k"	>> $restore_script
            ;;
        -t)	
	    echo $line					>> $restore_script
            ;;
    esac
done
echo "EOF"                                              >> $restore_script
echo ""                                                 >> $restore_script
echo "metainit -af"                                     >> $restore_script
echo ""                                                 >> $restore_script


echo "Writing commands that recreate /etc/vfstab."


cat <<'EOF'						>> $restore_script
echo "Installing the metadevice version of /etc/vfstab."

cat <<'EOF' > /etc/vfstab
EOF

cat /etc/vfstab                                         >> $restore_script
echo "EOF"						>> $restore_script
echo ""                                                 >> $restore_script


echo "Checking to see if a metadevice is mounted on the root file system."


cat /etc/vfstab | \
while read bdev rdev mp fsty fscp am mo; do
   case $bdev in
      "#"* | "")
         :
         ;;
      *)
         case $mp in
             "/")
                 echo $bdev | egrep '/dev/md' > /dev/null 2>&1
                 if [ $? -eq 0 ]; then
	            root_device=`echo $bdev | sed -e 's;/dev/md/dsk/;;'`
                    echo "Found a metadevice mounted on the root file system."
                    echo "Adding a metaroot command."
                    echo "echo \"Mounting $root_device on the root \c" \
		                                        >> $restore_script
                    echo "file system.\""               >> $restore_script
                    echo ""   				>> $restore_script
                    echo "metaroot $root_device"	>> $restore_script
                    echo ""      	                >> $restore_script
                 fi
                 ;;
         esac
         ;;
    esac
done


echo "Checking for submirrors that will need to be reattached."


if metastat -p | merge_continued_lines | \
    egrep -e '-m[ 	]+d.*[ 	]+d.*' > /dev/null 2>&1; then

   echo "Found submirrors, writing the reattach commands."

#
# Write commands to S94SUNWmd.cvt that create an rc script in
# /etc/rc2.d.  The rc script executes another script called
# /usr/sbin/metareattach that reattaches the submirrors
#

   cat <<'EOF'						>> $restore_script
echo "Installing a script that automatically reattaches the remaining"
echo "submirrors when the machine reboots, and disables itself for"
echo "later reboots."

rc_script=/etc/rc2.d/S94SUNWmd.reattach

if [ -f $rc_script ]; then
   rm -f $rc_script
fi

cat <<'EOF'				> $rc_script
#!/bin/sh

reattach_script=/usr/sbin/metareattach

if [ -x $reattach_script ]; then
   $reattach_script
   rm -f $reattach_script
fi

EOF

   echo "EOF"						>> $restore_script
   cat <<'EOF'						>> $restore_script

chmod 744 $rc_script

EOF

#
# Write commands to S94SUNWmd.cvt that create
# /usr/sbin/metareattach
#

   cat <<'EOF'						>> $restore_script
reattach_script=/usr/sbin/metareattach

if [ -f $reattach_script ]; then
   rm -f $reattach_script
fi

cat <<'EOF'				> $reattach_script
#!/bin/sh

PATH=/usr/sbin:$PATH
export PATH

resyncwait()
{
   echo "Waiting for $2 to resync with $1."
   progress_message=`metastat $1 2>&1 | \
       egrep -i resync | egrep -v -i state`
   while [ ! -z "$progress_message" ]; do
       echo "$progress_message."
       sleep 60
       progress_message=`metastat $1 2>&1 | \
           egrep -i resync | egrep -v -i state`    
   done
   echo "Done."
}

reattach()
{
   mirror=$1
   shift
   while [ $# -ne 0 ]; do
      submirror=$1
      echo "Reattaching submirror $submirror to mirror $mirror."
      metattach $mirror $submirror
      shift
      if [ $# -ne 0 ]; then
          resyncwait $mirror $submirror
      fi
   done
}

EOF

   metastat -p | sed -e '/^WARNING:/d' | merge_continued_lines | \
   sed -e 's;/dev/dsk/;;g' -e 's;/dev/rdsk;;g' | \
   while read line; do
      set -- $line
      device_name=$1
      shift
      device_type=$1
      shift
      case $device_type in
	 -m)
	     smallest_submirror=""
	     min_submirror_size=""
	     for submirror in $*; do
		case $submirror in
		   d*)
		       submirror_size=`device_size $submirror`
		       if [ -z "$min_submirror_size" ]; then
			   min_submirror_size=$submirror_size
			   smallest_submirror=$submirror
		       elif [ $submirror_size -lt $min_submirror_size ]; then
                          min_submirror_size=$submirror_size
			  smallest_submirror=$submirror
		       fi
		       ;;
		esac
	     done
             other_submirrors=""
             for submirror in $*; do
                case $submirror in
		   d*)
		      if [ "$submirror" != "$smallest_submirror" ]; then
			[ -z "$other_submirrors" ] &&
			 other_submirrors="$submirror" || 
                         other_submirrors="$other_submirrors $submirror"
       		      fi
		      ;;
                esac
             done
             if [ ! -z "$other_submirrors" ]; then
                 echo "reattach $device_name $other_submirrors" \
							>> $restore_script
             fi
          ;;
      esac
   done

   echo ""						>> $restore_script
   echo "EOF"    					>> $restore_script

   cat <<'EOF'						>> $restore_script

chmod 744 $reattach_script

EOF
fi


echo "Adding the lockfs command."

cat <<'EOF'						>> $restore_script
echo "Flushing in core file system buffers."

lockfs -af

echo ""
echo "                         ***** ATTENTION *****"
echo ""
echo "You must now reboot the system to restore and remount the metadevices."
echo ""

exit 0

EOF

chmod 744 $restore_script


echo ""
echo "Done writing"
echo ""
echo "$restore_script"
echo ""


cat /etc/vfstab | \
while read bdev rdev mp fsty fscp am mo; do
   case $bdev in
      "#"* | "")
         :
         ;;
      *)
         case $mp in
             "/")
                 echo $bdev | egrep '/dev/md' > /dev/null 2>&1
                 if [ $? -eq 0 ]; then
	            root_device=`echo $bdev | sed -e 's;/dev/md/dsk/;;'`
                    boot_slice=`get_boot_slice $root_device`
                    echo "Changing the boot device to $boot_slice."
                    metaroot $boot_slice
                 fi
                 ;;
         esac
         ;;
    esac
done


echo "Replacing metadevice mounts on /usr /usr/openwin, /var, /opt,"
echo "/export/root, and /export/exec with single-slice mounts,"
echo "and removing all other metadevice mounts from /etc/vfstab."


mv /etc/vfstab /etc/vfstab.md
mv /etc/vfstab.slice /etc/vfstab


echo "Deleting the metadb replicas."


metadb | sed -e '1d' | awk '{print $NF}' | sed -e 's;.*/;;' | sort | \
    uniq | while read slice ; do
        metadb -df $slice
    done


echo "Flushing in core file system buffers."


lockfs -af

echo ""
echo "                               ***** CAUTION *****"
echo ""
echo "PLEASE NOTE THE FOLLOWING POINTS:"
echo ""
echo "1. Before rebooting the system, make a backup copy of"
echo ""
echo "   $restore_script"
echo ""
echo "   that you can use to restore the metadevices after rebooting or"
echo "   upgrading."
echo ""
echo "2. Don't change the system's hardware configuration or write to file"
echo "   systems on which striped or concatenated metadevices have been mounted"
echo "   before running"
echo ""
echo "   $restore_script"
echo ""
echo "3. Don't change the sizes of disk partitions that are used in metadevices."
echo "   In particular, don't run upgrades that change the sizes of slices used"
echo "   in metadevices."
echo "" 
echo "4. You must reboot the system to remove the metadevice configuration data" 
echo "   from system memory and unmount the metadevices."
exit 0
