#!/bin/sh

DOIT=yes ; export DOIT
KILL_SCREEN_SHELLS=no ; export KILL_SCREEN_SHELLS

PS_BIN=ps
CURTTY=`tty | sed -e 's/\/dev\///'`

export PS_BIN CURTTY

usage () {
    cat <<EOF
This script helps kill all your processes associated with the intended
terminals. You can either kill "old" logins, "idle" logins, or logins
associated with specific tty devices. Children of screen(1) processes
will not be considered (unless the "--screen" flag is used).


Usage:
  killallold      - looks for ttys which have been idle for 24+ hours
  killallidle     - looks for ttys which have been idle for 10+ minutes

  killall(idle|old) --screen
                  - includes screen processes among those being considered
                    for reaping

  killallidle <ttyx> [<ttyy> [<ttyz> ...]]]
                  - prompts for killing all processes associated with
                    the ttys named as arguments to killallidle, regardless
                    of the actual idleness of those processes.
                    E.g. (on Solaris) "killallidle pts/22 pts/14"
EOF
}

# get_uid () {
# 	SOLARIS_POSIX_ID=/usr/xpg4/bin/id
# 	if [ -x "$SOLARIS_POSIX_ID" ]; then
# 	    "$SOLARIS_POSIX_ID" -u
# 	else
# 	    id -u
# 	fi
# }

allbutfirstline () {
    awk 'BEGIN { pastfirstline = 0 }
         { if (pastfirstline == 0) {
               pastfirstline = 1
            } else {
               print
            }
          }'
}


generic_ps () {
	CMD="$PS_BIN -t $1"
	$CMD | allbutfirstline | awk '{print $1}'
}

run_ps () {
	PSFUNC=generic_ps
	case "`uname -s`" in
		*) ;;
	esac

	"$PSFUNC" "$1"
}

screen_ttys () {
    ## Look for the ttys used by the children of screen processes.

    PSLIST="`$PS_BIN -o pid,ppid,tty,fname -u $USER | allbutfirstline`"

    SCREEN_PIDS="`echo \"$PSLIST\" | awk '/[sS][cC][rR][eE][eE][nN]/ {print \$1}'`"

    SHELL_TTYS=""
    for spid in $SCREEN_PIDS; do
	x="`echo \"$PSLIST\" | awk '(\$2 == \"'"$spid"'\") { print \$3 }'`"
	SHELL_TTYS="$SHELL_TTYS $x"
    done
    echo $SHELL_TTYS
}

kill_tty_shells () {
    TARGET_TTYS="$@"
    for tt in $TARGET_TTYS; do
	if [ ."$tt" = ."" ]; then
	    echo "Invalid tty."
	    exit 1
	else
	    KILLCMD="kill -HUP `run_ps $tt`"
	    if [ ."$DOIT" != ."yes" ]; then
		echo $KILLCMD
	    else
		$KILLCMD
	    fi
	fi
    done
}

find_old_ttys () {
    who -u | awk '{ if ($1 == "'"$USER"'") {
                        if ($6 == "old") {
                            print $2
                        }
                    }
                  }'
}

find_idle_ttys () {
    who -u | awk '{ if ($1 == "'"$USER"'") {
                        if ($6 !~ /^[\.1-9]$/) {
                            # if idle time is not "." or a single digit
                            print $2
                        }
                    }
                  }'
}

find_ttys () {
    MODE="$1"
    case $MODE in
	kill-old)  find_old_ttys  ;;
	kill-idle) find_idle_ttys ;;
	*)         echo "usage"   ;;
    esac
}

not_cur_tty () {
    egrep -v '(^|[ 	])'"$CURTTY"'([ 	]|$)'
}

maybe_not_screen_ttys () {
    if [ \( $KILL_SCREEN_SHELLS = "no" \) -a ."$SCREEN_TTYS" != ."" ]; then
	TTY_RE="`echo $SCREEN_TTYS | sed -e 's/ /|/g' -e 's#/#\\\\/#g'`"
	TTY_RE="($TTY_RE)"
	egrep -v '(^|[ 	])'"$TTY_RE"'([ 	]|$)'
    else
        cat
    fi
}

list_ttys () {
    WHO="`w`"
    # display 'w' banner
    echo "$WHO" | head -2 | tail -1
    for t in $@; do
	echo "$WHO" | grep '[ 	]'"$t"'[ 	]'
    done
}

confirm_should_kill () {
    echo "These logins have been identified as possibly stale:"
    list_ttys "$@"
    echo ""
    while true; do
	printf 'Would you like to terminate the above logins? [y/n] '
	read answer
	case "$answer" in
	    y*|Y*)
		return 0 ;;
	    n*|N*)
		return 1 ;;
	esac
    done
}

MODE=kill-old

case "`basename $0`" in
    killallidle) MODE=kill-idle ;;
esac

while [ .$1 != '.' ]; do
   case $1 in
       --h*|-h*)
	   usage ; exit 1 ;;
       --idle)
	   MODE=kill-idle
	   shift ;;
       --screen|-s)
           KILL_SCREEN_SHELLS=yes
	   shift ;;
       *)
	   ASKED_FOR="$ASKED_FOR $1"
	   shift ;;
   esac
done

if [ ."$ASKED_FOR" = ."" ]; then
    SCREEN_TTYS="`screen_ttys`" ; export SCREEN_TTYS
    QUESTIONABLE="`find_ttys $MODE | not_cur_tty | maybe_not_screen_ttys`"
    if [ x"$QUESTIONABLE" = x"usage" ]; then
	usage ; exit 1
    fi
else
    QUESTIONABLE="$ASKED_FOR"
fi

if [ ."$QUESTIONABLE" != ."" ]; then
    if confirm_should_kill $QUESTIONABLE; then
	kill_tty_shells $QUESTIONABLE
    else
	echo "Logins NOT terminated."
    fi
else
    echo "No stale logins found. (Run \"$0 --help\" for instructions.)"
fi
