#!/usr/bin/perl -w
#
# Module: show_version
# 
# **** License ****
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
# 
# This code was originally developed by Vyatta, Inc.
# Portions created by Vyatta are Copyright (C) 2005, 2006, 2007 Vyatta, Inc.
# All Rights Reserved.
# 
# Author: Rick Balocca
# Date: 2007
# Description:
# 
# **** End License ****
# 
use strict;
use warnings;

#
# Global hash of debians in the base install and now.
#
my $rHoH_base_debs;
my $rHoH_now_debs;

my $base          = '/opt/vyatta/etc';
my $versionfile   = "$base/version";
my $buildfile     = "$base/build.txt";
my $debsfile      = "$base/deb-versions.txt";

sub echo_file {
    my ($file) = @_;

    my @lines = ();
    if (!(-e $file)) {
	return @lines;
    }
    
    open(my $FH, '<', $file) or die "Unable to open [$file]\n";
    @lines=<$FH>;
    close($FH);
    return @lines;
}

#
# convert the "dpkg -l" output have same format as deb-versions.txt
#
sub get_pkg_version {
    my @lines = @_;
    
    my @new_lines = ();
    foreach my $line (@lines) {
	if ($line =~ /^[D\|\+]/) {
	    next;   # skip header
	}
	my ($status, $pkg, $version) = split(/[ \t\n]+/, $line, 4);
	if ($status =~ /^i/) {
	    push(@new_lines, "$pkg $version");
	}
    }
    return @new_lines;
}

sub read_pkg_file {
    my @pkgs_list = @_;

    my %HoH = ();
    my ($name, $version);
    foreach my $line (@pkgs_list) {
	($name, $version) = split(/[ \t\n]+/, $line, 3);
	$HoH{$name}{'version'} = $version;
    }
    return \%HoH;
}

sub show_added {
    for my $name (sort keys %$rHoH_now_debs) {
	if (!$rHoH_base_debs->{$name}) {
	    printf("Aii %-25s %-25s\n", 
		   $name, $rHoH_now_debs->{$name}->{'version'});
	}
    }
}

sub show_deleted {
    for my $name (sort keys %$rHoH_base_debs) {
	if (!$rHoH_now_debs->{$name}) {
	    printf("X   %-25s %-25s\n", 
		   $name, $rHoH_base_debs->{$name}->{'version'});
	}
    }
}

sub show_upgraded_downgraded {
    my ($up_down) = @_;
    
    my ($symbol, $op, $ver_base, $ver_now, $cmd);
    if ($up_down eq "upgraded") {
	$symbol = "U";
	$op = "lt";
    } else {
	$symbol = "D";
	$op = "gt";
    }
    for my $name (sort keys %$rHoH_base_debs) {
	if ($rHoH_now_debs->{$name}) {
	    $ver_base = $rHoH_base_debs->{$name}{'version'};
	    $ver_now  =  $rHoH_now_debs->{$name}{'version'};
	    if ($ver_base ne $ver_now) {
		$cmd = "dpkg --compare-versions \"$ver_base\" $op \"$ver_now\"";
		if (!system($cmd)) {
		    printf("%sii %-25s %-20s (baseline: %s)\n", 
			   $symbol, $name, $ver_now, $ver_base);
		}
            }
	} 
    }
}

sub show_upgraded {
    show_upgraded_downgraded("upgraded");
}

sub show_downgraded {
    show_upgraded_downgraded("downgraded");
}

sub show_all {
    show_added();
    show_deleted();
    show_upgraded();
    show_downgraded();
}

my %options = (
    "added"      => \&show_added,
    "deleted",   => \&show_deleted,
    "upgraded"   => \&show_upgraded,
    "downgraded" => \&show_downgraded,
    "all"        => \&show_all,
);

#
# main
#
print(&echo_file($versionfile));
print(&echo_file($buildfile));

my $booted = `grep -e '^unionfs.*/filesystem.squashfs' -e '^aufs.*/filesystem.squashfs' /proc/mounts`;
if (defined($booted) && $booted ne "") {
    $booted="livecd";
} else {
    my $image_boot = `grep -e '^unionfs / unionfs.*squashfs=ro' /proc/mounts`;
    if ($image_boot ne "") {
	$booted="image";
    } else {
	$booted="disk";
    }
}
print "Boot via:     $booted\n";
my $uptime = `uptime`;
if (defined $uptime && $uptime ne "") {
    print "Uptime:      $uptime\n";
}
if (!(-e $debsfile)) {
    exit 0;
}

print "\n";
$rHoH_base_debs = read_pkg_file(&echo_file($debsfile));
$rHoH_now_debs  = read_pkg_file(get_pkg_version(`dpkg -l`));

if ($#ARGV == 0) {
    if ($options{$ARGV[0]}) {
        $options{$ARGV[0]}->();
    } else {
	print "Usage: showversion [added|deleted|upgraded|downgraded|all]\n";
	exit 1;
    }
}
 
# end of file