#!/bin/sh -
#
# comprehensive finger scan.
#
# WARNING: There are a lot of hosts at DoC. So this program inevitably creates
#  a lot of network traffic. Therefore:
#   * it is to be used sparingly, i.e. the odd manual usage (it's not to be
#     run in an automated loop, for example!);
#   * it is not to be installed in the lab area (the sheer number of even
#     individually infrequent users could then be a problem).
#
# usage: fscan [-]		(simply fingers each host in turn)
#	 fscan [-] -w		(does "w" on each host in turn)
#	 fscan [-] -s		(produces a listing sorted by user. Note that
#				  this uses rusers and thus depends on the
#				  cooperation of the rusers daemons.)
#	 fscan [-] -t		(tiny sorted listing of users, all on one line.
#				  Note that this uses rusers and thus depends
#				  on the cooperation of the rusers daemons.)
#	 fscan [-] -l <user>	(looks for all last login times of that user,
#				  using finger.)
#
# A *non-empty* host list in ~/.fscanrc will override the default host list,
# unless the option - is in use, in which case the default host list is
# always used.
#
umask 077	#privacy in /tmp
progname=`basename $0`


#
#	timeouts
#
finger_timeout=20
ssh_timeout=30
rusers_timeout=10


#
# get host list ready
#
try_fscanrc=TRUE #provisionally
if [ $# -ne 0 ]; then
  if [ "x$1" = "x-" ]; then
    shift ; try_fscanrc=FALSE
  fi
fi

if [ $try_fscanrc = TRUE -a -f $HOME/.fscanrc ]; then
  hosts=`sed 's/#.*$//' $HOME/.fscanrc`
  if [ -n "$hosts" ]; then
    echo "(Using host list in \"$HOME/.fscanrc\")" >&2
  else
    hosts=`sed 's/#.*$//' $LOCALLAB/lib/student_hosts.cf`
  fi
else
  hosts=`sed 's/#.*$//' $LOCALLAB/lib/student_hosts.cf`
fi


#
# prepare directory in /tmp (not actually used by all options)
#
temploc=/tmp/$progname.$$
tempstderr=$temploc/stderr.txt
tempstderrbyhost=$temploc/stderrbyhost.txt
temperrorhosts=$temploc/errorhosts.txt
trap "rm -rf $temploc ; exit 1" 1 2 3 15

rm -rf $temploc
mkdir $temploc
if [ $? -ne 0 ]; then
  echo "$progname: fatal error: funny business in /tmp" >&2
  exit 1
fi


#
# now determine what option is wanted.
#


if [ $# = 0 ]; then #just the huge scan!

  for host in $hosts ; do
    runprog -$finger_timeout finger @$host
    if [ $? -eq 104 ]; then
      echo "***$progname: finger @$host timed out" >&2
    fi
  done #for host

elif [ "x$1" = "x-w" ]; then #do "w" on each host in turn

  if [ $# != 1 ]; then
    echo $progname: -w option takes no further arguments >&2
    rm -rf $temploc
    exit 1
  fi

  for host in $hosts ; do
    echo "[$host.doc.ic.ac.uk]"
     #makes it look like a "finger @<host>" output
    (
      runprog -$ssh_timeout ssh -n -x $host w -s
      if [ $? -eq 104 ]; then
        echo "***$progname: ssh -n -x $host w -s timed out" >&2
      fi
    ) | sed -e '1d' -e 's/[ 	][ 	]*[^ 	][^ 	]*[ 	][ 	]*/	/' | fingerize | sort
    #
    # (The sed above removes a part of the header that would get parsed in a
    #  meaningless and confusing way, and also removes the TTY info, to make it
    #  more likely the final output will fit into 80 columns.)
    #
  done #for host

elif [ "x$1" = "x-s" ]; then #listing sorted by user, using rusers

  if [ $# != 1 ]; then
    echo $progname: -s option takes no further arguments >&2
    rm -rf $temploc
    exit 1
  fi

  echo "Login       Name               Host         When        Idle Where"
  #the echo above gives the output the same flavour as finger
  (
    for host in $hosts ; do
      (
        runprog -$rusers_timeout rusers -l $host
        if [ $? -eq 104 ]; then
          echo "$progname: $host: rusers timed out" >&2
        fi
      ) 2> $tempstderrbyhost
      cat $tempstderrbyhost >&2

      if [ -s $tempstderrbyhost ]; then
        echo $host >> $temperrorhosts
      fi
    done | fingerize | sed 's/\.[^ 	]*:[^ 	]*[ 	][ 	]*/	/' | sort
    #the sed above removes the TTY info, to fit final output into 80 columns
  ) 2> $tempstderr
  sed 's/^/***/' $tempstderr >&2

  #
  #	Now, if any hosts gave errors, then try fingering them as an
  #	emergency measure. (Let's not worry about finger giving errors too!)
  #
  #	We use "ssh -n -x <host> finger", rather than "finger @<host>",
  #	as there are now an awful lot of hosts with their finger daemon
  #	disabled.
  #
  if [ -s $temperrorhosts ]; then
    errorhosts=`cat $temperrorhosts`
    errorhosts=`echo $errorhosts`	#just to throw away multi-line layout!
    echo "($progname: fingering host(s) that gave errors: $errorhosts)"

    for errorhost in $errorhosts ; do
      echo "[$errorhost.doc.ic.ac.uk]"
       #makes it look like a "finger @<host>" output
      (
        runprog -$ssh_timeout ssh -n -x $errorhost finger
        if [ $? -eq 104 ]; then
          echo "***$progname: ssh -n -x $errorhost finger timed out" >&2
        fi
      ) | sort
    done #for errorhost
  fi

elif [ "x$1" = "x-t" ]; then #tiny sorted listing of users, all on one line

  if [ $# != 1 ]; then
    echo $progname: -t option takes no further arguments >&2
    rm -rf $temploc
    exit 1
  fi

  (
    for host in $hosts ; do
      runprog -$rusers_timeout rusers $host
      if [ $? -eq 104 ]; then
        echo "$progname: $host: rusers timed out" >&2
      fi
    done | echo `sed 's/^[^ 	]*[ 	]//' | tr -s ' 	' '\012' | sort -u`
  ) 2> $tempstderr
  sed 's/^/***/' $tempstderr >&2

elif [ "x$1" = "x-l" ]; then #look for all last login times of the given user

  if [ $# != 2 ]; then
    echo $progname: -l option requires one username >&2
    rm -rf $temploc
    exit 1
  fi

  user=$2

  for host in $hosts ; do
    #
    #	We use "ssh -n -x $host finger $user", rather than "finger $user@$host",
    #	as there are now an awful lot of hosts with their finger daemon
    #	disabled.
    #
    (
      (
        runprog -$ssh_timeout ssh -n -x $host finger $user
        if [ $? -eq 104 ]; then
          echo "***$progname: ssh -n -x $host finger $user timed out" >&2
        fi
      ) | egrep '^Last login |^On since '
    ) 2>&1 | sed "s/^/$user@$host:	/"
  done #for host

else #illegal option!

  sed 's/^    //' << __here >&2
    usage: fscan [-]            (simply fingers each host in turn)
           fscan [-] -w         (does "w" on each host in turn)
           fscan [-] -s         (produces a listing sorted by user)
           fscan [-] -t         (tiny sorted listing of users, all on one line)
           fscan [-] -l <user>  (looks for all last login times of that user)
    (the - option means don't look for a personal host list in ~/.fscanrc).
__here
  rm -rf $temploc
  exit 1

fi


#
# final tidyup at end.
#
rm -rf $temploc
exit 0
