#!/usr/bin/perl -w

# apt-dater - terminal-based remote package update manager
#
# Authors:
#   Andre Ellguth <ellguth@ibh.de>
#   Thomas Liske <liske@ibh.de>
#
# Copyright Holder:
#   2008-2012 (C) IBH IT-Service GmbH [http://www.ibh.de/apt-dater/]
#
# License:
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   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.
#
#   You should have received a copy of the GNU General Public License
#   along with this package; if not, write to the Free Software
#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
#

use strict;

my $CMD = shift;
my $ADPROTO = '0.5';
my $UUIDFILE = '/etc/apt-dater-host.uuid';

$ENV{'LC_ALL'} = 'C';

die "Don't call this script directly!\n" unless (defined($CMD));
if($CMD eq 'sshkey') {
    die "Sorry, no shell access allowed!\n"
      unless(defined($ENV{'SSH_ORIGINAL_COMMAND'}));

    @ARGV = split(' ', $ENV{'SSH_ORIGINAL_COMMAND'});

    shift;
    $CMD = shift;
}
die "Invalid command '$CMD'!\n" unless ($CMD=~/^(refresh|status|upgrade|install|kernel)$/);

if ($CMD eq 'refresh') {
    print "ADPROTO: $ADPROTO\n";
    &do_status;
    &do_kernel;
}
elsif ($CMD eq 'status') {
    print "ADPROTO: $ADPROTO\n";
    &do_status;
    &do_kernel;
}
elsif ($CMD eq 'upgrade') {
    &do_upgrade;
}
elsif ($CMD eq 'install') {
    &do_install(@ARGV);
}
elsif ($CMD eq 'kernel') {
    print "ADPROTO: $ADPROTO\n";
    &do_kernel;
}
else {
    die "Internal error!\n";
}

sub get_virt() {
    return "Unknown" unless (-x '/usr/bin/imvirt');

    my $imvirt;
    chomp($imvirt = `/usr/bin/imvirt`);

    return $imvirt;
}

sub get_uname() {
    my $kernel;
    my $machine;

    chomp($kernel = `uname -s`);
    chomp($machine = `uname -m`);
    return "$kernel|$machine";
}

sub do_status() {
    # retrieve lsb informations
    unless (open(HLSB, "lsb_release -a 2> /dev/null |")) {
	print "\nADPERR: Failed to execute 'lsb_release -a' ($!).\n";
	exit(1);
    }
    my %lsb;
    while(<HLSB>) {
	chomp;

	$lsb{$1}=$2 if (/^(Distributor ID|Release|Codename):\s+(\S.*)$/);
    }
    close(HLSB);
    print "LSBREL: $lsb{'Distributor ID'}|$lsb{'Release'}|$lsb{'Codename'}\n";

    # retrieve virtualization informations
    print "VIRT: ".&get_virt."\n";

    # retrieve uname informations
    print "UNAME: ".&get_uname."\n";

    # rpm is readonly, so forbid anything!
    print "FORBID: 255\n";

    # add installation UUID if available
    if(-r $UUIDFILE && -s $UUIDFILE) {
	print "UUID: ", `head -n 1 "$UUIDFILE"`;
    }

    # get version of installed packages
    my %installed;
    my %status;
    unless(open(HDPKG, "rpm -qa --qf '%{NAME}\t%{VERSION}-%{RELEASE}\ti\n' |")) {
	print "\nADPERR: Failed to execute 'rpm -qa --qf '%{NAME}\\t%{VERSION}-%{RELEASE}\\ti\\n' ($!).\n";
	exit(1);
    }
    while(<HDPKG>) {
	chomp;

	next unless (/^(\S+)\s+(\S+)\s+(\S+)/);
	$installed{$1} = $2 ;
	$status{$1} = substr($3, 0, 1);
    }
    close(HDPKG);
    
    foreach my $pkg (keys %installed) {
	print "STATUS: $pkg|$installed{$pkg}|$status{$pkg}\n";
    }
}

sub do_upgrade() {
    # not implemented
    print STDERR "\n\n** Sorry, apt-dater based upgrades on this host are not supported! **\n\n";
}

sub do_install() {
    # not implemented
    print STDERR "\n\n** Sorry, apt-dater based installations on this host are not supported! **\n\n";
}

sub do_kernel() {
    my $infostr = 'KERNELINFO:';
    my $version = `uname -r`;
    chomp($version);

    my $ver = $version;
    my $rel = '';
    my $add = '';
    $add = $1 if($version =~ /([a-z]+)$/);
    ($ver, $rel) = ($1, $2) if($version =~ /(.+)-([^-]+)$add$/);

    $add = "-$add" if($add);

    my $kinstalled;
    my $distri = 0;
    unless(open(HKERNEL, "rpm -q --whatprovides kernel$add --qf '%{NAME}\t%{VERSION}\t%{RELEASE}\n' |")) {
	print "\nADPERR: Failed to execute 'rpm -q --whatprovides kernel$add --qf '%{NAME}\\t%{VERSION}\\t%{RELEASE}\\n' ($!).\n";
	exit(1);
    }
    while(<HKERNEL>) {
	if(/^\S+\s+(\S+)\s+(\S+)/) {
	    if($ver eq $1) {
		$distri = 1;
		
		if(!$kinstalled) {
		    $kinstalled = $2;
		}
		else {
		    $kinstalled = $2 if(&versioncmp($kinstalled, $2) < 0);
		}
	    }
	}
    }
    close(HKERNEL);

    unless($distri) {
	print "$infostr 2 $version\n";
	return;
    }

    unless($kinstalled cmp $rel) {
	print "$infostr 0 $version\n";
	return;
    }
    print "$infostr 1 $version\n";
}

##
# Taken from Sort::Versions 1.4
# Copyright (c) 1996, Kenneth J. Albanowski.
##
sub versioncmp() {
    my @A = ($_[0] =~ /([-.]|\d+|[^-.\d]+)/g);
    my @B = ($_[1] =~ /([-.]|\d+|[^-.\d]+)/g);

    my ($A, $B);
    while (@A and @B) {
	$A = shift @A;
	$B = shift @B;
	if ($A eq '-' and $B eq '-') {
	    next;
	} elsif ( $A eq '-' ) {
	    return -1;
	} elsif ( $B eq '-') {
	    return 1;
	} elsif ($A eq '.' and $B eq '.') {
	    next;
	} elsif ( $A eq '.' ) {
	    return -1;
	} elsif ( $B eq '.' ) {
	    return 1;
	} elsif ($A =~ /^\d+$/ and $B =~ /^\d+$/) {
	    if ($A =~ /^0/ || $B =~ /^0/) {
		return $A cmp $B if $A cmp $B;
	    } else {
		return $A <=> $B if $A <=> $B;
	    }
	} else {
	    $A = uc $A;
	    $B = uc $B;
	    return $A cmp $B if $A cmp $B;
	}	
    }
    @A <=> @B;
}
