#!/usr/bin/perl -w
# $Id: dmesg 28 2012-04-28 19:15:03Z sanders $
#
# perly dmesg filter for human readable timestamps
# 
use strict;

my $output_limit = 15; # Show last N lines by default
my $show_age = 1; # Switch to show age of events instead of uptime at event.

foreach my $argv (@ARGV) {
	if ($argv =~ m#-u|--uptime#) {
		$show_age = 0;
	} elsif ($argv =~ m#^(?:-f|--full)$#) {
        $output_limit = -1;
    } elsif ($argv =~ m#^--?(\d+)$#) {
        $output_limit = $1;
    } elsif ($argv =~ m#-h|--help#) {
        showHelp();
    } else {
        print "ignored: $argv\n";
    }
}

open (UPTIME, "</proc/uptime") or die "Can't read /proc/uptime: $!\n";
my $tmp = <UPTIME>; close(UPTIME);
my ($cur_uptime) = $tmp =~ m#([\d\.]+)\s#;

my @lines = ();
open (DMESG, "/bin/dmesg|") or die "Can't exec dmesg: $!\n";
while (my $line = <DMESG>) {
	if ($line =~ /^\[\s*?(\d+\.\d+)\]\s/) {
		my $uptime_at_event = $1;

		my $diff = 0;
		if ($show_age) {
			$diff = $cur_uptime - $uptime_at_event;
		} else {
			$diff = $uptime_at_event;
		}

		my $day = int($diff / 86400); $diff -= ($day * 86400);
		my $hrs = int($diff / 3600); $diff -= ($hrs * 3600);
		my $min = int($diff / 60); $diff -= ($min * 60);
		my $sec = $diff;

		my $formatted = sprintf("%03dd%02dh%02dm%02ds", $day, $hrs, $min, $sec);
		$line =~ s/^\[\s*?\d+\.\d+\]/[$formatted]/;
		push @lines, $line;
	}
}
close(DMESG);

# Add a little bit of fairydust
my $linecount = scalar(@lines);
my $offset = $linecount - $output_limit;
$offset = 0 if ($output_limit == -1 or $output_limit > $linecount);
shift @lines while ($offset--);
print join "", @lines;
exit 0;

########

sub showHelp {
    print "dmesg filter\n";
    print "\n";
    print " -u   --uptime    Display events timed since boot (default dmesg style)\n";
    print " -f   --full      Display entire dmesg buffer\n";
    print " -NN  --NN        Display last NN lines of dmesg buffer\n";
    exit 0;
}
