#! /bin/sh
# waitfor --- notify you when a user logs in

# Copyright (C) 1991, 1994 Noah S. Friedman

# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1991-08-08

# $Id: waitfor,v 1.4 1996/03/03 23:03:30 friedman Exp $

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you can either send email to this
# program's maintainer or write to: The Free Software Foundation,
# Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.

# Commentary:

# Notifies invoker when specified user logs onto any of the specified
# hosts.  This script will automatically background itself.  There's no
# need to call it with a "&" operator.

# Code:

# Name by which this script was invoked.
progname=`echo "$0" | sed -e 's/[^\/]*\///g'`

# To prevent hairy quoting and escaping later.
bq='`'
eq="'"

usage="Usage: $progname {options} [user] {host1} {host2} {...}

Options are:
-D, --debug                  Turn on shell debugging ($bq${bq}set -x$eq$eq).
-F, --force                  Do not examine ownership of tty to decide
                             whether to terminate.  Use of this option is
                             discouraged because failure to kill this program
                             at logout will annoy the next user to log in.
-h, --help                   You're looking at it.
-i, --interval  SECONDS      Number of seconds between checks, default 60.

If no hosts are specified, the current host is assumed.
"

# Clever way to save arguments whilst preserving quoting.
# Note that only one set of args can be saved at a time.
# Usage: eval "$save_current_args"
#        eval "$restore_saved_args"
save_current_args='
  {
    _saved_args=
    while : ; do
      case $# in 0 ) break ;; esac
      eval _saved_args$#=\$1
      _saved_args="$_saved_args \"\$_saved_args$#\""
      shift
    done
    eval "$restore_saved_args"
  }'
restore_saved_args='
  {
    eval '\''{ eval set fnord $_saved_args ; }'\''
    shift
  }'

# Usage: eval "$getopt"; value=$optarg
# or     optarg_optional=t; eval "$getopt"; value=$optarg
#
# This function automatically shifts the positional args as appropriate.
# The argument to an option is optional if the variable `optarg_optional'
# is non-empty.  Otherwise, the argument is required and getopt will cause
# the program to exit on an error.  optarg_optional is reset to be empty
# after every call to getopt.  The argument (if any) is stored in the
# variable `optarg'.
#
# Long option syntax is `--foo=bar' or `--foo bar'.  2nd argument
# won't get used if first long option syntax was used.
#
# Note: because of broken bourne shells, using --foo=bar syntax can
# actually screw the quoting of args that end with trailing newlines.
# Specifically, most shells strip trailing newlines from substituted
# output, regardless of quoting.
getopt='
  {
    optarg=
    case "$1" in
      --*=* )
        optarg=`echo "$1" | sed -e "1s/^[^=]*=//"`
        shift
       ;;
      * )
        case ${2+set} in
          set )
            optarg="$2"
            shift
            shift
           ;;
          * )
            case "$optarg_optional" in
              "" )
                case "$1" in
                  --*=* ) option=`echo "$1" | sed -e "1s/=.*//;q"` ;;
                  * ) option="$1" ;;
                esac
                exec 1>&2
                echo "$progname: option $bq$option$eq requires argument."
                echo "$progname: use $bq--help$eq to list option syntax."
                exit 1
               ;;
           esac
         ;;
        esac
     ;;
    esac
    optarg_optional=
  }'

# Initialize variables.
# Don't use `unset' since old bourne shells don't have this command.
# Instead, assign them an empty value.
debug=
daemonp=f
force=
sleep_interval=60

eval "$save_current_args"

# Parse command line arguments.
# Make sure that all wildcarded options are long enough to be unambiguous.
# It's a good idea to document the full long option name in each case.
# Long options which take arguments will need a `*' appended to the
# canonical name to match the value appended after the `=' character.
while test $# != 0; do
  case $# in 0) break ;; esac
  case "$1" in
    --daemon )
      daemonp=t
      shift
     ;;
    -D | --debug | --d* )
      debug=t
      shift
     ;;
    -F | --force | --f* )
      force=t
      shift
     ;;
    -h | --help | --h )
      echo "$usage" 1>&2
      exit 1
     ;;
    -i | --interval* | --i* )
      eval "$getopt"
      sleep_interval="$optarg"
     ;;
    -- )     # Stop option processing
      shift
      break
     ;;
    -? | --* )
      case "$1" in
        --*=* ) arg=`echo "$1" | sed -e 's/=.*//'` ;;
        * )     arg="$1" ;;
      esac
      exec 1>&2
      echo "$progname: unknown or ambiguous option $bq$arg$eq"
      echo "$progname: Use $bq--help$eq for a list of options."
      exit 1
     ;;
    -??* )
      # Split grouped single options into separate args and try again
      optarg="$1"
      shift
      set fnord `echo "x$optarg" | sed -e 's/^x-//;s/\(.\)/-\1 /g'` ${1+"$@"}
      shift
     ;;
    * )
      break
     ;;
  esac
done

case "$debug" in t ) set -x ;; esac

case $# in
  0 )
    exec 1>&2
    echo "$progname: You must supply a username."
    echo "$usage"
    exit 1
   ;;
esac

case "$force" in
  t ) : ;;
  * )
    TTY=${TTY-`tty 2> /dev/null`}
    case "$TTY" in
      /dev/* ) : ;;
      * )
        echo "$progname: Can't run without a tty." 1>&2
        exit 1
       ;;
    esac

    USER=${USER-${LOGNAME-`(whoami) 2> /dev/null \
                           || id | sed -ne 's/.*uid=[0-9]*(//;s/).*//;p'`}}

    export TTY USER

    tty_sed='s/	/ /g
             s/^[^ ]* *[0-9]* *//
             s/ .*//
             p'
    tty_owner=`ls -ld "$TTY" | sed -ne "$tty_sed"`
    case "$tty_owner" in
      "$USER" ) : ;;
      * )
        exec 1>&2
        echo "$progname: You must own $TTY to run this script."
        ls -ld "$TTY"
        exit 1
       ;;
    esac
   ;;
esac

case "$daemonp" in f )
  eval "$restore_saved_args"
  $0 --daemon ${1+"$@"} &
  echo "$progname backgrounded."
  exit 0
 ;;
esac


tmpfile="/tmp/$progname$$"

target_user="$1"
shift
case $# in 0 )
  set fnord `hostname`
  shift
 ;;
esac

trap 'exitstat=$?
      rm -f "$tmpfile" 2> /dev/null
      trap "" 1 2 3 15
      exit $exitstat
     ' 1 2 3 15

while : ; do
  case "$force" in
    t ) : ;;
    * )
      tty_owner=`ls -ld "$TTY" | sed -ne "$tty_sed"`
      case "$tty_owner" in
        "$USER" ) : ;;
        * )
          rm -f "$tmpfile" 2> /dev/null
          exit 0
         ;;
      esac
     ;;
  esac

  rusers -l ${1+"$@"} 2> /dev/null \
   | grep "^$target_user" > "$tmpfile" 2> /dev/null
  if test -s "$tmpfile" ; then
    echo "*** $progname: $target_user has logged in:"
    cat "$tmpfile"
    echo "*** $progname: Terminating."
    rm -f "$tmpfile"
    exit 0
  fi

  sleep "$sleep_interval"
done

# waitfor ends here
