#!/usr/bin/env perl 
# $Id: ckillnode.in 188 2011-01-22 00:21:28Z gvh $
#
#               C3 Cluster Command & Control Suite
#           Oak Ridge National Laboratory, Oak Ridge, TN,
#     Authors:  M.Brim, R.Flanery, G.A.Geist, B.Luethke, S.L.Scott
#                 (C) 2007 All Rights Reserved
# 
#                             NOTICE
# 
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby granted
# provided that the above copyright notice appear in all copies and
# that both the copyright notice and this permission notice appear in
# supporting documentation.
# 
# Neither the Oak Ridge National Laboratory nor the Authors make any
# representations about the suitability of this software for any
# purpose.  This software is provided "as is" without express or
# implied warranty.
 
# The C3 tools were funded by the U.S. Department of Energy.
 

# ckillnode - used by ckill[s] to kill a process on a node
# Author: Brian Luethke 
# Last Updated: 05/22/2007

# declare modules
use Getopt::Long;

my $c3_version = '5.1.1';


# set help information
$help_info = $version_info . <<"EOF";
Usage: ckillnode [OPTIONS] --signal=signal --process=processName 

	-h, --help 			: get this message
	-p, --process processName	: name of process to kill 
					  (not PID or job number)
	-s, --signal signal		: signal to send to process, same as 
					  standard 'kill'
	-u, --user username		: user name of the process owner 
					  (root user only)
	-v, --version			: get the version information

EOF

# interpret command line options
GetOptions( "help|h",
	    "signal|s=s",
	    "process|p=s",
	    "user|u=s",
	    "version|v"
);

# if not enough arguments are given at the command line, 
# quit with the help message
if ( !$opt_signal ) {
	$opt_signal = "" }
else {
	$opt_signal = "-$opt_signal";}
	
if ( $opt_version ) {
	print $c3_version . "\n";
	exit(0);
}

if ( !$opt_process || $opt_help ) { die qq($help_info); };
if ( $opt_user  && $< != 0 ) { die "must be root to specify a user\n"; }

$opt_help =""; #this quiets intepreter warnings


if( $opt_user ne "NONE" && $opt_user ne "ALL" ) {
  open( ETC_PASSWD, "< /etc/passwd" ) or die "couldn't open /etc/passwd\n";

  while (<ETC_PASSWD>) {
    chomp( $_ );
    if( $_ =~ /($opt_user):(.*):(.*):(.*):(.*):(.*):.(.*)/ ) {
      $uid = $3;
    }
  }
  if( !$uid ) { die "Could not find user $opt_user\n"; }
  close( ETC_PASSWD );
}

if( $opt_user eq "ALL" ) { $uid = ".*"; }

if( !$opt_user ) { $uid = $<; }



print "uid selected is $uid\n";

my $pid;
my $task = "";

# Note: we use args to avoid to have a truncated process name (limited to 15
# characters on Linux systems). So we use args, which gives us the full command
# string and we will later parse it to get the process name.
system ("ps -eo uid,pid,args > /tmp/ps_temp_$<" );

open( PS_OUTPUT, "< /tmp/ps_temp_$<" ) or 
  die "couldn't open /tmp/ps_temp_$<\n";
while( <PS_OUTPUT> ) {
  my $l = $_;
  # We extract the pid and the args from the ps output
  if ($l =~ /\s+$uid\s+(\w+)\s+(.*)/) {
    $pid = $1;
    $task = $2;
  }
  # Now from the args, we get the first element, which is the binary path or
  # the command
  my @a = split (" ", $task);
  $task = $a[0];
  # Then we clean up...
  # if we have a path, we only care about the last part of the path, i.e., the
  # binary name.
  if ($task =~ /\/(.*)\/(.*)/) {
    $task = $2;
  }
  # Sometimes, we have a ":" at the end, we just remove it (thanks ps!)
  if ($task =~ /(.*)\:$/) {
    $task = $1;
  }   # Sometime, we have the cmd in between brackets, we just remove them
  if ($task =~ /^\[(.*)\]/) {
    $task = $1;
  }
  if( $task eq $opt_process )   {
    system ( "kill $opt_signal $pid" );
  }
}

exit( 0 );

# vim:tabstop=4:shiftwidth=4:noexpandtab:textwidth=76
