#!/usr/bin/perl -w
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2005,2006 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
#-------------------------------------------------------------------------------
# Items that may be overridden:
#   - GPFS source location -- Does not require any knowledge of the system
#                             configurable parameters.
#   - OS Kernel headers    -- Does not necessarily preclude the automatically
#     determined system configuration (but the implications of specifying them
#     indicates a mismatch with automatically determinable items).
#-------------------------------------------------------------------------------

#-------------------------------------------------------------------------------
# function: usage
#
# This function displays the usage for the auto-configuration program.
#-------------------------------------------------------------------------------
sub usage()
{
  # Obtain invoked program name
  $program = `basename $0`;
  chomp($program);

  # Display full syntax description
  print "\nUsage: ${program} [--help] [sharkcloneroot=<dir>]\n";
  print "\nOptions:\n";
  print "\n    --help";
  print "\n           Display ${program} help and exit.\n";
  print "\n    sharkcloneroot=<dir>";
  print "\n           Specify the location of the source tree to configure.";
  print "\n           If not specified, check the SHARKCLONEROOT environment";
  print "\n           variable. If neither is specifiec, default to the GPL";
  print "\n           source directory /usr/lpp/mmfs/src.\n";
}

#-------------------------------------------------------------------------------
# function: get_OS
#
# This function determines the target Operating System.
#-------------------------------------------------------------------------------
sub get_OS()
{
  local ($os);
  local ($gpfs_os);

  $os = `uname`;
  if ($os =~ "AIX")
  {
    $gpfs_os = "GPFS_AIX";
  }
  elsif ($os =~ "Linux")
  {
    $gpfs_os = "GPFS_LINUX";
  }
  else
  {
    $gpfs_os = "UNSUPPORTED";
  }

  return($gpfs_os);
}

#-------------------------------------------------------------------------------
# function: get_Architecture
#
# This function determines the target hardware architecture.
#-------------------------------------------------------------------------------
sub get_Architecture()
{
  local ($arch);
  local ($gpfs_arch);

  $arch = `uname -m`;
  if ($arch =~ /^ia64$/)
  {
    $gpfs_arch = "GPFS_ARCH_IA64";
  }
  elsif ($arch =~ /^i\d86$/)
  {
    $gpfs_arch = "GPFS_ARCH_I386";
  }
  elsif ($arch =~ /^ppc$/)
  {
    $gpfs_arch = "GPFS_ARCH_POWER";
  }
  elsif ($arch =~ /^ppc64$/)
  {
    $gpfs_arch = "GPFS_ARCH_PPC64";
  }
  elsif ($arch =~ /^x86_64$/)
  {
    $gpfs_arch = "GPFS_ARCH_X86_64";
  }
  else
  {
    $gpfs_arch = "UNSUPPORTED";
  }

  return($gpfs_arch);
}

#-------------------------------------------------------------------------------
# function: get_DistValues
#
# This function determines the target Linux distribution values.
#-------------------------------------------------------------------------------
sub get_DistValues()
{
  local ($redhat_release, $suse_release);
  local ($dist, $dist_level, $kernel_string);
  local($version, $release, $modification, $fix);
  local($modification_actual, $fix_actual);

  local($kernel, $kernel_actual);

  $suse_release = "/etc/SuSE-release";
  $redhat_release = "/etc/redhat-release";

  # Obtain the running kernel version string
  $kernel_string = `uname -r`;
  chomp($kernel_string);
  if ($kernel_string =~ /([2])\.([46]).(\d+)(.*)$/)
  {
    # Obtain the version, release, modification and fix level. Also obtain
    # the "actual" modification and fix values (full, unmodified numeric only
    # values) required for SLES 9 kernel headers.
    $version = $1;
    $release = $2;
    $modification_actual = $modification = $3;
    $fix = $4;

    if ($modification > 99)
    {
      # Reduce modification to two digits to fit format string.
      $modification = 99;
    }
    if ($fix =~ /^.(\d+)([.-])(\d+)([.-])(\d+)/)
    {
      # Fix level utilizes a multi-numeric format "." or "-" separated.
      $fix = $1;
      $fix_actual = $1 . $2 . $3 . $4 . $5;
    }
    elsif ($fix =~ /^([.-])(\d+)([.-])(\d+)/)
    {
      # Fix level utilizes a multi-numeric format "." or "-" separated.
      $fix = $2;
      $fix_actual = $1 . $2 . $3 . $4;
    }
    elsif ($fix =~ /^-(\d+)/)
    {
      # Fix level utilizes a single-numeric format.
      $fix_actual = $fix = $1;
    }
    else
    {
      # No fix level in format; assign one to fit format string.
      $fix = "00";
    }
    if ($fix > 99)
    {
      # Reduce fix to two digits to fit format string.
      $fix = 99;
    }
    $kernel = sprintf("%01d%02d%02d%02d", $version, $release, $modification,
                         $fix);
    $kernel_actual = sprintf("%d.%d.%d-%s", $version, $release,
                                $modification_actual, $fix_actual);
  }
  else
  {
    die("Cannot parse kernel version $kernel_string\n");
  } 

  # DES: Fix this...if we do NOT do alternate configurations
  # If the requested build is for the local machine, then we can determine the
  # following information from local files. Otherwise, the user will have to
  # provide that information.
  if (-f $suse_release)
  {
    # SuSE Release
    $dist = "SUSE_LINUX";
    $dist_level = "80";
    open(RELFILE, $suse_release) || die "Cannot open $suse_release";
    LINE: while ($line = <RELFILE>)
    {
      if ($line =~ /VERSION = (\d+)/ )
      {
        $dist_version = $1;
      }
    }
    close(RELFILE);

    # Determine the kernel headers directory
    $lib_mod_bld_dir = "/lib/modules/$kernel_string/build/include";
    $lib_mod_src_dir = "/lib/modules/$kernel_string/source/include";
    $usr_src_dir = "/usr/src/linux-$kernel_actual/include";
    if ($dist_version eq "8" && (-f "$lib_mod_bld_dir/linux/version.h"))
    {
      $kernel_hdr_dir = $lib_mod_bld_dir;
      # Build directory not required for the 2.4 kernel
      $kernel_bld_dir = "";
    }
    elsif ($dist_version eq "9" && (-f "$lib_mod_src_dir/linux/version.h"))
    {
      $kernel_hdr_dir = $lib_mod_src_dir;
      # Build directory for the linux 2.6 kernel
      $kernel_bld_dir = "/lib/modules/$kernel_string/build";
    }
    elsif ($dist_version eq "9" && (-f "$usr_src_dir/linux/version.h"))
    {
      $kernel_hdr_dir = $usr_src_dir;
      # cannot guess the value in this case - let the user specify this
      $kernel_bld_dir = "";
    }
    elsif ($dist_version eq "10" && (-f "$lib_mod_src_dir/linux/version.h"))
    {
      $kernel_hdr_dir = $lib_mod_src_dir;
      # cannot guess the value in this case - let the user specify this
      $kernel_bld_dir = "/lib/modules/$kernel_string/build";
    }
    elsif ($dist_version eq "10" && (-f "$usr_src_dir/linux/version.h"))
    {
      $kernel_hdr_dir = $usr_src_dir;
      # cannot guess the value in this case - let the user specify this
      $kernel_bld_dir = "";
    }
    else
    {
      die ("Cannot find a valid kernel include dir\n");
    }

    # ensure that the source directory has the right autoconf.h and version.h
    # copied to it.  Due to some distro bugs this may not always be the case.
    if ($kernel_hdr_dir ne "" && $kernel_bld_dir ne "")
    {
      if (system("/usr/bin/diff -q $kernel_hdr_dir/linux/version.h $kernel_bld_dir/include/linux/version.h") != 0)
      {
         die("Kernel source tree does not have the correct version.h file.\n",
             "See /usr/lpp/mmfs/src/README for further information\n");
      }

      if (system("/usr/bin/diff -q $kernel_hdr_dir/linux/autoconf.h $kernel_bld_dir/include/linux/autoconf.h") != 0)
      {
         die("Kernel source tree does not have the correct autoconf.h file.\n",
             "See /usr/lpp/mmfs/src/README for further information\n");
      }
    }

  }
  elsif (-f $redhat_release)
  {
    # RedHat Release
    open(RELFILE, $redhat_release) || die "Cannot open $redhat_release";
    LINE: while ($line = <RELFILE>)
    {
      if ($line =~ /Red Hat Linux release (\S+)/ )
      {
        $dist = "REDHAT_LINUX";
        $dist_level = $1 eq "9" ? "90" : "80";
      }
      elsif ($line =~ /Red Hat Enterprise Linux/ )
      {
        $dist = "REDHAT_AS_LINUX";
        $dist_level = "80";
      }
    }
    close(RELFILE);

    # Determine the kernel headers directory
    $lib_mod_dir = "/lib/modules/$kernel_string/build/include";
    $usr_src_dir = "/usr/src/linux-$kernel_string/include";
    if (-f "$lib_mod_dir/linux/version.h")
    {
      $kernel_hdr_dir = $lib_mod_dir;
      $kernel_bld_dir = "/lib/modules/$kernel_string/build";
    }
    elsif (-f "$usr_src_dir/linux/version.h")
    {
      $kernel_hdr_dir = $usr_src_dir;
      $kernel_bld_dir = "/usr/src/linux-$kernel_string";
    }
    else
    {
      die ("Cannot find a valid kernel include dir\n");
    }
  }
  else
  {
    $dist = "UNSUPPORTED";
    $dist_level = "UNSUPPORTED";
    $kernel = "UNSUPPORTED";
    $kernel_hdr_dir = "UNSUPPORTED";
    $kernel_bld_dir = "UNSUPPORTED";
  }

  return($dist, $dist_level, $kernel, $kernel_hdr_dir, $kernel_bld_dir);
}

#-------------------------------------------------------------------------------
# function: write_config
#
# This function writes the build configuration file, combining the template and
# the supplied configuration values.
#-------------------------------------------------------------------------------
sub write_config()
{
  local ($os, $architecture, $dist, $dist_level, $kernel);
  local ($kernel_hdr_dir, $template_dir);

  $os = shift;
  $architecture = shift;
  $dist = shift;
  $dist_level = shift;
  $kernel = shift;
  $kernel_hdr_dir = shift;
  $kernel_bld_dir = shift;
  $template_dir = shift;

  # Open the template and build configuration files
  open(TEMPLATE, "$template_dir/site.mcr.proto") ||
    die "Unable to open template file $template_dir/site.mcr.proto\n";
  open(CONFIG, ">$template_dir/site.mcr") ||
    die "Unable to open configuration file $template_dir/site.mcr\n";

  #-----------------------------
  # Generate configuration file
  #-----------------------------
  foreach $line (<TEMPLATE>)
  {
    # Substitute variable fields in configuration file
    if ($line =~ m/^#define GPFS_LINUX$/)
    {
       $line =~ s/GPFS_LINUX$/$os/;
    }
    elsif ($line =~ m/^#define GPFS_ARCH_I386$/)
    {
       $line =~ s/GPFS_ARCH_I386$/$architecture/;
    }
    elsif (($line =~ m/^LINUX_DISTRIBUTION = REDHAT_LINUX$/) && ($os eq "GPFS_LINUX"))
    {
       $line =~ s/REDHAT_LINUX$/$dist/;
    }
    elsif (($line =~ m/^#define LINUX_DISTRIBUTION_LEVEL 90$/) && ($os eq "GPFS_LINUX"))
    {
       $line =~ s/90$/$dist_level/;
    }
    elsif (($line =~ m/^#define LINUX_KERNEL_VERSION 2042028$/) && ($os eq "GPFS_LINUX"))
    {
       $line =~ s/2042028$/$kernel/;
    }
    elsif (($line =~ m/^KERNEL_HEADER_DIR = \/lib\/modules\/`uname -r`\/build\/include$/) && ($os eq "GPFS_LINUX"))
    {
       $line =~ s/\/lib\/modules\/`uname -r`\/build\/include$/$kernel_hdr_dir/;
    }
    elsif (($line =~ m/^KERNEL_BUILD_DIR = \/lib\/modules\/`uname -r`\/build$/) && ($os eq "GPFS_LINUX"))
    {
       $line =~ s/\/lib\/modules\/`uname -r`\/build$/$kernel_bld_dir/;
    }
    print CONFIG "$line";
  }

  # Close the template and configuration files.
  close(TEMPLATE);
  close(CONFIG);
}

#-------------------------------------------------------------------------------
# function: configure
#
# This function obtains the full set of build configuration values, generating
# the configuration file from the template.
#-------------------------------------------------------------------------------
sub configure()
{
  local ($architecture, $dist, $dist_level, $kernel, $kernel_hdr_dir, $os);
  local ($sharkcloneroot, $template_dir);

  # Obtain input parameters
  $sharkcloneroot = shift;

  #------------------------
  # Verify source location
  #------------------------
  if ($sharkcloneroot =~ m/^[^\/]/)
  {
    # Source path not fully qualified
    print STDERR "Source path not fully qualified: $sharkcloneroot\n";
    return(-1);
  }

  #----------------------------------------------------------------
  # Verify build type (GPL or development) from template location.
  #----------------------------------------------------------------
  if (-e "$sharkcloneroot/config/site.mcr.proto")
  {
    $template_dir = "$sharkcloneroot/config";
  }
  elsif (-e "$sharkcloneroot/shark-config/site.mcr.proto")
  {
    $template_dir = "$sharkcloneroot/shark-config";
  }
  else
  {
    print STDERR "Missing or incomplete source at: $sharkcloneroot\n";
    return(-1);
  }

  #-------------------------
  # Determine the target OS
  #-------------------------
  $os = get_OS();
  if ($os eq "GPFS_LINUX")
  {
    #---------------------------------------
    # Determine Linux specific settings
    #---------------------------------------

    # Determine the Architecture
    $architecture = get_Architecture();
    if ($architecture eq "UNSUPPORTED")
    {
      print STDERR "Unsupported Architecture: $architecture\n";
      $rc = -1;
      return($rc);
    }

    # Determine the Distribution, Kernel, Kern Header Directory
    ($dist, $dist_level, $kernel, $kernel_hdr_dir, $kernel_bld_dir) = get_DistValues();
    if ($dist eq "UNSUPPORTED")
    {
      print STDERR "Unsupported Distribution: $dist\n";
      $rc = -1;
      return($rc);
    }
    if ($dist_level eq "UNSUPPORTED")
    {
      print STDERR "Unsupported Distribution Level: $dist_level\n";
      $rc = -1;
      return($rc);
    }
  }
  elsif ($os eq "GPFS_AIX")
  {
    #---------------------------------
    # Determine AIX specific settings
    #
    # NOTE: Only require architecture
    #---------------------------------

    $architecture = "GPFS_ARCH_POWER";
  }
  else
  {
    #------------------------------
    # Unsupported Operating System
    #------------------------------

    print STDERR "Unsupported Operating System: $os\n";
    $rc = -1;
    exit($rc);
  }

  # If we have gotten to this point without an error occurrence, then process
  # the site.mcr.proto and write a site.mcr file for the source code build.
  if ($rc eq 0)
  {
    &write_config($os, $architecture, $dist, $dist_level, $kernel,
                  $kernel_hdr_dir, $kernel_bld_dir, $template_dir);
  }

  return(0);
}

#-------------------------------------------------------------------------------
# Main program
#-------------------------------------------------------------------------------

# Initialize utility variables
$rc = 0;

# Initialize core variables
$sharkcloneroot = undef;

# Process command-line arguments
foreach $arg (sort @ARGV)
{
  if ($arg =~ m/^-/)
  {
    # Option specified
    if ($arg eq "--help")
    {
      # Help requested ==> Display usage, exit success
      usage();
      exit(0);
    }
    else
    {
      # Unknown option ==> Display usage, exit failure
      usage();
      exit(1);
    }
  }
  else
  {
    # Attribute/value pair specified
    ($attr, $value) = split("=", $arg);
    if ($attr eq "sharkcloneroot")
    {
      # Source override specified
      if (!$sharkcloneroot)
      {
        $sharkcloneroot = $value;
      }
      else
      {
###     prtMsg(36, "source");
        usage();
        exit(1);
      }
    }
    else
    {
      # Invalid override
      print STDERR "Invalid override: $attr\n";
      usage();
      exit(1);
    }
  }
}

#--------------------------------------
# Assign program defaults as necessary
#--------------------------------------

# Define the source directory. The default value may be overridden with the
# following priority utilized:
#     1) sharkcloneroot attribute setting supplied via command line
#     2) SHARKCLONEROOT environment variable
#     3) /usr/lpp/mmfs/bin default
if (!$sharkcloneroot)
{
  # sharkcloneroot attribute unspecified
  if (defined $ENV{SHARKCLONEROOT})
  {
    # SHARKCLONEROOT environment variable specified
    $sharkcloneroot = $ENV{SHARKCLONEROOT};
  }
  else
  {
    # SHARKCLONEROOT environment variable unspecified
    $sharkcloneroot = "/usr/lpp/mmfs/src";
  }
}

#----------------------------------------------------------
# Process the configuration; Return success/failure status
#----------------------------------------------------------
$rc = &configure($sharkcloneroot);
exit($rc);

#-------------------------------------------------------------------------------
