#!/bin/ksh
# $Id: vxconfigbackupd.sh,v 1.1.2.2 2003/03/20 17:12:05 girish Exp $
#ident "$Source: /project/unixvm-cvs/src/sol/cmd/vxvm/support/Attic/vxconfigbackupd.sh,v $"

# Copyright (c) 2001 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

#
############# Daemon to Backup VxVM Configuration Changes ##################
#

#
# Command and argument defaults
#
DCMD=`basename $0`
CFGDIR=/etc/vx/dgcfg
NBKUPS=5
RMCFG=0
DGS=
ALLDGS=

trap "" HUP QUIT INT USR1 USR2 TTIN TTOU
trap "pkill -TERM -P $$ vxnotify" TERM

usage()
{
	echo \
"Usage: $DCMD [ -d dir ] [ -n num ] [ -R ] [ dg_name ... ]"
        quitd 1;
}

#
# Stuff the message with timestamp and route it to console device
#
msglog()
{
	echo \
"`date '+%b %e %T'` `uname -n` $DCMD: $*" >/dev/console 2>/dev/null
}

#
# Perform sanity checks to validate the command line arguments
# Set variables/directory 
#
validate_set_args()
{
	[ $NBKUPS -le 25 -a $NBKUPS -gt 0 ] 2>/dev/null;
	[ $? -ne 0 ] && quitd 2;

	dglist=`vxprint -GnA 2>/dev/null`;
	if [ ! -z "$DGS" ]; then
		# user specified diskgroup(s) on the command line
		ALLDGS=no
		for dg in $DGS; do 
			echo "$dglist" | grep -w "$dg" 2>/dev/null 1>&2;
			[ $? -ne 0 ] && quitd 3;
		done
	else
		DGS="$dglist"
	fi

	# treat the directory path as absolute, so prefix it with slash
	( mkdir -p /$CFGDIR && touch /$CFGDIR 2>/dev/null ) || quitd 4;
	cd /$CFGDIR; CFGDIR=`pwd`; 

	# remove leftover tmp files (if any) from previous daemon session
	rm -f $CFGDIR/._tmpdg* $CFGDIR/._tmp*.1*
}

#
# Quit daemon with non-zero status on fatal error
#
quitd()
{
        case $1 in
	1)	;;
        2)	msglog \
"ERROR: Invalid or out of range count specified"
		;;
        3)	msglog \
"ERROR: Diskgroup(s) specified not found or imported"
		;;
        4)	msglog \
"ERROR: Write permission to backup directory denied"
		;;
        5)	msglog \
"ERROR: Another instance of daemon is already running"
		;;
        esac
        exit $1;
}

#
# If only select diskgroups configuration is asked for, dglist (DGS)
# is statically maintained otherwise it is updated dynamically
#
# Hunt a diskgroup in the diskgroup list and return status
#
hunt_dg_dglist()
{
        [ "X$ALLDGS" = "Xno" ] && {
                echo "$DGS" | grep -w "$1" 2>/dev/null 1>&2
                return $?
        }
	return 0
}

#
# Analyze DG config change event and decide to do write_dg_config or not
# 
record_change() 
{
	#
	# ____Possible notification formats____
	# change disk accessname dm medianame dg groupname dgid groupid
	# change dg groupname dgid groupid
	#

        set -- $*
        object_type=$1
        object_dg=
	case "$object_type" in
		disk)   shift 5; object_dg=$1 ;;
		dg) 	shift 1; object_dg=$1 ;;
	esac

	[ "$object_dg" = "-" ] && return

	hunt_dg_dglist "$object_dg" || return
	write_dg_config "$object_dg"
}

#
# Record all diskgroup configuration changes when we are not sure about
# exactly which diskgroup's object(s) underwent change. For instance: A
# 'vxdg flush' operation does not report the DG info in the 'change' 
# notification and also it could act upon multiple diskgroups
#
record_all_changes()
{
        [ "X$ALLDGS" = "Xno" ] || DGS=`vxprint -GnA 2>/dev/null`
	for dg in $DGS; do
		write_dg_config "$dg"
	done
}

#
# Select available compression utility
#
sel_compression_util()
{
	CAT=/usr/bin/cat
	[ -x /usr/bin/gzip ] && eval $1=/usr/bin/gzip && return;
	[ -x /usr/bin/compress ] && eval $1=/usr/bin/compress && return;
	eval $1=$CAT
}

#
# Compare and write the changed configuration into compressed 
# vxmake description format
#
write_dg_config()
{
	ret=0; dg=$1;
	( touch $CFGDIR/._tmpdg$$ &&
	  vxprint -g $dg -m >$CFGDIR/._tmpdg$$ ) 2>/dev/null
	[ $? -ne 0 ] &&  { 
		rm -f $CFGDIR/._tmpdg$$
		return
	}
	sel_compression_util CUTIL 
	[ -f "$CFGDIR/${dg}.1" ] && {
		# deflate if possible
		$CUTIL -d <$CFGDIR/${dg}.1>$CFGDIR/._tmp${dg}.1$$ 2>/dev/null\
		|| $CAT <$CFGDIR/${dg}.1>$CFGDIR/._tmp${dg}.1$$ 2>/dev/null 
		cmp -s $CFGDIR/._tmpdg$$ $CFGDIR/._tmp${dg}.1$$
		if [ $? -ne 0 ]; then
			suffix=`expr $NBKUPS - 1`;
			while [ $suffix -gt 0 ]; do
			    mv -f $CFGDIR/${dg}.${suffix} \
			      $CFGDIR/${dg}.`expr $suffix + 1` 2>/dev/null
			    suffix=`expr $suffix - 1`
			done
		else
			ret=1
		fi
	}
	[ $ret -eq 0 ] && {
		$CUTIL < $CFGDIR/._tmpdg$$ > $CFGDIR/._tmp${dg}.1$$ &&
		mv -f $CFGDIR/._tmp${dg}.1$$ $CFGDIR/${dg}.1 2>/dev/null
		[ $? -ne 0 ] && msglog \
"WARNING: failed to move backup files, configuration logging skipped for $dg"
	}
	rm -f $CFGDIR/._tmpdg$$ $CFGDIR/._tmp${dg}.1$$
}

#
# Remove deported DG configuration or move it to deport folder
#
record_deport() 
{
        set -- $*
        object_type=$1
	shift 1
	object_dg=$1

	hunt_dg_dglist "$object_dg" || return
	if [ $RMCFG -eq 0 ]; then
		mkdir -p $CFGDIR/deport 2>/dev/null &&
		mv -f $CFGDIR/${object_dg}.* $CFGDIR/deport 2>/dev/null
                [ $? -eq 0 ] && touch $CFGDIR/deport 2>/dev/null 1>&2
	else
		[ ! -z "$object_dg" ] && rm -f $CFGDIR/${object_dg}.*
	fi
}

#
# Allow only single instance of daemon to run
#
[ "`ps -ef | grep -c $DCMD`" -gt 2 ] && quitd 5;

while getopts ":d:Rn:" opt
do
	case $opt in
	d)      CFGDIR=$OPTARG ;;
	n)      NBKUPS=$OPTARG ;;
	R)	RMCFG=1 ;;
	?)      usage ;;
	esac
done
shift `expr $OPTIND - 1`
DGS=$*

validate_set_args

# Daemon has just started, write configuration info for all dgs
record_all_changes

#
# Monitor and process {'change', 'deport'} notifications from vxnotify
#
vxnotify | while read code more
do
	case $code in
		change) changerec="`echo $more| grep -v \"dgid -\"`"
			[ -z "$changerec" ] && record_all_changes && continue
			record_change "$changerec"
			;;
		deport) record_deport $more 
			;;
	esac
done 
msglog "Diskgroup configuration backup daemon stopped"
