#!/usr/bin/perl -w
#
# $Header: //depot/equalizer/bugs/bugfix_8.6.1/l7up/l7up.pl#3 $
#
# l7up.pl -     perform upgrade to version supporting l7
#

use	Carp;
require "getopts.pl";

$opt_P		= "/pub/patches";	        # path prefix
$opt_h		= "128.121.100.123";	        # host
$opt_u		= "";				# user:passwd override
$opt_v		= "8.6.0";			# product version #
$opt_X		= 0;
$opt_b		= 0;				# batch mode
$opt_k          = 0;                            # keep keys mode
$opt_S          = 0;
$opt_r          = 0;
$opt_C          = 0;
$opt_G          = 0;
$opt_F          = 0;
$opt_l		= 0;
$batch		= "";
$keys           = "";
$snmp           = "";
$reboot         = "";
$clear          = "";
$lic	        = "";
$gui            = "";
$upgrade_fw     = "";
$outputfile     = "/var/log/eq_upgrade.log";
#
# usage - print usage info
#

sub usage {

    print "usage: l7up.pl <opts>\n";
    print "    [-Ppath]          FTP path override ($opt_P)\n";
    print "    [-hhost]          FTP host ($opt_h)\n";
    print "    [-uuser[:passwd]] FTP user/passwd ($opt_u)\n";
    print "    [-vvers]		 version number ($opt_v)\n";
    print "    [-b]              batch mode\n";
    print "    [-k]              keep SSH keys\b";

    exit 1;
}

#
# note - print an informational message
#

sub note {
    my $arg = shift || "";

    print "$arg\n";
}

#
# sis - perform `system' function and croak if non-zero result.
#

sub sis {
    my $arg = shift or die "";

    #
    # This is perl-ass-backwards, if you can imagine what that is.
    #
    system $arg and die "\n";
}

#
# fetch - fetch a file from the remote repository
#

sub fetch {
    my $what = shift or die "";
    my $user = "";
    my $path = "$opt_P/eq/upgrade-$opt_v/$what";

    $user = "$opt_u" . "@" if $opt_u;

    note "/usr/bin/fetch -p -o $what ftp://$user$opt_h$path";
    sis  "/usr/bin/fetch -p -o $what ftp://$user$opt_h$path";
}

#
# md5_check - check md5 checksum
#

sub md5_check {
    my $what    = shift or die "";
    my $desired = shift or die "";
    my $sum;

    chop($sum = `md5 $what`);

    $sum =~ s/.* = //;

    $sum eq $desired;
}

#
# md5_verify - verify md5 checksum
#

sub md5_verify {
    my $what    = shift or die "";
    my $desired = shift or die "";

    die "$what: md5 mismatch.\n" unless md5_check($what, $desired);
}

#
# fix_stupidity
#

sub fix_stupidity {
    local *BOM;
    local $cwd;

    chop($cwd = `/bin/pwd`);

    return unless $cwd ne "/usr/l7up";
    return unless -f "./BoM";

    mkdir("/usr/l7up", 0755) unless -d "/usr/l7up";
    
    open BOM, "< ./BoM";

    while (<BOM>) {
	chop;

	if (/^md5 /) {
	    my ($ign, $md5, $uid, $gid, $mode, $path) = split;

	    next unless -f "./$path";
	    
	    sis "mv ./$path /usr/l7up/$path";
	}
    }

    close BOM;

    sis "mv ./BoM /usr/l7up/BoM";
    sis "mv ./BoM.md5 /usr/l7up/BoM.md5";
    sis "mv ./l7up.pl /usr/l7up/l7up.pl";
}

#
# setup - perform necessary setup.
#

sub setup {
 
    select(STDOUT); $| = 1;
    select(STDERR); $| = 1;

    &Getopts('Xh:u:p:v:P:bkSrClGF');

    if ($opt_X) {
	fix_stupidity();
	exit 0;
    } 

    if ($opt_b) {
	$batch = " -b";
    }

    if ($opt_k) {
	$keys = " -k";
    }

    if ($opt_S) {
	$snmp = " -S";
    }

    if ($opt_C) {
	$clear = " -C";
    }
    
    if ($opt_l) {
	$lic = " -l";
    }
    
    if ($opt_r) {
	$reboot = " -r";
    }
    
    if ($opt_F) {
	$upgrade_fw = " -F";
    }
    
    if ($opt_G) {
	$gui = " -G";
        open( STDOUT, '>>'.$outputfile ) or die $!;
        open( STDERR, '>>'.$outputfile ) or die $!;
        select(STDOUT); $| = 1;
        select(STDERR); $| = 1;
	
    }
    #
    # We must be in the designated directory.
    #

    mkdir("/usr/l7up", 0755) unless -d "/usr/l7up";
    chdir "/usr/l7up";
    unlink "./.phase1";

    fetch "BoM" unless -f "./BoM";
    fetch "BoM.md5" unless -f "./BoM.md5";

    "Invalid BoM" unless md5_check("./BoM", `cat ./BoM.md5`);
}

#
# bom_suck - suck down the files in the BoM
#

sub bom_suck {
    local *BOM;

    open BOM, "<./BoM" or die "$!: ./BoM";

    while (<BOM>) {
	chop;

	if (/^\# EQVERS=([^:]+)/) {
	    my $v = $1;

	    die "Version mismatch: $opt_v != $v\n" unless $v eq $opt_v;

	    next;
	}

	if (/^md5 /) {
	    my ($ign, $md5, $uid, $gid, $mode, $path) = split;

	    note "verifying file $path";

	    fetch $path unless -f "./$path";
	    md5_verify($path, $md5);

	    sis "chown $uid:$gid $path";
	    chmod $mode, $path or die "$!: chmod $path";
	} elsif (/^exe echo "(.*)"$/) {
	    note "$1";
	} elsif (/^exe (.*)$/) {
	    my $todo = $1;

	    note "executing `$todo$batch$keys$snmp$clear$reboot$gui$upgrade_fw$lic'";

	    sis "$todo$batch$keys$snmp$clear$reboot$gui$upgrade_fw$lic";
	} else {
	    warn "unexpected BoM entry: $_\n";
	}
    }

    close BOM;
}

sub main {
    &setup;
    &bom_suck;
}

&main;
