#!/usr/bin/env perl

# This script is used to flash the mics on the host.
# This script is run by xdsh from MN/SN to the host
# parameters
#  -m xcatmaster
#  -p the path of the mic configuration file. Generally, it's /tftpboot/xcat/miccfg/micflash.hostname

use strict;
use IO::Socket;

use File::Path;
use File::Copy;
use Getopt::Long;

# enable the autoflush of stdout
select STDOUT;
$| = 1;

my $tmppath   = "/tmp/mictmp";
my $logpath   = "/var/log/xcat/";
my $logfile   = "$logpath/flash.log";
my $micmnt    = "/var/mpss/mnt";
my $flashpath = "$micmnt/usr/share/mpss/flash";

if (!-d "$flashpath") {
    $flashpath = "/usr/share/mpss/flash";
}

mkpath $tmppath;
mkpath $micmnt;

#open the log file
open(LOG, ">>$logfile") or die "Error: cannot open $logfile\n";
print LOG "\n\n====================================================\nStart mic flashing: " . `date` . "\n";

my ($master, $cfgpath);
GetOptions('m=s' => \$master, 'p=s' => \$cfgpath);
unless ($master && $cfgpath) {
    outputmsg("Error: the -m master and -p path arguments must be specified for configmic.\n", 1);
}

# get the correct host name for the host
my ($nodename, $nodename_short);
my $masterip = `getent hosts $master | awk {'print \$1'}`;
if ($masterip) {
    chomp($masterip);
    my $myip = `ip route get $masterip| head -n 1 | sed 's/^.*src//g' | awk {'print \$1'}`;
    if ($myip) {
        my $myipinfo = `getent hosts $myip`;

        if ($myipinfo && $myipinfo =~ /([^\s]+)\s+([^\s]+)\s+([^\s]+)/) {
            my $n1 = $2;
            my $n2 = $3;
            if (length($n1) > length($n2)) {
                $nodename_short = $n2;
            } else {
                $nodename = $n1;
            }
        } elsif ($myipinfo && $myipinfo =~ /([^\s]+)\s+([^\s]+)/) {
            $nodename_short = $2;
        }
    }
}
unless ($nodename) {
    $nodename = `hostname`;
    chomp($nodename);
}
unless ($nodename_short) {
    $nodename_short = `hostname -s`;
    chomp($nodename_short);
}

# download the mic configuration file from master
my $cmd = "wget -N --waitretry=10 --random-wait -T 60 http://$master/$cfgpath/micflash.$nodename_short -P $tmppath";
my ($rc, $output) = runsyscmd($cmd);
if ($rc) {
    $cmd = "wget -N --waitretry=10 --random-wait -T 60 http://$master/$cfgpath/micflash.$nodename -P $tmppath";
    runsyscmd($cmd, "Error: failed to download mic configuration file from $master\n", 3);
}

unless (-r "$tmppath/micflash.$nodename") {
    runsyscmd("Error: cannot get the mic configuration file from http://$master/$cfgpath/micflash.$nodename\n", 4);
}

# parse the configuration file
unless (open(CFGFILE, "<$tmppath/micflash.$nodename")) {
    runsyscmd("Error: cannot open $tmppath/micflash.$nodename\n", 5);
}

# the configureation file should have the following format
#miclist=mic0
#0:name=host1-mic0
#imgpath=/install/mpss3.new

my %miccfg;
my $miclist;
my $ospath;
while (<CFGFILE>) {
    if (/(\d+):(.*)/) {
        my $deviceid = $1;
        my @params = split(/\|/, $2);
        foreach (@params) {
            my ($n, $v) = split(/=/, $_);
            $miccfg{$deviceid}{$n} = $v;
        }
    } elsif (/^miclist=(.*)/) {
        $miclist = $1;
    } elsif (/^imgpath=(.*)/) {
        $ospath = $1;
    }
}
close(CFGFILE);

$miclist =~ s/,/ /g;

# add the mount entry for mounting of root fs from master to /etc/fstab
# e.g. mount $master:/install/mpss3 /var/mpss/mnt
$cmd = "grep \'$master:$ospath \' $micmnt /etc/fstab ";
($rc, $output) = runsyscmd($cmd);
if ($rc) {

    # not found the exact mount entry
    $cmd = "grep $micmnt /etc/fstab";
    ($rc, $output) = runsyscmd($cmd);
    if (!$rc) {

        # found the mount to $micmnt with another master or directory, remove the entry and umount it
        my $trans = $micmnt;
        $trans =~ s/\//\\\//g;
        $cmd = "sed \"/$trans/d\" /etc/fstab > $tmppath/fstab.tmp";
        runsyscmd($cmd, "Error: failed to configure fstab.\n", 6);
        copy("$tmppath/fstab.tmp", "/etc/fstab");
        $cmd = "umount -l -f $micmnt";
        runsyscmd($cmd, "Error: failed to run umount -l -f $micmnt\n", 7);
    }
    $cmd = "echo \"$master:$ospath $micmnt nfs timeo=14,intr 1 2\" >>/etc/fstab";
    runsyscmd($cmd);
    $cmd = "mount -a";
    runsyscmd($cmd);
}

# make sure the remote flash directory is accessable
unless (-d "$flashpath") {
    outputmsg("Error: cannot access the $flashpath.\n", 8);
}

# start to flash the mic
# #
# # reset the mic to ready stat
$cmd = "micctrl -r -w $miclist";
($rc, $output) = runsyscmd($cmd, "Error: failed to reset mic.\n", 100);

my $micidlist;
foreach my $micid (keys %miccfg) {
    unless (grep /mic$micid: ready/, @$output) {
        outputmsg("MICMSG:$miccfg{$micid}{'name'}: Error: failed to reset mic to ready stat.\n", 100);
    }
    $micidlist .= ",$micid";
}

$micidlist =~ s/^,//;

# do the flash
$cmd = "micflash -update $flashpath -device $micidlist";
($rc, $output) = runsyscmd($cmd);

# generate the output messages
foreach (@$output) {
    foreach my $line (split /\n/, $_) {
        if ($line =~ /^mic(\d+):/) {
            $line =~ s/^mic(\d+):/MICMSG:$miccfg{$1}{'name'}:/;
        }
        print $line . "\n";
    }
}

print LOG "\nFinish the mic flashing: " . `date` . "====================================================\n";

close(LOG);

exit 0;

# run command
sub runsyscmd {
    my $cmd    = shift;
    my $errmsg = shift;
    my $rc     = shift;

    print LOG "---------------------------------------------\n";
    print LOG "Run command: $cmd\n";

    if (!($cmd =~ /2>&1$/)) { $cmd .= ' 2>&1'; }
    my @output = `$cmd`;

    my $errcode = 0;
    if ($?) {
        $errcode = $? >> 8;
    }

    foreach (@output) {
        print LOG $_;
    }
    print LOG "---------------------------------------------\n";

    if ($rc && $errcode) {
        outputmsg($errmsg, $rc);
        exit $rc;
    }
    return ($errcode, \@output);
}

# display the output message
sub outputmsg {
    my $msg = shift;
    my $rc  = shift;
    print LOG $msg;
    print $msg;
    if ($rc) {
        exit $rc;
    }
}

