#!/bin/setpgrp /bin/ksh -p
#
# ident "@(#)utlog.ksh	1.27 04/03/12 SMI"
#
# Copyright 1998-2005 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
export PATH=/bin:/usr/bin:/sbin:/usr/sbin

BASEDIR=/etc/opt/SUNWut/basedir
SUNWUT=`${BASEDIR}/lib/utprodinfo -r SUNWuto 2>/dev/null`/SUNWut
SUNWUTLIB=${SUNWUT}/lib
UTADMIN_CONF="/etc/opt/SUNWut/utadmin.conf"
TMPDIR="/var/opt/SUNWut/tmp"

PROG=$0
ARGS=$*
OS=`uname -s`

# variables needed for logging stdin
NBYTES=0
LOGFILE=""
SIZE=""
typeset -i AGESIZE
# default size for rotation limit is 512KB
AGESIZE_DEF=524288
AGESIZE=$AGESIZE_DEF

#
# Subroutines
#

#
# Usage message
#
function usage {
	print "
Usage: ${PROG##*/} [-a | -e enetAddr] [-r] [-n networks] [-s source] [-f facility] [-d destination]
       ${PROG##*/} -o logfile -S size
Parameters:
	-c			# cleanup log files
	-a | -e enetAddr	# all terminals, or only enetAddr terminal, affected
	-r			# remove logging
	-n interface		# symbolic names of SunRay interconnect interfaces
	-N subnetworks		# the subnetwork address for the SunRay network
	-s {all|kernel|network|usb|video|application}
				# source within terminal
	-f {user|local[0-7]}.{panic|alert|crit|error|warn|notice|info|debug}
				# syslog facility id used to send terminal messages
	-d {emailAddress | /fileName | @remoteLogHost }
				# tells syslog where to file messages. multiple
				# comma separated destinations may be specified
	-o logfile		# Accept data from stdin and redirect to logfile
	-S size			# rotate logfile when it reaches size (default $AGESIZE_DEF)
"
	exit 2
}

#
# Translate string to syslog facility ID
#
function facilityId {
case $1 in
	kern)	print $((0<<3));;	# kernel messages
	user)	print $((1<<3));;	# random user-level messages
	mail)	print $((2<<3));;	# mail system
	daemon)	print $((3<<3));;	# system daemons
	auth)	print $((4<<3));;	# security/authorization messages
	syslog)	print $((5<<3));;	# internal syslogd messages
	lpr)	print $((6<<3));;	# line printer subsystem
	news)	print $((7<<3));;	# netnews subsystem
	uucp)	print $((8<<3));;	# uucp subsystem
	cron)	print $((15<<3));;	# cron/at subsystem
	local0)	print $((16<<3));;	# reserved for local use
	local1)	print $((17<<3));;	# reserved for local use
	local2)	print $((18<<3));;	# reserved for local use
	local3)	print $((19<<3));;	# reserved for local use
	local4)	print $((20<<3));;	# reserved for local use
	local5)	print $((21<<3));;	# reserved for local use
	local6)	print $((22<<3));;	# reserved for local use
	local7)	print $((23<<3));;	# reserved for local use
	*)	usage;;
esac
}


#
# setup logging outfile and counter
#
function start_agefile {
	NBYTES=0
	# rotate existing file first
	/opt/SUNWut/lib/utagelog $LOGFILE 9

	# open descriptor 4 for writing directly into logfile
	exec 4> $LOGFILE
}


#
# read stdin, dump to LOGFILE, rotate
#
function log_stdin {
	# first close stdout & stderr so if piped, other side of pipe
	# won't wait for output that'll never come
	exec 1>&-
	exec 2>&-

	start_agefile
	# 5090309 utlog munges valid input, discards valid output
	# clear IFS so that no characters are considered field delimiters
	# save whatever IFS is in effect now so that we can restore it
	oldIFS="$IFS"
	IFS=""
	while read -r VAL
	do
		IFS="$oldIFS"
		# how many bytes in this line (+1 to count newline character)
		NBYTES=$((NBYTES+1+${#VAL}))

		# is it time to rotate yet ?
		if [[ $NBYTES -gt $AGESIZE ]] then
			# close output before rotating file
			exec 4>&-
			start_agefile

			# start counting again
			NBYTES=$((NBYTES+1+${#VAL}))
		fi

		# write to log
		# 5090309 utlog munges valid input, discards valid output
		# add "-" to signal end of switches and start of output
		print -r -u4 - "$VAL"
		IFS=""
	done

	IFS="$oldIFS"

	# close descriptor to logfile
	exec 4>&-

	exit 0
}


#
# Translate string to syslog priority ID
#
function priorityId {
case $1 in
	emerg|panic)
		print 0;;	# system is unusable
	alert)	print 1;;	# action must be taken immediately
	crit*)	print 2;;	# critical conditions
	err*)
		print 3;;	# error conditions
	warn*)
		print 4;;	# warning conditions
	notice)	print 5;;	# normal but signification condition
	info)	print 6;;	# informational
	debug)	print 7;;	# debug-level messages
	*)	usage;;
esac
}

#
# Translate syslog facility.priority string to decimal number
#
LOG_PRIMASK=7		# mask to extract priority part (internal)
LOG_FACMASK=1016	# mask to extract facility part

function facPri {
	fac=$(facilityId $1)
	pri=$(priorityId $2)
	print $(( ($fac & $LOG_FACMASK) | ($pri & $LOG_PRIMASK) ))
}


#
# get the current dhcp table info
#
GetCurrentCfg () {
	# Will remove the following check once utdhcpnet is used
	if [ "$OS" == "Linux" ]; then
		return 1
	fi
	rm -f $DHTADM_P 2> /dev/null
	dhtadm -P 2>/dev/null | sed -e "1,2d" > $DHTADM_P
	if [ ! -s $DHTADM_P ]; then
		return 1
	fi
	return 0
}

#
# Get the DHCP type string for a particular symbol
#
function dhcpGetSymType {
	print $(nawk '
			{
				if($1 == symbol) {
					print $3;
				}
			}
		' symbol=$1 ${DHTADM_P})
}

#
# Get the current DHCP value of a symbol
# Parameters:
#	$1 the symbol for the value to be returned
#	$2 (new) if exists, use it as the Macro name
#
function dhcpGetSymValue {
	typeset Macro=${MACRO}
	if [ $# -eq 2 ]; then
	    Macro=$2
	fi
	nawk '
		{
			if (($1 == macro) && ($2 == "Macro")) {
				print $3;
			}
		}
	' macro=$Macro ${DHTADM_P} |
	tr ':' '\012' |
	grep -w $1 |
	sed -e 's/^[^=]*=//'
}

#
# Set the value of a DHCP symbol. Define a new symbol if needed
# dhcpSetSym name type value
#
CORONA_NAME="SunRay"
function dhcpSetSym {

	# do this for each of the given interfaces
	NETWORKS="/etc/inet/networks";
	for INTF in ${INTF_LIST} ${SUBNET}; do
		CheckIPA ${INTF}
		if [[ $? -eq 0 ]]; then
			# subnetworks
			INTF_NET=${INTF}
		else
			INTF_NET=`netstat -n -I ${INTF} -f inet | awk 'NR == 2 { print $3 }'`;
		fi
		INTF_NETNAME=${CORONA_NAME}-${INTF}
		MACRO=`grep "^${INTF_NETNAME}" ${DHTADM_P} | awk '{ print $1 }'`
		if [ -z "$MACRO" ]; then
			continue
		fi
		AUTHSRVR=$(dhcpGetSymValue AuthSrvr)

		Symbol=$1
		Pvalue=$(dhcpGetSymValue $Symbol)	# present value
		if [ -z "${Pvalue}" ]; then
			# try looking up in the SunRay Macro
			Pvalue=$(dhcpGetSymValue $Symbol ${CORONA_NAME})
		fi
		Nvalue="$2"				# new value

		# print "_______________"
		# print "Symbol=$Symbol"
		# print "Pvalue=$Pvalue"
		# print "Nvalue=$Nvalue"

		if [ "$Pvalue" != "$Nvalue" ]
		then
			# Set symbol value 
			/usr/sbin/dhtadm -M -m $MACRO -e "$Symbol=$2"
			DHCPchanged=true
		fi
	done
}

#
# Verify a dotted IP address
#  usage:  CheckIPA <ipaddr>
# returns a 0 if a good ipa is given, and a 1 otherwise
#
function CheckIPA {
	typeset IP_ADDR=`expr ${1} : '^\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)$'`
	if [ ! "${IP_ADDR}" ]; then
		return 1
	fi
	NNO1=${1%%.*}
	tmp=${1#*.}
	NNO2=${tmp%%.*}
	tmp=${tmp#*.}
	NNO3=${tmp%%.*}
	tmp=${tmp#*.}
	NNO4=${tmp%%.*}
	if [ ${NNO1} -gt 255 -o ${NNO2} -gt 255 -o ${NNO3} -gt 255 -o ${NNO4} -gt 255 ]; then
		return 1
	fi
	return 0
}

#
# Utility functions to set various symbols
#

# logkern FacId
function LogKern {
	dhcpSetSym LogKern $1
}

function LogNet {
	dhcpSetSym LogNet $1
}

function LogUSB {
	dhcpSetSym LogUSB $1
}

function LogVid {
	dhcpSetSym LogVid $1
}

function LogAppl {
	dhcpSetSym LogAppl $1
}

function GetPid {
	pid=`ps -e   |
	     grep $1 |
	     sed -e 's/^  *//' -e 's/ .*//'`
}

#
# HupDHCP - send a HUP signal to the dhcp daemon
#
HupDHCP () {

	pkill -HUP in.dhcpd
	case $? in
	0)	# signal sent succesfully
		print "### reinitialized DHCP daemon"
		;;
	1)	# dhcp is not currently running
		print "#### DHCP daemon not reinitialized because it is not currently running.\
		       \nYou may want to start one manually using \"${INIT_DHCP} start\"."
		;;
	*)	# failed with some other error
		print -u2 "Warning: failed to initialize the DHCP daemon.\
		           \nYou may want to restart it manually."
		;;
	esac
}


#
# Begin main part of script
#

#
# Constants
#
CONF=/etc/syslog.conf
DHTADM_P="${TMPDIR}/utlog-dhtadm-P.$$"
trap "rm -f ${TMPDIR}/*.$$; exit" 0 1 2 3 14 15

#
# Default values
#
ALL=1			# command affects all Coronas
EA=""
REMOVE=0		# Add logging
SOURCE="all"		# log everything
FACILITY="user.info"	# XXX this should come out of a configuration file
DESTINATION=""
CLEANUP=0;
DODHCP="Y";
DHCPchanged=false
INTF_LIST=""
SUBNET=""

#
# Parse and validate command line options
#
while getopts ace:rn:N:s:f:o:S:d:z name 2>/dev/null
do
	case $name in
	a)	if [ -n "$EA" ] ; then usage; fi;
		ALL=1;;
	e)	if [ $ALL -eq 1 ] ; then usage; fi;
		ALL=0
		EA="$OPTARG";;
	n)	INTF_LIST="$OPTARG";;
	N)	SUBNET="$OPTARG";;
	r)      REMOVE=1;;
	s)	SOURCE="$OPTARG";;	# XXX should allow comma separated list
	f)	FACILITY="$OPTARG";;
	d)	DESTINATION="$OPTARG";;
	c)	CLEANUP=1;;
	z)	DODHCP="N";;
	o)	LOGFILE="$OPTARG";;
	S)	SIZE="1"
		AGESIZE=$OPTARG
		;;
	?)	usage;;
	esac
done

# check args for stdin dump
if [[ -z $LOGFILE && -n $SIZE ]] then
	# -S given but -o not given
	print "Error: -o logfile expected"
	usage;
fi
# -o option processing
if [[ -n $LOGFILE ]] then
	# check for illegal options
	if [[ -n $SIZE ]] then
		# -S used, max 4 args
		if [[ $# -gt 4 ]] then
			print "Error: extra arguments found with -o and -S "
			usage
		fi
		# size should be valid
		if [[ $AGESIZE -le 0 ]] then
			print "Error: invalid size $AGESIZE"
			exit 2
		fi
	else
		# -S not used, max 2 args
		if [[ $# -gt 2 ]] then
			print "Error: extra arguments found with -o"
			usage
		fi
	fi

	# all ok, start logging
	log_stdin
fi

case $FACILITY in
	user.* | local1.info)
		;;
	*)
		print "user.* facilities are the only ones that work"
		exit 2
		;;
esac

shift $(($OPTIND - 1))
if [ $# -ne 0 ]
then
	# Log a message and exit
	logger -p $FACILITY -t UTLOG "Unexpected arguments encountered"
	exit 0
fi

if [ "$CLEANUP" -eq 1 ]
then
	logdir=$(dirname $DESTINATION)
	logfile=$(basename $DESTINATION)
	cd $(dirname $DESTINATION) || usage;
	if [ -f $logfile ]
	then
		# move old log
		$SUNWUTLIB/utagelog $logfile 5
		pkill -HUP syslogd
	fi
	exit 0
fi

if [ -z "$SOURCE" ]
then
	print "Error: must supply a message source";
	usage;
fi

#
# Translate facility name to numeric constant
#
FACILITYID=$(facPri $(print $FACILITY | sed -e 's=\.= ='))
FACILITYID=$(( ~$LOG_FACMASK & $FACILITYID ))	# XXX NewT forces facility to be "user"

#
# Update /etc/syslog.conf
#
# Check to see if $CONF exists
if [ ! -f $CONF ]; then
	print "Error: $CONF file is not availale on the system"
	exit 1
fi
syslog_changed=false

if [ $REMOVE -eq 0 ]
then

	# Syslog complains if the file isn't there.
	# XXX will syslog create the file anyway?
	if [ ! -f $DESTINATION ]; then
		mkdir -p $(dirname $DESTINATION)
		touch $DESTINATION
		syslog_changed=true
	fi
	ADMINGID=`$SUNWUTLIB/utadmingid`
	if [[ -f $UTADMIN_CONF ]]; then
		chmod 640 $DESTINATION
	else
		chmod 600 $DESTINATION
	fi
	chgrp $ADMINGID $DESTINATION

	# check to see if this log entry is already there
	N=$(grep -c "${FACILITY}.*${DESTINATION}" $CONF)
	if [ $N -eq 0 ]
	then
		print "$FACILITY\t\t${DESTINATION}" >> $CONF
		syslog_changed=true
	fi
	# Need to kick syslog
	if $syslog_changed; then
		pkill -HUP syslogd
	fi

	#
	# Set the facility IDs at the UltraTerminal end
	#
	GetCurrentCfg
	if [ ${?} -eq 0 ];
	then

		case "$SOURCE" in
		all)
			LogKern $FACILITYID
			LogNet $FACILITYID
			LogUSB $FACILITYID
			LogVid $FACILITYID
			LogAppl $FACILITYID
			;;
		kernel)
			LogKern $FACILITYID
			;;
		network)
			LogNet $FACILITYID
			;;
		usb)
			LogUSB $FACILITYID
			;;
		video)
			LogVid $FACILITYID
			;;
		application)
			LogAppl $FACILITYID
			;;
		*)
			usage;;
		esac

		# Need to kick dhcp if DODHCP is "Y"
		if ${DHCPchanged} && [[ $DODHCP = "Y" ]]; then
			HupDHCP
		fi

	fi

else

	# Remove an entry from /etc/syslog.conf
	
	# check to see if this log entry is there
	N=$(grep -c "${FACILITY}.*${DESTINATION}" $CONF)
	if [ $N -ne 0 ]
	then
		DESTINATION=$(echo ${DESTINATION} | sed -e 's/\//\\\//g')
		sed -e "/${FACILITY}.*${DESTINATION}/d" $CONF > ${TMPDIR}/syslog_conf.$$
		
		cp ${TMPDIR}/syslog_conf.$$ ${CONF}
		rm -f ${TMPDIR}/syslog_conf.$$ 2>/dev/null
		syslog_changed=true
	fi

	# Need to kick syslog
	if $syslog_changed; then
		pkill -HUP syslogd
	fi

fi
