#!/bin/sh

#set -v
#set -n

SHELL=/bin/sh
export SHELL

######################################################################
# 
# Script for backing up clearcase VOBs with Legato.  Based on Dave
# Chapple's scripts for doing the backup to local tapes, along with the
# script posted by Mark Paz (mpaz@informix.com).
#
# $Id: savevobs,v 2.6 1999/03/10 23:04:33 john Exp $
#
# $Log: savevobs,v $
# Revision 2.6  1999/03/10 23:04:33  john
# - yet another minor bug fix, not sure what really went wrong here.
# - commented out some of the experimental code for removing log files
#   based on the status.  Try this next time.
#
# Revision 2.5  1999/03/10 20:30:56  john
# - fixed bug with missing " in if statement.
#
# Revision 2.4  1999/03/09 16:30:15  john
# changed the lockvobs{} function to select only local hosts and to make
# sure we get *all* VOBs on the server, even if they aren't mounted on
# the server.
#
# Revision 2.3  1999/02/17 15:28:46  john
# - final merge of the 2.1 and 2.0.1.1 versions to make sure I'm back to
#   just one branch.
#
# Revision 2.2  1999/02/17 14:46:18  john
# - merge of version 2.0.1.1 and 2.1 and me learning about rcsmerge.  
#
# Revision 2.1  1999/02/17 14:31:59  john
# - start of support for trapping errors and handling them more gracefully
# - now tries to re-make a mirror if there's only one sub-mirror so that
#   it can then break the mirror again to do a backup.
#
# Revision 2.0  1999/02/12 19:16:06  john
# lots of big changes to this version
# - now broken up into functions
# - start of support for traps, so we can die and exit cleanly
#   - if we exit when VOBs are locked, unlock
#   - if we exit when VOLUMES are un-mirrored, re-mirror
#
# - now supports VOBs on mirror ODS volumes.
#
# Revision 1.1  1999/01/07 15:09:22  john
# Initial revision
#
# See the
# http://engineering.casc.com:8080/sysadmin/admindocs/vob-backup.html for
# full details of this script.

######################################################################
log()
{
    echo $@ >> ${LOG} 2>&1
}

######################################################################
initialize() 
{
    BV="savevob$$"
    
    ###### Setup where we are and how we were called as a command.
    
    case $0 in
    /*)
PATH=/opt/vxva/bin:/usr/atria/bin:/usr/sbin:/bin:/usr/bin:`/bin/dirname $0`
	c=`/bin/basename $0`
	;;
    /*) PATH=/opt/vxva/bin:/usr/atria/bin:/usr/sbin:/bin:/usr/bin
	c=$0
	;;
    esac
    export PATH	
    
    UNMIRRORED=0
    VOBSLOCKED=0
    MOUNTED=0

    ###### Valid savegroup statuses (See tech bulletin 306 from legato)
    
    statuses="
    
    failed.
    
    abandoned.
    
    succeeded.
    
    completed savetime=
    
    "
}

######################################################################
#
# This is unused at the present time.  6/8/1999
#
# trapper() 
# {
#     echo "" >> ${LOG}
#     echo "Trapper called!" >> ${LOG}
#     echo "  VOBSLOCKED:  ${VOBSLOCKED}" >> ${LOG}
#     echo "  MOUNTED:     ${MOUNTED}" >> ${LOG}
#     echo "  UNMIRRORED:  ${UNMIRRORED}" >> ${LOG}
#     echo "" >> ${LOG}
#
#     if [ ${VOBSLOCKED} eq 1 ]; then
# 	unlockvobs
#     fi
#
#     if [ ${MOUNTED} eq 1 ]; then
# 	unmountbackvol
#     fi
#
#     if [ ${UNMIRRORED} eq 1 ]; then
# 	make_mirror
#     fi
# }
#
######################################################################
reattach_mirror()
{
    reattach_result=0
}

######################################################################
loginit()
{
    ###### setup the log files

    if [ ! -d /tmp/savevobs ]; then
		mkdir /tmp/savevobs
		echo "${c}: mkdir /tmp/savevobs" >> ${LOG} 2>&1
    fi
    
    umask 002
    
    LOG="/tmp/savevobs/$c.$$"
    touch ${LOG} >> ${LOG} 2>&1
    
    SAVELOG="/tmp/savevobs/$c-save.$$"
    touch ${SAVELOG} >> ${LOG} 2>&1
    
    ###### print message into log
    
    echo "command: $0"  >> ${LOG}
    echo "${c}": backup started at `date`  >> ${LOG}
    echo "" >> ${LOG}
}

######################################################################
parse_filesystem() 
{
    
    ###### This is the filesystem we want to backup on this invocation,
    ###### without _backup appended.  
        
    MOUNT=`echo "$@" | /bin/awk '{ print $NF }'`
    FILESYS=`echo ${MOUNT} | /bin/sed -e 's/_backup//'`
    MACHINE=`uname -n`
    
    if [ "${MOUNT}" = "${FILESYS}" ]; then
        echo "Error! You must specify ${FILESYS}_backup in Networker" >> ${LOG}
        echo "save for ${FILESYS} failed." >> ${LOG}
        echo "save for ${FILESYS} failed."
        exit 127
        exit 127
        exit 127
    fi
}

######################################################################
find_volume() 
{
    ###### get the volume type and the $FILESYS is mounted on, it's
    ###### always the last part of the device string.  Could have used
    ###### basename here.
    
    BASEVOL=`mount|grep "${FILESYS} "|/bin/awk '{ print $3 }'`
    VOLTYPE=`echo ${BASEVOL} | /bin/awk -F'/' '{ print $3 }'`
    VOL=`echo ${BASEVOL} |/bin/awk -F'/' '{ print $NF }'`

    case ${VOLTYPE} in

    vx) 
        ###### now get the diskgroup that the veritas volume is part of
        DISKGRP=`vxprint ${VOL} | /bin/grep "Disk group:" | /bin/awk '{print $3 }'`
    
        ###### we want the last element in the plex, and we check to make sure
        ###### there are at least two plexes in the volume.
        
        PLEX=`/usr/sbin/vxinfo -p ${VOL}|tail -1|/bin/awk '{ print $2 }'`
        NUMMIR=`/usr/sbin/vxinfo -p ${VOL}|egrep "plex.*ACTIVE"|wc -l|sed 's/ //g'`
        
        # We need the length of the plex if it has two or more sub-disks.
            LEN=`/usr/sbin/vxprint -l ${PLEX} | grep info | /bin/awk -F"=" '{ print $3 }'`
        ;;
    md)
        MIRROR=${VOL}
        SUBMIRROR=`/usr/opt/SUNWmd/sbin/metastat ${VOL} | egrep "Submirror " | grep -v "Submirror of" | tail -1 | awk '{ print $3 }'`
        
        NUMMIR=`/usr/opt/SUNWmd/sbin/metastat ${VOL} | egrep "Submirror " | grep -v "Submirror of" | wc -l | sed 's/ //g'`
        ;;
    esac
        
    echo "MOUNT:      ${MOUNT}" >> ${LOG}
    echo "FILESYS:    ${FILESYS}" >> ${LOG}
    echo "VOLTYPE:    ${VOLTYPE}" >> ${LOG} 
    echo "NUMMIR:     ${NUMMIR}" >> ${LOG}

    case ${VOLTYPE} in
    vx)
        echo "DISKGRP:    ${DISKGRP}" >> ${LOG}
        echo "VOL:        ${VOL}" >> ${LOG} 
        echo "PLEX:       ${PLEX}" >> ${LOG}
        echo "LEN:        ${LEN}" >> ${LOG} 
        ;;
    md)
        echo "MIRROR:     ${MIRROR}" >> ${LOG}
        echo "SUBMIRROR:  ${SUBMIRROR}" >> ${LOG}
        ;;
    *)
        echo "Error!  Unknown volume type: ${VOLTYPE}" >> ${LOG}
        echo "Error!  Unknown volume type: ${VOLTYPE}"
        echo "save for ${FILESYS} failed."
        exit 127
	echo "trying to exit 127"
        exit 127
	echo "still trying to exit 127"
        exit 127
	echo "third try unlucky trying to exit 127"
        ;;
    esac

    # make sure we have at least two plexes in the volume, otherwise croak.
    
    if [ "${NUMMIR}" -lt 2 ]; then
        echo "Error! You only have ${NUMMIR} submirror in the volume ${VOL}" >> ${LOG}
        if [ "${NUMMIR}" -eq 1 ]; then
            result = reattach_mirror
            
            if [ "${result}" -ne 0 ]; then
                log "Failed to re-attach mirror!"
                echo "Failed to re-attach mirror!"
		echo "save for ${FILESYS} failed."
		exit 127
            fi
        else
            log "Exiting save, we have no mirrors at all"
            echo "Exiting save, we have no mirrors at all"
	    echo "save for ${FILESYS} failed."
	    exit 127
        fi

        echo "save for ${FILESYS} failed." >> ${LOG}
	exit 127

    fi
    echo ""  >> ${LOG}
}

######################################################################
lockvobs() 
{
    VOBS=`/usr/atria/bin/cleartool lsvob -host ${MACHINE} | /bin/cut -c 3- | /bin/grep ${FILESYS} | /bin/awk '{ print $2 }'`
    echo `date` - ${c}: Locking VOBS... >> ${LOG} 2>&1
    for VOBSLOCK in ${VOBS}
    do
        echo "   ${VOBSLOCK}" >> ${LOG}
        /usr/atria/bin/cleartool lock -vob ${VOBSLOCK} >> ${LOG} 2>&1
    done

    VOBSLOCKED=1

    echo `date` - ${c}: All VOBS locked >> ${LOG} 2>&1e
    echo "" >> ${LOG}
}

######################################################################
break_mirror_ods() 
{
    echo "  lockfs... -w ${FILESYS}" >> ${LOG}
    /usr/sbin/lockfs -w ${FILESYS} >> ${LOG} 2>&1

    echo "  metaoffline... ${MIRROR} ${SUBMIRROR}" >> ${LOG}
    /usr/opt/SUNWmd/sbin/metaoffline ${MIRROR} ${SUBMIRROR} >> ${LOG} 2>&1

    result=$?

    echo "  lockfs... -u" >> ${LOG}
    /usr/sbin/lockfs -u ${FILESYS} >> ${LOG} 2>&1
    
    if [ ${result} -eq 0 ]; then
		touch /tmp/savevobs/metaoffline.$$.${MIRROR}
		touch /tmp/savevobs/metaoffline.$$.${SUBMIRROR}
		echo "touched metaoffline status files..." >> ${LOG}
	fi

    if [ ${result} -ne 0 ]; then
		echo "" >> ${LOG}
		echo "Error!  Metaoffline had an error: ${result}" >> ${LOG}
    fi
}

######################################################################
break_mirror_vxvm() 
{
    ###### vobs are locked, break mirror

    echo "Sync the disks" >> ${LOG}  2>&1
    sync >> ${LOG} 2>&1
    sync >> ${LOG} 2>&1
    sync >> ${LOG} 2>&1
    /usr/sbin/ssaadm sync_cache /devices/sbus*/SUNW,soc*/*ctlr >> ${LOG} 2>&1
			    
    echo "" >> ${LOG}
    echo `date` - ${c}: Breaking the mirror >> ${LOG} 2>&1
    
    echo "  vxplex... -g ${DISKGRP} dis ${PLEX}" >> ${LOG}
    /usr/sbin/vxplex -g ${DISKGRP} dis ${PLEX}  >> ${LOG} 2>&1
}

######################################################################
break_mirror() 
{
    case ${VOLTYPE} in
    vx)
	break_mirror_vxvm
	;;
    md)
    	break_mirror_ods
	;;
    esac

    UNMIRRORED=1

}

######################################################################
unlockvobs() 
{
    ######## now unlock the vobs
    
    echo "" >> ${LOG}
    echo `date` - ${c}: Unlocking the VOBS... >> ${LOG} 2>&1
    for VOBSLOCK in ${VOBS}
    do
		echo "  ${VOBSLOCK}" >> ${LOG} 2>&1
		/usr/atria/bin/cleartool unlock -vob ${VOBSLOCK} >> ${LOG} 2>&1
    done

    VOBSLOCKED=0

    echo `date` - ${c}: All VOBS unlocked >> ${LOG} 2>&1e

}

######################################################################
makebackvol_vxvm() 
{
    # create the temporary volume, though be carefull
    # to create a unique volume name for the backup because we can
    # have multiple versions of this script running at once.

    echo "" >> ${LOG} 2>&1
    echo `date` - ${c}: Creating ${BV} volume >> ${LOG} 2>&1
    
    echo "  vxmake..." >> ${LOG}
    /usr/sbin/vxmake -U fsgen -g ${DISKGRP} vol ${BV} plex=${PLEX} len=${LEN} >> ${LOG} 2>&1

    echo "  vxvol..." >> ${LOG}
    /usr/sbin/vxvol -g ${DISKGRP} start ${BV}  >> ${LOG} 2>&1
    
    # we need to fsck because even though we lock the VOBs on the disk,
    # there might be other filesystem accesses happening at the same time.
    # We need to get VxFS working on these systems as well to get real
    # secure backups.  
    
    echo "  fsck..." >> ${LOG} 2>&1
    /etc/fsck -y /dev/vx/rdsk/${DISKGRP}/${BV} >> ${LOG} 2>&1

}    

######################################################################
makebackvol_ods()
{
    echo "  fsck..." >> ${LOG} 2>&1
    /etc/fsck -y /dev/md/rdsk/${SUBMIRROR} >> ${LOG} 2>&1
}

######################################################################
makebackvol()
{
    case ${VOLTYPE} in 
    vx)
	makebackvol_vxvm
	;;
    md)
	makebackvol_ods
	;;
    esac
}

######################################################################
mountbackvol() 
{
    ##### Make sure we have a directory we can mount on.
    
    if [ ! -d ${MOUNT} -a ! -f ${MOUNT} ]; then
	    mkdir ${MOUNT} >> ${LOG} 2>&1 ;
    elif [ -f ${MOUNT} ]; then
	    mv ${MOUNT} ${MOUNT}.orig  >> ${LOG} 2>&1
	    mkdir ${MOUNT} >> ${LOG} 2>&1 ;
    fi
    
    # mount the filesystem readonly
    
    echo "  mount..." >> ${LOG}
	
    case ${VOLTYPE} in
    vx)
	/usr/sbin/mount -r /dev/vx/dsk/${DISKGRP}/${BV} ${MOUNT} >> ${LOG} 2>&1
	;;
    md)
	/usr/sbin/mount -r /dev/md/dsk/${SUBMIRROR} ${MOUNT} >> ${LOG} 2>&1
	;;
    esac

    MOUNTED=1
}

######################################################################
nsrsave()
{
    # call the real NSR save program to save the data.  See Leagto
    # Tech Bulletin 306 for whats happening here.

    echo "" >> ${LOG}
    echo `date` - ${c}:  Starting save... >> ${LOG}
    
    save $* > ${SAVELOG} 2>&1
    
    cat ${SAVELOG}

    # do we want to cleanup the log files?
    rmlogs=0

    for i in ${statuses}
    do
	result=`grep "${i}" ${SAVELOG}`
	if [ $? != 0 ]; then
	    echo ${result}
# 	    case ${i} in
# 		failed)
# 		    rmlogs=`expr ${rmlogs} - 1`
# 		    ;;
# 	        abandon)
# 		    rmlogs=`expr ${rmlogs} - 1`
# 		    ;;
# 		succeeded)
# 		    rmlogs=`expr ${rmlogs} + 1`
# 		    ;;
# 		savetime=)
# 		    rmlogs=`expr ${rmlogs} + 1`
# 		    ;;
# 	    esac
	fi
    done
    
    echo "" >> ${LOG}
    echo `date` - ${c}:       ...save done >> ${LOG}
}

######################################################################
umountbackvol()
{
    echo "" >> ${LOG}
    echo "  umount... ${MOUNT}" >> ${LOG}
    /usr/sbin/umount ${MOUNT}
    
    MOUNTED=0

}

######################################################################
make_mirror_vxvm() 
{
    echo "" >> ${LOG}
    echo `date` - ${c}: Restoring mirror... >> ${LOG}
    
    echo "  vxvol stop..." >> ${LOG}
    /usr/sbin/vxvol -g ${DISKGRP} stop ${BV}  >> ${LOG} 2>&1
    
    echo "  vxplex dis..." >> ${LOG}
    /usr/sbin/vxplex -g ${DISKGRP} dis ${PLEX}  >> ${LOG} 2>&1
    
    echo "  vxedit rm..." >> ${LOG}
    /usr/sbin/vxedit -g ${DISKGRP} rm ${BV}  >> ${LOG} 2>&1
    
    echo "  vxplex att..." >> ${LOG}
    /usr/sbin/vxplex -g ${DISKGRP} -o iosize=128k att ${VOL} ${PLEX}  >> ${LOG} 2>&1
    echo `date` - ${c}:       ...done >> ${LOG}
    echo "" >> ${LOG}
}

######################################################################
make_mirror_ods() 
{
    echo "  metaonline... ${MIRROR} ${SUBMIRROR}" >> ${LOG}
    /usr/opt/SUNWmd/sbin/metaonline ${MIRROR} ${SUBMIRROR} >> ${LOG} 2>&1

    if [ $? -ne 0 ]; then
                echo "----------------------------------------" >> ${LOG}       
                echo "metaonline status: $?" >> ${LOG}
                echo "" >> ${LOG}
        
                /usr/opt/SUNWmd/sbin/metastat -t ${MIRROR} >> ${LOG} 2>&1
                echo "----------------------------------------" >> ${LOG}
    fi

        if [ $? -eq 0 ]; then
                rm /tmp/savevobs/metaoffline.$$.${MIRROR}
                rm /tmp/savevobs/metaoffline.$$.${SUBMIRROR}
                echo "  rm metaoffline status file..." >> ${LOG}
        fi

    echo `date` - ${c}:       ...done >> ${LOG}
    echo "" >> ${LOG}
}

######################################################################
make_mirror() 
{
    
    case ${VOLTYPE} in

    vx)
        make_mirror_vxvm
        ;;
    md)
        make_mirror_ods
        ;;
    esac

    UNMIRRORED=0
}

######################################################################
alldone()
{

    echo "--------------- end of log ----------------" >> ${LOG}
            
    cat ${LOG} ${SAVELOG} | /usr/bin/mailx -s "${MACHINE} - NSR VOB backup" john
        if [ ${rmlogs} -eq 1 ]; then
                /bin/rm ${LOG} ${SAVELOG}
        fi

    exit 0
}


######################################################################
# 
# Main section of code
#
######################################################################

initialize
loginit

parse_filesystem $@
find_volume $@

if [ $? != 0 ]; then
    exit 127
fi

lockvobs
break_mirror
unlockvobs

makebackvol
mountbackvol

nsrsave $@

umountbackvol

make_mirror

alldone
