#!/usr/bin/perl
#
# Chris Vanhoof <vanhoof@redhat.com>
#
# Simple sysrq-t parser -- Reads either netdump log, or /var/log/messages
# and prints out the name of the proc, pid, state (user specified), and parent pid.
# Makes my life easier in tracking down troublesome processes
#
# ex: perl sysrq-t_parser.pl --input_file=/var/log/messages --process_state=S
# 	init(1) is in a state of 'S'
# 	khelper(4) is in a state of 'S', whose parent is 3
#

use strict;
use Getopt::Long;
use Benchmark;

my $input_file;
my $process_state;

my $stdin_results = GetOptions(
	'input_file:s'	   => \$input_file,
	'process_state:s'  => \$process_state
);

if ((! $input_file) || (! $process_state)) {
	die("Usage: $0 --input_file=/path/to/input/file --process_state=D|R|S|Z"."\n");
}

if ($process_state !~ m/D|R|S|Z/){
	die("process state must be D|R|S|Z");
}

if (! -e $input_file) {
	die("$input_file does not exist..."."\n");
}

my $t0 = new Benchmark;

open(FILE, $input_file);
my @lines = <FILE>; 
close(FILE);

my $iteration = 0;

my %message_has_been_printed_before_hash;
my %process_pid_to_name_hash;

foreach my $line (@lines) {
	my ($process_name, $process_state_output, $process_pid, $process_parent_pid);
	my $message;

        if ($line =~ m/^\w+\s\d+\s\d+:\d+:\d+\s\w+\s\w+:\s([\w\/]+)\s+($process_state)\s+.{8}\s+\d+\s+(\d+)\s+(\d+).*/) {
		($process_name, $process_state_output, $process_pid, $process_parent_pid) = ($1, $2, $3, $4);	
        } elsif ($line =~ m/^([\w\/]+)\s+($process_state)\s+.{8}\s+\d+\s+(\d+)\s+(\d+).*/) {
		($process_name, $process_state_output, $process_pid, $process_parent_pid) = ($1, $2, $3, $4);
	}
	else {
		next;
	}

	$message = "$process_name($process_pid) is in a state of \'$process_state_output\'";
	$message .= ", whose parent is $process_parent_pid" if ($process_parent_pid);

	$process_pid_to_name_hash{$process_pid} = $process_name;
	$message_has_been_printed_before_hash{$message} = $process_parent_pid;
	$iteration++;
}

my @messages = keys %message_has_been_printed_before_hash;
@messages = sort {
	my $a_value = $a;
	my $b_value = $b;

	$a_value =~ s/^[\w\/]*\((\d+)\).*$/$1/msg;
	$b_value =~ s/^[\w\/]*\((\d+)\).*$/$1/msg;

	return $a_value <=> $b_value;
} @messages;

foreach my $message (@messages){
	next if (! $message);
	my $process_parent_pid = $message_has_been_printed_before_hash{$message};
	if ($process_parent_pid){
		my $process_parent_name = $process_pid_to_name_hash{$process_parent_pid};
		$message =~ s/$process_parent_pid$//msg;
		$message .= $process_parent_name.'('.$process_parent_pid.')';
	}
	print $message."\n";
}

if (! (keys %message_has_been_printed_before_hash)){
	die("no matches found..."."\n");
}

my $t1 = new Benchmark;
my $td = timediff($t1, $t0);
print "$0 took: ".timestr($td)." \@ $iteration passes"."\n";


__DATA__

$1 process name
$2 process state
$3 process pid
$4 process parent pid
