:
#	@(#) idleout.sh 22.2 90/04/03 
#
#	Copyright (C) The Santa Cruz Operation, 1988.
#	This Module contains Proprietary Information of
#	The Santa Cruz Operation and should be treated
#	as Confidential.
#

# idleout(C)

# SIGHUP is ignored so that if the root user who invoked the 
# idleout process gets logged out (or logs out) the idleout
# process will not die.

# Idleout has to work in the background. It pulls some trickery 
# so that the user does not have to invoke it in the background.
# The first invocation of idleout(C) calls itself recursively with
# the environment variable RECURSE equal to 1.

# The command ``idleout 0'' turns off idle logout.

# PATH=/bin:/usr/bin		# S000
PATH=/bin:/usr/bin:$PATH	# S000
DEFFILE=/etc/default/idleout
DEFFIELD="IDLETIME="
LOCKD="/usr/spool/locks"
LOCKF="LCK..idleout"
progname="$0"
trap "" 1		
IFS=:$IFS
# Force command line args to be parsed again with ":" as a separator
[ $# -ne 0 ] && set $@
# save the args because shell functions will clobber them
argc=$# arg1=$1 arg2=$2
hours=0 minutes=0 defhours=0 defminutes=0
# This program uses "who -u" which loses track after 24 hours
MAXHOURS=23 MAXMINUTES=59

# idleout(C) uses a default file, /etc/default/idleout, to provide
# a system default for the amount of time a user can remain idle before
# being logged out. It should have one entry of the form:
#
#	IDLETIME=[hours:]minutes
#
# indicating the amount of time a user can remain idle before
# being logged out.

# Function definitions

# Print usage message and exit
printusage() {
	echo "usage: $progname [ minutes | hours:minutes ]" >&2
	exit 1
}

# Make sure we are superuser, because only they can execute the program
superuser() {
	[ `id | sed 's/(.*$//'` != "uid=0" ] && {
		echo "$progname: must be root" >&2
		exit 5
	}
	return
}

# Verify that args to the program are numeric.
checkargs() {
	# If there are zero args just return
	[ $# -eq 0 ] && return 
	# verify args (if present) are numeric using the expr command
	[ $# -ge 1 ] && { expr $1 + 1 > /dev/null 2>&1 || printusage; }
	[ $# -ge 2 ] && { expr $2 + 1 > /dev/null 2>&1 || printusage; }
	return 
}

# This function reads a time out of the default file. It reads
# either the default logout time.
# It puts the time into the global vars ``defhours'' and ``defminutes''.
getdefault() {
	msg="$progname: $DEFFILE contains badly formatted information for $FIELD"
	# Make sure there's a default file
	[ ! -r $DEFFILE ] && return 0
	# Get then set the time as positional parms to this function
	# Also save the old command line args
	i=`fgrep $DEFFIELD $DEFFILE | sed s/$DEFFIELD//`; set $i
	# If no such entry then return
	[ $# -eq 0 ] && return 0
	# Check number of terms: 1 or 2 allowed in [hours:]minutes
	[ $# -gt 2 ] && { echo "$msg" >&2; return 1; }

	# Verify validity: make sure each term is a number
	for x 
	do	# This next line fails if the term is not a number
		expr "$x" + 1 > /dev/null 2> /dev/null || {
			echo "$msg" >&2; return 2
		}
	done
	# Got 1 or 2 valid arguments
	if [ $# -eq 1 ]
	then	{ defhours=0; defminutes=$1; }
	else	{ defhours=$1; defminutes=$2; }
	fi
	return 0
}

# This routine determines the logout time. First the command line
# arguments are evaluated. If they're null the defaults are used.
# Then the result, if nonzero, is compared with the maximum time
# and the minimum of the two is used. The final value is put into
# the two globals ``hours'' and ``minutes''.
gettime() {
	# Get the logout time
	case $# in
		0 ) hours=$defhours; minutes=$defminutes ;;
		1 ) hours=0; minutes=$1 ;;
		2 ) hours=$1; minutes=$2 ;;
	esac

	# Translate minutes > 60 to hours
	while [ $minutes -ge 60 ]
	do
		hours=`expr $hours + 1`
		minutes=`expr $minutes - 60`
	done
	time=`expr $hours '*' 60 + $minutes`
	max=`expr $MAXHOURS '*' 60 + $MAXMINUTES`
	[ $time -gt $max ] && {
		echo "$progname: warning: using maximum logout time of $MAXHOURS:$MAXMINUTES"
		hours=$MAXHOURS
		minutes=$MAXMINUTES
	}
}

# Next two funtions added S000

# rmlock
#
# Look for an idleout lock file. If found, get pid from the file,
# kill that process, and remove the file.
#
rmlock() {
	if [ -r $LOCKD/$LOCKF ]
	then
		read pid < $LOCKD/$LOCKF && 	\
				kill -9 $pid > /dev/null 2> /dev/null
		rm $LOCKD/$LOCKF
	fi
}

# mklock
#
# Create a lock file containing our pid.
mklock() {
	if [ ! -d $LOCKD ] 
	then
		mkdir $LOCKD > /dev/null 2> /dev/null || return
	fi
	echo $$ > $LOCKD/$LOCKF

}
# End S000

# This function builds a command which uses who(C) and awk(C) to
# kill(C) users who have been idle. 
#
# The parameters to this function are $1=hours and $2=minutes
# The awk patterns print the shell process ids of users who have
# been logged in a long time. Then those pids are killed -9. Users
# who are current are skipped in the first pattern. Users who are old
# are printed in the second pattern. This program has a hardwired
# maximum of 24 hours because who -u stops counting at 23:59 and
# reports "old". The bracketed statement assigns the users idle hours 
# and minutes to the variables x and y respectively. Then users idle
# longer that h:m are printed. h and m are awk parameters taken from
# arguments to this function.
# The output of `who -u' is being put into a tmp file and awk
# is being called to act upon that because when I piped the
# output of who -u into awk nothing happend.
killer() {
	TMPFILE=/tmp/kill$$
	who -u > $TMPFILE
	kill -9 `awk '				\
		$6 == "." { next } 	\
		$6 == "old"	{ print $7 ; next } 		\
		{	i=index($6,":");			\
			x=substr($6,1,i-1);			\
			y=substr($6,i+1,length($6)-i);		\
		} \
		x > h  { print $7 ; next } \
		x == h && y+0 >= m+0 { print $7 ; next } \
		' h=$1 m=$2 $TMPFILE `
	rm $TMPFILE
}


# main
# If this is a recursive call, don't do any checking.
# Indicated by 3 args, #1 is hours, #2 is minutes, #3 is "-"
if [ $argc -eq 2 -a "$RECURSE" = "1" ]	# Check for recursive call
then
	# Only recursive call executes here
	mklock				# make a lock file -- S000
	while true
	do
		killer $arg1 $arg2
		sleep 60
	done
fi

#
# Only nonrecursive call executes here. Do checking and arg evaluation
#

superuser			# are we suser? only suser allowed 
[ $argc -gt 2 ] && printusage	# verify arg count argc <= 2
checkargs $arg1 $arg2		# verify args are numeric
getdefault			# Get default idletime from default file
gettime $arg1 $arg2		# compute idle time for logouts
rmlock			# remove previous lock file if any -- S000
[ $hours -eq 0 -a $minutes -eq 0 ] && exit 0	# if zero, do nothing
# Make the recursive call
RECURSE=1; export RECURSE	# make sure next invocation stays
# exec /bin/sh $progname $hours $minutes &	# S000
exec $progname $hours $minutes &		# S000
