#!/bin/sh
#
# Copyright (c) 1999 by Sun Microsystems, Inc.  All Rights Reserved
#
# @(#)sslogmgmt.sh	3.3 01/10/19 Sun Microsystems, Inc.
#
# SunScreen log retrieval processing
#
# Author: Marc S Dye

OSS=/opt/SUNWicg/SunScreen
SUNSCREEN_ETC=${SUNSCREEN_ETC:-/etc$OSS}
[ -z "$SUNSCREEN_BASE" -a -f $SUNSCREEN_ETC/location ] \
  &&  read SUNSCREEN_BASE <$SUNSCREEN_ETC/location
SUNSCREEN_BASE=${SUNSCREEN_BASE:-$OSS}
. $SUNSCREEN_BASE/bin/.ssenv.profile

PATH=$BIN_DIR:/usr/bin:/bin ; export PATH
ME=sslogmgmt
MEG=1048576

# commands used
SSADM=ssadm
STRS="$SSADM -n lib/strs"
# things w/ vocal variants
SAY=: #echo
DOITg=
##$SAY 
DOITx=
##$SAY
DOITz=
##$SAY

# -v			be verbose
# -C			clear the log on (successful) get
# -Z			'compress(1)' the gotten logs
# -f <filter-expr>	add the given filter expression for filtering
# -F <macro-name>	expand and add the given log macro for filtering
# -o <dest-dir>		use the named destination directory for gotten logs
# -P <passwd-file>	screen / user / password file
# -s <space-param>	control gets based on log size
# -S <localspace>	required local filespace before attempting each get
# -X <script-spec>	invoke the given script on the results of each get;
#			may have options attached, after a space
# <screen>		include <screen> in the set of screens to be
#			retrieved

SMSG=`$STRS 1 1910 "screen"`

usage () {
	U=`$STRS 1 2180 "usage"`	
	F=`$STRS 1 640 "filter-expr"`
	M=`$STRS 1 1304 "macro-name"`
	D=`$STRS 1 440 "dest-dir"`
	P=`$STRS 1 1610 "passwd-file"`
	L=`$STRS 1 1240 "local-space"`
	S=`$STRS 1 1950 "space-param"`
	X=`$STRS 1 1912 "script-spec"`
	echo "$U: [-v] [-C] [-Z] [-f <$F>] [-F <$M>] [-o <$D>] \\" 1>&2
	echo "       [-P <$P>] [-s <$L>] [-S <$S>] \\" 1>&2
	echo "       [-X <$X>] [<$SMSG> ...]" 1>&2
	cleanup
	exit 1
}

# checkremotespace $SCRN $LSPC
checkremotespace () {
	if [ $RSPCT -lt 0 ] ; then
		T=-1		# won't be used
	# four calculations, based on sign and %age
	elif [ $RSPCT -eq 0 ] ; then
		if [ $RSPACE -ge 0 ] ; then
			T=$RSPACE
		else
			T=`expr $GETRSTAT_size_r + $RSPACE `
		fi
	elif [ $RSPACE -ge 0 ] ; then
		T=`echo $GETRSTAT_size_r $RSPACE \* 100 / p | dc`
	else
		R=`expr $RSPACE : '-\(.*\)'`
		T=`echo $GETRSTAT_size_r $GETRSTAT_size_r $R \* 100 / - p \
		  | dc`
	fi
	$SAY "checkremotespace: remote threshold => $T"
	if [ $T -lt 0 -o $GETRSTAT_used_r -ge $T ] ; then
		CHKRMTSPC_r=1		# get it
	else
		CHKRMTSPC_r=0		# don't get it
	fi
	if [ $CHKRMTSPC_r -gt 0 ] ; then
		F=`expr $2 - $GETRSTAT_used_r`
		if [ $F -le 0 ] ; then
			E=`$STRS 1 1252 "log could exceed free disk space"`
			L=$2
		elif [ $LSPACE -gt 0 -a $F -le $LSPACE ] ; then
			E=`$STRS 1 1250 "log could exceed disk space limit"`
			L=`expr $2 - $LSPACE`
		else
			E=
		fi
		if [ -n "$E" ] ; then
			echo "$ID $E ($L <= $GETRSTAT_used_r)" 1>&2
			CHKRMTSPC_r=-1		# pass on this one
		fi
	fi
}

cleanup () {
	clrremoteaccess
}


clrremoteaccess () {
	$SAY "clrremoteaccess"
	if [ -n "$SSADM_TICKET_FILE" -a -r "$SSADM_TICKET_FILE" ] ; then
		$SAY "clrremoteaccess: --> logout"
		doremote $SCRN "logout" -
		rm $SSADM_TICKET_FILE
		SSADM_TICKET_FILE=
	fi
}

# doremote $SCRN $CMD $DSTFILE $NONFATAL
doremote () {
# todo: something w/ passwords (for remotes)
	$SAY "doremote:  SCRN=='$1'  CMD=='$2'  DSTFILE=='$3'  NONFATAL=='$4'"
	if [ $1 = "-" ] ; then
		SARG=""		# it's local
	else
		SARG="-r $1 "	# it's remote
	fi
	if [ $3 = "-" ] ; then
		$SAY "doremote: $SSADM $SARG$2"
		DORMT_r=`$SSADM $SARG$2`
	else
		$SAY "doremote: $SSADM $SARG$2 >$3"
		DORMT_r=`$SSADM $SARG$2 >$3`
	fi
	DORMT_err=$?
	if [ -z "$4" -a $DORMT_err -ne 0 ] ; then
		E=`$STRS 1 1848 "remote command error"`
		echo "$ID $E '$2' : $DORMT_err"
		exit 15
	fi
	$SAY "doremote:  ==>  '$DORMT_r'  err==$DORMT_err"
}

# error <exitval> <msg>
error () {
	FE=`$STRS 1 610 "fatal error"`
	echo "$ME $FE: $2" 1>&2
	exit $1
}

# fileMB $TFILE
fileMB () {
	FILEMB_r=`ls -s $1 | awk '{print ($1 / 2048)}'`
}

# getremoteaccess $SCRN
getremoteaccess () {
	# extract the user name and password for $SCRN from the password file
	BT=" 	"	# blank & tab
	U=`sed -n <$PWDFILE \
	  -e "s/^$1[$BT][$BT]*\([^$BT]*\).[$BT]*[^$BT]*/\1/p"`
	if [ -z "$U" ] ; then
		E=`$STRS 1 372 "couldn't find user in password file"`
		echo "$ID $E" 1>&2
		exit 20
	fi
	P=`sed -n <$PWDFILE \
	  -e "s/^$1[$BT][$BT]*[^$BT]*.[$BT]*\([^$BT]*\)/\1/p"`
	if [ -z "$P" ] ; then
		E=`$STRS 1 370 "couldn't find password in password file"`
		echo "$ID $E" 1>&2
		exit 21
	fi
	GETRMTACS_r=1
	# attempt to login; ticket files are stored in the destination
	# directory and used as a locking mechanism
	SSADM_TICKET_FILE=$DSTDIR/$1.$U.${ME}.ssadmticket
	if [ -r $SSADM_TICKET_FILE ] ; then
		E=`$STRS 1 390 "currently active - skipped"`
		echo "$ID $ME $U $E" 1>&2
		SSADM_TICKET_FILE=
	else
		touch $SSADM_TICKET_FILE
		chmod go= $SSADM_TICKET_FILE
		export SSADM_TICKET_FILE
		doremote $1 "login $U $P" - -
		if [ $DORMT_err -ne 0 ] ; then
			# stderr will have gotten some complaint (we hope)
			E=`$STRS 1 1280 "login failed - skipped"`
			echo "$ID $ME $U $E" 1>&2
			SSADM_TICKET_FILE=
		else
			GETRMTACS_r=0		# success
		fi
	fi
	P=	# scrub
}

# getlocalspace $TDIR
getlocalspace () {
	GETLSPC_r=`df -k $1 | tail -1 | awk '{print int($4 / 1024)}'`
	[ $? -ne 0 ] && error 10 "getlocalspace: $?"
	if [ $VERBOSE -gt 1 ] ; then
		E=`$STRS 1 1241 "local space: "`
		echo "$ID $E: $GETLSPC_r (MB)"
	fi
}

# getremotelog $SCRN $FILTEXPR $TFILE
getremotelog () {
	if [ $CLRLOG -eq 1 ] ; then
		O="${USER:+-U '$USER' }get_and_clear"
	else
		O="get"
	fi
	if [ $VERBOSE -gt 1 ] ; then
		S=`$STRS 1 720 "get log: "`
		echo "$ID $S: $O${2:+ $2} >$3"
	fi
	$DOITg doremote $SCRN "-n -b log $O${2:+ $2}" $3
}

# getremotemacro $SCRN
getremotemacro () {
	doremote $SCRN "-n logmacro expand $FILTER" -
	GETRMTMAC_r=$DORMT_r
}

# getremotestats $SCRN
#   sizes converted to $MEGs, space-used rounded up to next meg
getremotestats () {
	doremote $SCRN "-n logstats -Z" -
	X=`expr "$DORMT_r" : '\([0-9][0-9]*\).*'`
	GETRSTAT_used_r=`echo "$X $MEG + 1 - $MEG / p" | dc`
	X=`expr "$DORMT_r" : '.* .* ".*" \([0-9][0-9]*\) .*'`
	GETRSTAT_size_r=`echo "$X $MEG / p" | dc`
	X=`expr "$DORMT_r" : '.* .* ".*" .* \([0-9][0-9]*\)'`
	GETRSTAT_loss_r=$X
	$SAY "getremotestats:  ==>  used==$GETRSTAT_used_r"
	$SAY "getremotestats:  ==>  size==$GETRSTAT_size_r"
	$SAY "getremotestats:  ==>  loss==$GETRSTAT_loss_r"
}

spacey () {
	S=`expr "$1" : '\(-\).*'`
	P=`expr "$1" : '.*\(%\)'`
	N=`expr "$1" : "$S\([0-9][0-9]*\)$P"`
 	$SAY "spacey: S=='$S'  N=='$N'  P=='$P'"
	[ -z "$N" ] && usage
	RSPACE=`expr $S$N + 0`
	if [ -z "$P" ] ; then
		RSPCT=0
	elif [ $RSPACE -lt 0 -a $RSPACE -lt -100 -o $RSPACE -gt 100 ] ; then
		E=`$STRS 1 570 "error: invalid"`
		S=`$STRS 1 1950 "space-param"`
		echo "$E <$S> '$1'" 1>&2
		exit 1
	else
		RSPCT=1
	fi
}

CLRLOG=0
COMPRESS=0
DSTDIR=
FILTER=
FILTERMACRO=0
LSPACE=-1
PWDFILE=
RSPACE=0
RSPCT=-1
SCRIPT=
USER=
VERBOSE=0

while [ $# -gt 0 ] ; do
	$SAY case "$1"
	case $1 in
	-v*|-C*|-Z*)
		OZ=`expr "$1" : '-\(.*\)'`
		while [ -n "$OZ" ] ; do
			case $OZ in
			v*)	VERBOSE=`expr $VERBOSE + 1`
				;;
			C*)	CLRLOG=1
				;;
			Z*)	COMPRESS=1
				;;
			*)	usage
				;;
			esac
			OZ=`expr "$OZ" : '.\(.*\)'`
		done
		;;
	-f)	[ -n "$FILTER" -o $# -lt 2 ] && usage
		shift
		FILTER=$1
		;;
	-f*)	[ -n "$FILTER" ] && usage
		FILTER=`expr "$1" : '..\(.*\)'`
		;;
	-F)	[ -n "$FILTER" -o $# -lt 2 ] && usage
		shift
		FILTER=$1
		FILTERMACRO=1
		;;
	-F*)	[ -n "$FILTER" ] && usage
		FILTER=`expr "$1" : '..\(.*\)'`
		FILTERMACRO=1
		;;
	-o)	[ -n "$DSTDIR" -o $# -lt 2 ] && usage
		shift
		DSTDIR=$1
		;;
	-o*)	[ -n "$DSTDIR" ] && usage
		DSTDIR=`expr "$1" : '..\(.*\)'`
		;;
	-P)	[ -n "$PWDFILE" -o $# -lt 2 ] && usage
		shift
		PWDFILE=$1
		;;
	-P*)	[ -n "$PWDFILE" ] && usage
		PWDFILE=`expr "$1" : '..\(.*\)'`
		;;
	-s)	[ $RSPCT -ge 0 -o $# -lt 2 ] && usage
		shift
		spacey $1
		;;
	-s*)	[ $RSPCT -ge 0 ] && usage
		spacey `expr "$1" : '..\(.*\)'`
		;;
	-S)	[ $LSPACE -ge 0 -o $# -lt 2 ] && usage
		shift
		LSPACE=$1
		;;
	-S*)	[ $LSPACE -ge 0 ] && usage
		LSPACE=`expr "$1" : '..\(.*\)'`
		;;
	-U)	[ -n "$USER" -o $# -lt 2 ] && usage
		shift
		USER=$1
		;;
	-U*)	[ -n "$USER" ] && usage
		USER=`expr "$1" : '..\(.*\)'`
		;;
	-X)	[ -n "$SCRIPT" -o $# -lt 2 ] && usage
		shift
		SCRIPT=$1
		;;
	-X*)	[ -n "$SCRIPT" ] && usage
		SCRIPT=`expr "$1" : '..\(.*\)'`
		;;
	-*)
		usage
		;;
	*)
		break
		;;
	esac
	shift
done

# process local space
if [ "$LSPACE" = "-1" ] ; then
	:	# don't worry, be happy
else
	N=`expr "$LSPACE" : '\([0-9][0-9]*\)'`
	if [ -z "$N" ] ; then
		E=`$STRS 1 570 "error: invalid"`
		L=`$STRS 1 1240 "local-space"`
		echo "$E <$L> '$LSPACE'" 1>&2
		exit 1
	fi
fi

# process script
S=`expr "$SCRIPT" : '\([^ ]*\) .*'`
[ -z "$S" ] && S=$SCRIPT
if [ -n "$S" -a ! -x "$S" ] ; then
	E=`$STRS 1 572 "error: missing"`
	X=`$STRS 1 1912 "script-spec"`
	echo "$E <$X> '$S'" 1>&2
	exit 1
fi

# process screen args (if any)
SCRNZ=
while [ $# -gt 0 ] ; do
	SCRNZ="$SCRNZ${SCRNZ:+ }$1"
	shift
done
if [ -z "$SCRNZ" ] ; then
	SCRNZ=-
fi

# default destination
if [ -z "$DSTDIR" ] ; then
	DSTDIR="$VAR_DIR/logarchive"
	[ ! -d $DSTDIR ]  &&  ( umask 077 ; mkdir $DSTDIR )
elif [ ! -d $DSTDIR ] ; then
	E=`$STRS 1 572 "error: missing"`
	D=`$STRS 1 440 "dest-dir"`
	echo "$E <$D> '$DSTDIR'" 1>&2
	exit 1
fi

# default password directory
[ -z "$PWDFILE" ] && PWDFILE="$ETC_DIR/logpasswd"
if [ $SCRNZ != "-" -a ! -r $PWDFILE ] ; then
	E=`$STRS 1 572 "error: missing"`
	P=`$STRS 1 1610 "passwd-file"`
	echo "$E <$P> '$PWDFILE'" 1>&2
	exit 1
fi

$SAY "CLRLOG==$CLRLOG  COMPRESS==$COMPRESS  DSTDIR=='$DSTDIR'"
$SAY "PWDFILE=='$PWDFILE'"
$SAY "FILTERMACRO==$FILTERMACRO  FILTER=='$FILTER'"
$SAY "LSPACE==$LSPACE  RSPACE==$RSPACE  RSPCT==$RSPCT"
$SAY "SCRIPT=='$SCRIPT'  VERBOSE==$VERBOSE"

EV=0

trap cleanup 0 1 2 3 15

for SCRN in $SCRNZ ; do
	TS=`date +%Y-%m-%d@%H:%M:%S`
	ID="$TS $SMSG $SCRN"
	[ $VERBOSE -gt 0 ] && echo "$ID"

	# create the target directory, if needed; get space available therein
	TDIR="$DSTDIR/$SCRN"
	TFILE="$TDIR/$TS.log"
	$SAY "TDIR==$TDIR  TFILE==$TFILE"
	if [ ! -d $TDIR ] ; then
		[ $VERBOSE -gt 0 ] && echo "mkdir $TDIR" 
		(umask 77 ; mkdir $TDIR)
		E=$?
		[ $E -ne 0 ] && error 7 "mkdir($TDIR): $E"
	fi

	getlocalspace $TDIR
	$SAY "GETLSPC_r==$GETLSPC_r"

	# check for local space (if specified)
	if [ $LSPACE -gt 0 ] ; then
		if [ $GETLSPC_r -lt $LSPACE ] ; then
			E=`$STRS 1 1236 "local disk space limit exceeded"`
			echo "$ID $E ($GETLSPC_r < $LSPACE (MB))" 1>&2
			exit 6
		fi 
	fi

	# obtain access to this screen (if remote)
	GETRMTACS_r=0
	[ $SCRN != "-" ] && getremoteaccess $SCRN 
	[ $GETRMTACS_r -ne 0 ] && continue

	# check for remote space limit reached (if specified)
	getremotestats $SCRN
	# whine if we've lost records and have selected CLRLOG
	if [ $CLRLOG -ne 0 -a $GETRSTAT_loss_r -gt 0 ] ; then
		E=`$STRS 1 1256 "log lost"`
		R=`$STRS 1 1840 "(records)"`
		echo "$ID $E $GETRSTAT_loss_r $R" 1>&2
		EV=5
	fi
	checkremotespace $SCRN $GETLSPC_r
	if [ $CHKRMTSPC_r -le 0 ] ; then
		if [ $CHKRMTSPC_r -lt 0 -a $EV -lt 5 ] ; then
			EV=2
		elif [ $VERBOSE -gt 0 ] ; then
			E=`$STRS 1 1266 "log size under threshold - skipped"`
			echo "$E"
		fi
		clrremoteaccess
		continue
	fi

	# expand macro from screen (if given)
	if [ $FILTERMACRO -gt 0 ] ; then
 		getremotemacro $SCRN
		FILT=$GETRMTMAC_r
	else
		FILT=$FILTER
	fi

	# create the target file
	(umask 77 ; touch $TFILE)
	E=$?
	[ $E -ne 0 ] && error 8 "create($TFILE): $E"

	# suck the log ...
	getremotelog $SCRN "$FILT" $TFILE
	if [ $VERBOSE -gt 0 ] ; then
		fileMB $TFILE
		echo "$FILEMB_r (MB) >$TFILE"
	fi

	# release access to screen
	clrremoteaccess

	# invoke the user-specified script (if any)
	if [ -n "$SCRIPT" ] ; then
		ROPT=""  COPT=""  VOPT=""
		[ $SCRN != "-" ] && ROPT="-r$SCRN "
		[ $CLRLOG -gt 0 ] && COPT="-C "
		[ $VERBOSE -gt 0 ] && VOPT="-v "
		if [ $VERBOSE -gt 1 ] ; then
			S=`$STRS 1 1896 "run"`
			echo "$ID $S: $SCRIPT $ROPT$COPT$VOPT\c"
			echo "-o$DSTDIR $TFILE"
		fi
		$DOITx $SCRIPT $ROPT$COPT$VOPT-o$DSTDIR $TFILE
		E=$?
		[ $E -ne 0 ] && \
		  error $E "$SCRIPT $ROPT$COPT$VOPT-o$DSTDIR $TFILE : $E"
	fi

	# compress (if specified)
	if [ $COMPRESS -gt 0 ] ; then
		[ $VERBOSE -gt 1 ] && echo "compress: $TFILE"
		$DOITz compress $TFILE
		E=$?
		[ $E -ne 0 -a $E -ne 2 ] && error 9 "compress $TFILE"
		if [ $E -eq 0 -a $VERBOSE -gt 0 ] ; then
			fileMB ${TFILE}.Z
			echo "$FILEMB_r (MB) >${TFILE}.Z"
		fi
	fi
done

exit $EV

# eof
