#!/usr/bin/perl
##############################################################################################
# © Copyright 2000-2007 Hewlett-Packard Development Company, L.P
#
# 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 program; 
# if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##############################################################################################
# retrofit LinuxCOE 3.1 Bundles - leem@hp.com
# 
# To retrofit your system:
#  1) chmod +x retrofit (or whatever you named this file)
#  2) as root, run it with no arguments: # ./retrofit
#
# If you run this script with any argument, it won't install anything, but 
#   will echo what it would have done.  Feel free to try this as a mortal user
#   to see what we're proposing.  Ex: '# ./retrofit LinuxRox'
#
# Here's what this script will attempt:
#  0) Remove old LinuxCOE spcific RPMS if they exist
#  1) Send email with your MAC address for statistical purposes only!
#       - it's only your MAC, and we want to count unique installs...
#  2) Install APT || YUM, if it fails, create a rc snippet that will install it n
#      next boot.
#  3) Create /etc/opt/LinuxCOE/apt || yum dir if it doesn't exist (owned by apt)
#  4) Create files for each requested coe_bundle in above dir
#  5) call Bundle installer to walk dir and install coe_bundles
#
# All our docs:  http://linuxcoe.corp.hp.com/documentation/
# Problems/Bugs: http://linuxcoe.corp.hp.com/sr/
#

my $dont_do_it = 0;
my $YUM;
if ($ARGV[0]) { $dont_do_it = 1 }   # Don't really do anything!

# Create a logfile so we can help troubleshoot errors
my $log = "/var/log/LinuxCOE-retrofit.log";
open(LOG,">$log") ||  print STDERR "Cannot open $log : $!\n What's up with that? :)\n\n";
print LOG "It's a dry run! :^)\n" if ( $dont_do_it );

# Make everything hot, I'm forking...
select(LOG); $|=1;
select(STDOUT); $|=1;
select(STDERR); $|=1;

# Send in MAC (should be unique and innocent) for mgmt counter
print LOG "Sending in MAC for counter...\n";
if ( $dont_do_it ) {
  print "Would have sent the following email:\n /sbin/ifconfig | /bin/mail -s Retrofit retrofit\@linuxcoe.corp.hp.com\n";
} else {
  system '/sbin/ifconfig | /bin/mail -s Retrofit retrofit@linuxcoe.corp.hp.com';
}

print LOG "Scroll down to ===START=== for the real action.\n";

# If old version exists, get rid of it, as some of the older stuff won't
#  upgrade and we went through many RPM name changes, will solidify at 3.2

my $installed = `/bin/rpm -q linuxcoe`;
unless ( $installed =~ /package/ ) { &Remove_Old }

if ( $dont_do_it ) {
  print "Would have created APT/YUM breadcrumbs in /etc/opt/LinuxCOE/\n";
} else {
# LINUXCOE_PERL_HERE
}

# Load an %array of installed rpms....
print STDERR "Creating a list of installed rpms for comparison.\n";
my %installed = &load_installed;

# this %array created by /systemdesigner-cgi-bin/coe_retrofit
my %bundles = (

# REAL_DATA_HERE

);

# Snatch the waystation they selected
#  note to self: do not name a valid bundle 'WaYsTaTiOn' ;p

my $waystation = $bundles{'WaYsTaTiOn'};
delete($bundles{'WaYsTaTiOn'}); # let's not load this one!

print LOG " ===START=== \n";
print LOG "My Waystation is $waystation\n";

if ($dont_do_it ) {

  print "Would have created breadcrumbs for APT/YUM/RHN configuration.\n";

} else {

  open(WAY,">/etc/opt/LinuxCOE/waystation");
  print WAY "$waystation\n";
  close(WAY);

# APT_DEPOTS_HERE

}

# If they're retrofitting, they might be adding/deleting new addons.
# Re-run config scripts if they exist

if ( $dont_do_it ) {
  print STDOUT "Would have reconfigured apt/yum if installed\n";
} else {
  if ( -x "/opt/LinuxCOE/bin/configure_yum" ) { system "/opt/LinuxCOE/bin/configure_yum" }
  if ( -x "/opt/LinuxCOE/bin/configure_apt" ) { system "/opt/LinuxCOE/bin/configure_apt" }
}

#
# main()  - here's the meat!
#

# Walk the bundles they selected and load them as needed

foreach $bundle (sort(keys(%bundles))) {
  &load_bundle($bundle,$bundles{$bundle},$waystation);
}

my %coe_bundles = (
# COE_BUNDLES_HERE
);

my $ddir;
foreach my $bundle (sort(keys(%coe_bundles))) {
  my $outfile = $bundle;
  $outfile =~ tr/a-zA-z0-9/_/cs;
  $outfile = "/etc/opt/LinuxCOE/sw/$outfile";
  if ( $dont_do_it ) {
    print STDERR "Would have created $outfile to install $bundle\n";
  } else {
    open(OUT,">$outfile") || die "Cannot open $outfile for writing : $!\n";
    print OUT "$bundle\n$coe_bundles{$bundle}\n";
    close(OUT);
  }
}
my $syscall = "/opt/LinuxCOE/bin/install_bundles verbose";
if ( $dont_do_it ) {
  print STDERR "I would have executed:\n\n$syscall\n\n";
} else {
  system $syscall;
}

print STDERR "Done!  Thanks for choosing LinuxCOE!\n";

#
# End of main() - the rest is gravy...
#

sub load_bundle {

# Cycle through rpms associated with this bundle, load as needed.

  my ($bundle,$files,$waystation) = @_;
  print LOG "Installing $bundle bundle from $waystation\n";
  print STDERR "Please wait, installing $bundle bundle from $waystation - ";
  my @needem;
  my @rpms = split(' ',$files);

# Foreach rpm, see if it's needed
  foreach $rpm (@rpms) {
    if ( &need_it($rpm) ) { 
      print LOG " will install\n";
      push(@needem,$rpm); 
    } else {
      print LOG " already got it\n";
    }
  }

# Do we need any?  If so, attempt to install them
  if (@needem) {
    my $line = join(" ",@needem);
    $line = " $line";
    &load_rpms($bundle,$line); 
  } else {
    print LOG "$bundle is installed or superseded...\n";
    print STDERR "already got it, continuing...\n";
  }

}

sub need_it {

# is the rpm passed needed?

  my $rpm = shift;
  # Rip off all the leading path cruft;
  my @data = split('\/',$rpm);
  $rpm = pop(@data);        # grab the rpm name sans path
  (@data) = split('\.',$rpm);
  pop(@data); pop(@data);   # Get rid of .arch.rpm
  my ($name,$ver) = &parse_rpm(join('.',@data));
  print LOG "$name, comparing new $ver to installed $installed{$name}";
  if ( $ver gt $installed{$name} ) { return(1) }  # we need it!
  return;  # they got it!

}

sub parse_rpm {

#  autorpm does this better, but I can't force Patch_Mgmt  

  my $data = shift(@_);
  my @arr = split('-',$data);
  my ($test,@p);
  while ( $test = shift(@arr) ) {
    last if ( $test =~ /^[0-9]/ );
    push(@p,$test);
  }
  return(join('-',@p),join('-',$test,@arr));

}

sub load_installed {

# Create the %array of installed rpms.

 my %installed;
  open(IN,"/bin/rpm -qa |") ||
    die "Cannot fork rpm : $!\n";
  while(<IN>) {
    chomp;
    my ($product,$rev) = &parse_rpm($_);
    $installed{$product} = $rev;
    print LOG "Found installed product $product - $rev\n";
  }
  return(%installed);

}

sub make_snippet {

# Create a /etc/rc.d/init.d snippet to try again next reboot

  ($bundle,$rpms) = @_;
  open(RC,">/etc/rc.d/init.d/LinuxCOE-$bundle");
  print RC qq{#!/bin/sh
/bin/rpm --force -Uvh $rpms
if [ \$? -eq 0 ]
then
  /bin/rm /etc/rc.d/*/*LinuxCOE-$bundle
fi
};
system "/bin/chmod +x /etc/rc.d/init.d/LinuxCOE-$bundle";
system "/bin/ln -s /etc/rc.d/init.d/LinuxCOE-$bundle /etc/rc.d/rc2.d/S99LinuxCOE-$bundle";
system "/bin/ln -s /etc/rc.d/init.d/LinuxCOE-$bundle /etc/rc.d/rc3.d/S99LinuxCOE-$bundle";
system "/bin/ln -s /etc/rc.d/init.d/LinuxCOE-$bundle /etc/rc.d/rc4.d/S99LinuxCOE-$bundle";
system "/bin/ln -s /etc/rc.d/init.d/LinuxCOE-$bundle /etc/rc.d/rc5.d/S99LinuxCOE-$bundle";

}

sub load_rpms {

# Attempt to install the rpms passed via HTTP

  my ($bundle,$line) = @_;
  my $syscall = "/bin/rpm --force -Uvh $line >>${log}.rpm 2>&1";
  print LOG "Installing $bundle with:\n ";
  print LOG "$syscall\n";
  if ( $dont_do_it ) {
    print STDERR "I would have executed:\n\n$syscall\n\n";
    return;
  } else {
    system $syscall;
  }
  if ( $? != 0 ) {
    print LOG " $bundle failed, making rc.d snippet, will retry on next boot.\n";
    &make_snippet("$bundle","$line");
    print STDERR " failed. :(  Will retry on next boot.\n  See $log for details.\n";
  } else {
    print STDERR " succeeded!\n" unless ($dont_do_it);
  }

}

sub Remove_Old {

  if ( $dont_do_it ) {
     print "Would have removed OLD LinuxCOE-specific RPMS\n";
     return;
  }

  # Get rid of old stuff, it's not upgradeable

  my @rpms = qw(linuxcoe linuxcoe-apt-sources linuxcoe-configure-apt linuxcoe-configure_apt linuxcoe_configure-apt linuxcoe_configure_apt);
  print LOG "Removing OLD linuxcoe RPMS from RPM database:\n";
  foreach my $rpm (@rpms) {
    print LOG " $rpm";
    system "/bin/rpm -e  --justdb --nodeps $rpm >>$log 2>&1";
  }
  print LOG "\n";

  # Get rid of old configuration breadcrumbs (just in case)

  my @dirs = qw(/etc/opt/LinuxCOE/apt.sources /etc/opt/LinuxCOE/yum.sources);
  foreach my $dir (@dirs) {
    next unless ( -d $dir );
    open(DIR,"$dir") || die "Cannot open $dir : $!\n";
    my @files = sort(readdir(DIR));
    closedir(DIR);
    shift(@files); shift(@files);  # Toss . and ..
    foreach my $file (@files) {
      unlink "$dir/$file";
    }
  }

}
