#!/usr/bin/perl
# -*- Mode: CPerl -*-
#
# install the new configuration files
# takes one argument - the PATCHDIR, typically under install/patch/<patchnum>

use Getopt::Long;               # for GetOptions
use File::Compare;              # for compare
use File::Basename;             # for dirname
use File::Path;                 # for mkpath
use File::Copy;                 # for move, copy

#
# usage
#
sub usage
{
print <<EOF;

Usage: $0 [--domain <domain>|ALL] [--force] <patchdir>

  --domain <domain>|ALL
    The hosted domain to operate on, or ALL for all hosted domains
    You can also use the short form of the switch -d instead of --domain

  --force
    Do not prompt for confirmation when overwriting live config files.
    You can also use the short form of the switch -f instead of --force
    
  <patchdir>: The patch directory area created during patchadd.
    e.g. $basedir/install/patch/118207-41

EOF
  die "  Exiting";
}

########################################
# check_files
#   check if file exists
#   check to see if it has any diff3 conflicts
# args
#   $filelist - file containing list of files
# returns
#   number of files with errors
########################################
sub check_files
{
  my ($filelist) = @_;
  my ($cfile,$file,$errs,$stat);
  $errs = 0;
  open (CONFIG, "$filelist") or die ("Cannot open $filelist for reading -");
  while (<CONFIG>) {
    chomp;
    # the "config" file, a path relative to $basedir
    $cfile = $_;
    # check if new file exists and has no conflicts
    # increments newfile_error if any error found
    $file = "$SAVEDIR/$cfile.new";
    if ( ! -f "$file" ) {
      log_msg("-- ERROR: $file does not exist\n");
      $errs = $errs + 1;
    } else {
      $Cmd = "/bin/grep -s '^=======\$' $file";
      $stat = logonly_cmd("$Cmd");
      if ( $stat == 0 ) {
        log_msg("-- ERROR: $file has diff3 conflicts in it\n");
        $errs = $errs + 1;
      }
    }
  }
  close (CONFIG);
  return($errs);
}

########################################
# install newconfig files
# - install the new config files
########################################
sub install_newconfig
{
  my ($cfile,$newfile_error,$domain,$NUMCOPIES, $errs);
  $newfile_error = 0;

  # default domain
  if (! defined $opt_d ) {
    $errs = check_files("$PATCHDIR/newconfig.list");
    $newfile_error = $newfile_error + $errs;
  }

  # hosted domains
  foreach $domain (@domains) {
    $errs = check_files("$PATCHDIR/${domain}_newconfig.list");
    $newfile_error = $newfile_error + $errs;
  }

  if ( $newfile_error != 0 ) {
    log_msg("--\n");
    log_msg("-- $newfile_error errors found, please correct and rerun the\n");
    log_msg("-- utility. No change was made to the system.\n");
    die " $newfile_error errors - ";
  }

  # install the files
  $NUMCOPIES = 0;
  # default domain
  if ( ! defined $opt_d ) {
    log_msg("-- Checking default domain\n");
    $copies = install_filelist("$PATCHDIR/newconfig.list");
    $NUMCOPIES = $NUMCOPIES + $copies;
  }

  # hosted domains
  foreach $domain (@domains) {
    log_msg("-- Checking hosted domain $domain\n");
    $copies = install_filelist("$PATCHDIR/${domain}_newconfig.list");
    $NUMCOPIES = $NUMCOPIES + $copies;
  }
  log_msg("-- Number of different files: $NUMCOPIES\n");
  log_msg("-- Original files are backed up under $CONFIGBACKOUTDIR\n");
}

########################################
# install_filelist
# - given a file containing the file list, install the files
# args
#   $filelist - file containing file list
# uses global variables
#   $SAVEDIR $basedir $CONFIGBACKOUTDIR $opt_f
# returns - number of copies
#
########################################
sub install_filelist
{
  my($filelist) = @_;
  my($lineno, $cfile, $stat, $dir,$ans,$copies);
  $copies = 0;
  open (CONFIG, "$filelist") or die ("Cannot open $filelist for reading -");
  $lineno = 0;
  while (<CONFIG>) {
    $lineno = $lineno + 1;
    chomp;
    # the "config" file, a path relative to $basedir
    $cfile = $_;
    # check if it is identical first
    $stat = compare("$SAVEDIR/$cfile.new", "$basedir/$cfile");
    # cmp status is 0 if files are identical
    if ( $stat != 0 ) {
    # save existing config file
      if ( -f "$basedir/$cfile" ) {
        $dir = dirname("$CONFIGBACKOUTDIR/$cfile");
        if ( ! -d "$dir" ) {
          log_only("mkpath $dir 0 0755\n");
          mkpath("$dir",0,0755);
        }
        log_only("copy $basedir/$cfile $CONFIGBACKOUTDIR/$cfile\n");
        copy("$basedir/$cfile", "$CONFIGBACKOUTDIR/$cfile");
      }

      # install new config file
      #   no permissions being enforced by mkdir. Nuts.
      $dir = dirname( "$basedir/$cfile");
      if ( ! -d "$dir" ) {
        log_only("mkpath $dir 0 0755\n");
        mkpath("$dir",0,0755);
      }
      if ( defined $opt_f ) {
        $ans = "y";
      } else {
        $ans = YesOrNo("Overwrite $basedir/$cfile ?", "no");
      }
      if ($ans eq "y" ) {
        log_msg("copy $SAVEDIR/$cfile.new $basedir/$cfile\n");
        copy( "$SAVEDIR/$cfile.new", "$basedir/$cfile" );
        $copies = $copies + 1;
      }
    } else {
      log_msg("-- $SAVEDIR/$cfile.new and $basedir/$cfile are identical, skipping it\n");
    }

  }
  close (CONFIG);
  return($copies);
}

########################################
# determine the full path to this script's location
# set the variable scriptDir
#
# make $currDir and $scriptDir globally available
########################################
sub get_my_dir {
  $currDir=`pwd`;
  chomp $currDir;
  $scriptDir = dirname("$0");
  chdir $scriptDir;
  $scriptDir =`pwd`;
  chomp $scriptDir;
  chdir $currDir;
}

########################################
# main program
########################################
$ENV{"PATH"} = "/bin:/usr/bin:/usr/sbin:/sbin:/usr/etc:" . $ENV{"PATH"};

get_my_dir();
# assume that this script is located in $basedir/sbin/
# so set basedir accordingly
$basedir = dirname ("$scriptDir");

# Start environment variable settings
#
# LD_LIBRARY_PATH used for Solaris 2.5+, SCO Unix, IRIX, Linux
$ENV{"LD_LIBRARY_PATH"} = "${basedir}/lib:" . $ENV{"LD_LIBRARY_PATH"};

# prepend to search path
unshift (@INC, "$basedir/lib");
require "util.pl";

# get args
# whether to install the new config files or not
if (! GetOptions("help" => \$help,
                 "force" => \$opt_f,
                 "domain=s" => \$opt_d) ) {
  print "ERROR parsing options: \n";
  usage;
}

if ( $help ) {
  print "Here is your Help: \n";
  usage;
}

if ( @ARGV != 1 ) {
  print "ERROR: Missing patch directory argument\n";
  usage;
}
$PATCHDIR = "$ARGV[0]";

#
# must be root
#
if ($< != 0) {
  print "Utility to install the new config files generated by patch-config\n";
  print "To use this utility you need to be the system's root user. \n\n";
  exit(1);
}

# process -d switch
# @domains will be the list of hosted domains to operate on
@domains = get_hosted_domains();
if ( ! defined $opt_d ) {
  # default is to operate on all hosted domains, already set to do so
} elsif ( $opt_d eq "ALL") {
  # do nothing, already set to all domains
} else {
  # set to a specific domain
  # make sure it is a valid domain
  $exists = grep /^$opt_d$/, @domains;
  if ( $exists != 0 ) {
    @domains = ($opt_d);
  } else {
    print "ERROR: Invalid domain $opt_d\n";
    print "The list of valid domains are: @domains\n";
    die "  ";
  }
}

# initialize logging
$LOGFILE = getLogfile($PATCHDIR, '/', "install-newconfig");
log_init($LOGFILE);
log_only("basedir = $basedir\n");

# save directory created by patchadd and patch-config
if ( ! -d "$PATCHDIR/save" ) {
  log_msg("Invalid PATCHDIR, $PATCHDIR/save is not a directory\n");
  usage;
}
$SAVEDIR = "$PATCHDIR/save";

# file containing list of new config files
if ( defined $opt_d ) {
  foreach $domain (@domains) {
    if ( ! -f "$PATCHDIR/${domain}_newconfig.list" ) {
      log_msg("$PATCHDIR/${domain}_newconfig.list not found, Please run patch-config first\n");
      usage;
    }
  }
} else {
  if ( ! -f "$PATCHDIR/newconfig.list" ) {
    log_msg("$PATCHDIR/newconfig.list not found, Please run patch-config first\n");
    usage;
  }
}

# where original config files will be backed up
$datestr = genTimestamp();
$CONFIGBACKOUTDIR = "${PATCHDIR}/config_${datestr}";
mkpath("$CONFIGBACKOUTDIR", 0, 0755);

# check to make sure config is accessible
check_configaccess();
isHAconfigured();

if ( $isHAconfigured == 1 ) {
  log_msg("Warning an HA configuration is detected on your systems,\n");
  ContinueYesNo();
}

stop_servers();
install_newconfig();
perform_checks();
log_msg("-- The final step is to apply the ldif file\n");
log_msg("-- $basedir/lib/patch/ugdir_diff.ldif\n");
log_msg("-- to the user/group Directory\n");
log_msg("-- This is not performed automatically, you must do this manually\n");
