#!/bin/sh
# -*- mode: tcl -*-
# ALL the continued lines following this one are interpreted
# by the bourne shell and ignored by Tcl, which picks up
# execution after the exec line.\
exec `which tclsh` "$0" ${1+"$@"}

set ::ExitCode(OK)		0
set ::ExitCode(USER)		1
set ::ExitCode(NO_AGENT)	2

set ::LDAS_ROOT "/ldas"
set ::LDAS_OUTGOING_ROOT "/ldas_outgoing"
set SSH_AGENT_MGR "$::LDAS_ROOT/bin/ssh-agent-mgr"
set AGENT_FILE "${LDAS_OUTGOING_ROOT}/managerAPI/.ldas-agent"


set ::KillInteractively 0
set ::KillSearchUserInteractively 0
set ::SMF 0
set ::LDAS_PS ${::LDAS_ROOT}/bin/ldas-processes

if { [info exists ::env(SMF_FMRI)] } {
    # Started by Solaris' Service Management Facility
    set ::SMF 1
}

if { [ file executable "[file dirname $argv0]/ssh-agent-mgr" ] } {
    set SSH_AGENT_MGR "[file dirname $argv0]/ssh-agent-mgr"
}

proc Usage { } {
    set msg "Usage: $::argv0 \[--help\] \[--kill-search-user-interactively\]\n"
    set msg "${msg}--help          - Gives this usage message\n"
    set msg "${msg}--kill-interactively\n"
    set msg "${msg}                - Kill non-search user jobs interactively\n"
    set msg "${msg}--kill-search-user-interactively\n"
    set msg "${msg}                - Kill search user jobs interactively\n"

    pute 0 $msg
}

proc pute { ExitCode Message } {
    if { ! $::SMF } {
	puts stderr $Message
    }
    exit $ExitCode
}

proc put_warn { Message } {
    if { ! $::SMF } {
	puts stderr $Message
    }
}

proc put_debug { Message } {
    if { ! $::SMF } {
	puts stderr $Message
    }
}

proc put_info { Message } {
    if { ! $::SMF } {
	puts $Message
    }
}

proc NodeCompare { a b } {
    set asearch [ lindex $a 1 ]
    set bsearch [ lindex $b 1 ]
    set res [ string compare $asearch $bsearch ]
    if { $res != 0 } {
	return $res
    }
    set apid [ lindex $a 0 ]
    set bpid [ lindex $b 0 ]
    if { $apid == $bpid } {
	return 0
    } elseif { $apid < $bpid } {
	return -1
    }
    return 1
}

proc rkill { Host User Process { SearchUser "" } } {
    set ssh_host ""
    set rsh_cmd ""
    if { [ llength $Host ] == 2 } {
	set ssh_host [ lindex $Host 0 ]
	set rsh_host [ lindex $Host 1 ]
    } else {
	set ssh_host [ lindex $Host 0 ]
	set rsh_host [ lindex $Host 0 ]
    }
    if { ! [ string match $ssh_host $rsh_host ] } {
	if { [ string length $SearchUser ] > 0 } {
	    set rsh_cmd "rsh $rsh_host -l $SearchUser"
	}
    } else {
	if { [ string length $SearchUser ] > 0 } {
	    set ssh_host "${SearchUser}@${ssh_host}"
	}
    }
    if [ catch { set processes [ exec ssh $ssh_host $rsh_cmd kill -9 $Process ] } err ] {
	# :TODO: Need to do something more intelligent than just return
	# :TODO:  an empty string
	put_warn $err
	return ""
    }
}

proc rps { Host User Processes } {
    set ssh_host ""
    set rsh_cmd ""
    if { [ llength $Host ] == 2 } {
	set ssh_host [ lindex $Host 0 ]
	set rsh_host [ lindex $Host 1 ]
    } else {
	set ssh_host [ lindex $Host 0 ]
	set rsh_host [ lindex $Host 0 ]
    }
    if { ! [ string match $ssh_host $rsh_host ] } {
	set rsh_cmd "rsh $rsh_host"
    }
    upvar $Processes retval
    if { [ info exists retval ] } {
	# Ensure we are always working with an empty list
	unset retval
    }
    if [ catch { set processes [ exec ssh $ssh_host $rsh_cmd ${::LDAS_PS} -o pid,user,args ] } err ] {
	# :TODO: Need to do something more intelligent than just return
	# :TODO:  an empty string
	put_warn $err
	return ""
    }
    unset err
    set pattern {([^/]*/|)tclsh[ \t]}
    set test_scripts {(pipeloop|looptool)}
    foreach line [ split $processes '\n' ] {
	catch {
	    regexp {^[ \t]*([0-9]+)[ \t]+([A-Za-z0-9]+)[ \t]+(.*)$} $line -> \
		pid user cmd
	    if { $pid == [ pid ] } {
		# Exclude ourselves from the list
		continue
	    }
	    if { [ string match $User $::env(USER) ] } {
		# Processes to exclude as the 'ldas' user
		if { ! [ string match $User $user ] ||
		     ! [ regexp -- $pattern $line match ] ||
		     [ regexp -- $test_scripts $line match ] } {
		    continue
		}
		set retval($pid) [ list $user $cmd ]
	    } else {
		# Processes to exclude as the 'search' user
		if { ! [ regexp $User $user match ] } {
		    continue
		}
		set retval($pid) [ list $user $cmd ]
	    }
	}
	if { [ info exists err ] } {
	    put_debug "DEBUG: err: $err"
	    unset err
	}
    }
}

#------------------------------------------------------------------------
# Make sure that this program is run by the owner of the AGENT file
# :TODO: Allow for other user than ldas
#------------------------------------------------------------------------
if { ! [ string match ldas $::env(USER) ] } {
	pute $::ExitCode(USER) "This program must be run as user 'ldas'"
}
#------------------------------------------------------------------------
# Parse command line options
#------------------------------------------------------------------------
for { set idx 0 } { $idx < $::argc } { incr idx } {
    switch -exact -- [ lindex $::argv $idx ] {
	--help {
	    Usage
	}
	--kill-interactively {
	    set ::KillInteractively 1
	}
	--kill-search-user-interactively {
	    set ::KillSearchUserInteractively 1
	}
    }
}
#------------------------------------------------------------------------
# Get information about the the ssh-agent
#------------------------------------------------------------------------
if { ! $::SMF } {
    if { [ catch {set ::agent_env [ exec $::SSH_AGENT_MGR --shell=tclsh --agent-file=$::AGENT_FILE check 2> /dev/null ] } err ] } {
	# Attempt to add keys to the agent
	if { [ catch {set ::agent_env [ exec $::SSH_AGENT_MGR --shell=tclsh --agent-file=$::AGENT_FILE addkeys 2> /dev/null ] } err ] } {
	    # Attempt to start the agent
	    if { [ catch {set ::agent_env [ exec $::SSH_AGENT_MGR --shell=tclsh --agent-file=$::AGENT_FILE restart 2> /dev/null ] } err ] } {
		pute $::ExitCode(NO_AGENT) "Unable to connect to the ssh-agent"
		exec $::SSH_AGENT_MGR --shell=tclsh --agent-file=$::AGENT_FILE stop 2> /dev/null
	    }
	}
    }
    eval $::agent_env
}
#------------------------------------------------------------------------
# Check all hosts associated with the various APIs
#------------------------------------------------------------------------
source $LDAS_OUTGOING_ROOT/LDASapi.rsc
if { [ info exists ::Hosts ] } {
    unset ::Hosts
}
foreach api $::API_LIST {
    set api_name  "::[string toupper $api]_API_HOST"
    if { [info exists $::api_name] } {
	set ::Hosts([ set $api_name ]) [ set $api_name ]
    }
}
if { ! $::SMF } {
    set ttyid [ open /dev/tty r ]
}
foreach host [ array names ::Hosts ] {
    put_info "Querying: $host"
    rps $host $::env(USER) processes
    foreach cmd [ lsort -integer [ array names processes ] ] {
	if { $::KillInteractively && ! $::SMF } {
	    put_info [ format "KILL? %6d %-10s %s" $cmd \
			   [ lindex $processes($cmd) 0 ] \
			   [ lindex $processes($cmd) 1 ] ]
	    switch -regexp -- [ gets $ttyid ] {
		{^[Yy].*} {
		    rkill $host $::env(USER) $cmd
		}
	    }
	} else {
	    put_info [ format "KILLING: %6d %-10s %s" $cmd \
			   [ lindex $processes($cmd) 0 ] \
			   [ lindex $processes($cmd) 1 ] ]
	    rkill $host $::env(USER) \
		[ lindex $cmd 0 ] \
		[ lindex $cmd 1 ]
	}
    }
}
#------------------------------------------------------------------------
# Check for processes started by search users
#------------------------------------------------------------------------
if { ! $::SMF } {
    if { [expr [lsearch -exact $::API_LIST mpi ] >= 0] \
	     && [info exists ::MPI_API_HOST] } {
	source $LDAS_OUTGOING_ROOT/mpiAPI/LDASmpi.rsc
	if { [ info exists ::NODENAMES ] } {
	    foreach node $::NODENAMES {
		set node_list($node) $node
	    }
	    foreach node [ lsort [ array names ::node_list ] ] {
		put_info "Querying Node: $node"
		set host [ list $::MPI_API_HOST $node ]
		rps $host search processes
		set node_ps [ list ]
		foreach cmd [ array names processes ] {
		    lappend node_ps [ concat $cmd $processes($cmd) ]
		}
		set node_ps [ lsort -command NodeCompare $node_ps ]
		foreach cmd $node_ps {
		    if { $::KillSearchUserInteractively && ! $::SMF } {
			put_info [ format "KILL? %6d %-10s %s" \
				       [ lindex $cmd 0 ] [ lindex $cmd 1 ] [ lindex $cmd 2 ] ]
			switch -regexp -- [ gets $ttyid ] {
			    {^[Yy].*} {
				rkill $host $::env(USER) \
				    [ lindex $cmd 0 ] \
				    [ lindex $cmd 1 ]
			    }
			}
		    } else {
			put_info [ format "KILLING: %6d %-10s %s" \
				       [ lindex $cmd 0 ] [ lindex $cmd 1 ] [ lindex $cmd 2 ] ]
			rkill $host $::env(USER) \
			    [ lindex $cmd 0 ] \
			    [ lindex $cmd 1 ]
		    }
		}
	    }
	}
    } ;# if [info exists MPI_API_HOST]
}
if { ! $::SMF } {
    close $ttyid
}
