# $Header: emdb/sysman/webapps/em/WEB-INF/perl/clone_util_10_2.pl /st_emdbsa_11.2/5 2010/03/10 21:08:00 rimmidi Exp $
#
# clone_util_10_2.pl
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 
#
#    NAME
#      clone_util_10_2.pl - <one-line expansion of the name>
#
#    DESCRIPTION
#      <short description of component this file declares/defines>
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#    rimmidi     03/08/10 - Bug fix 9457350
#    rimmidi     12/09/09 - Bug fix 9147330
#    rimmidi     03/13/09 - Bug fix 8323159
#    ngade       02/02/09 - Code slap 10.2.0.5.0 -> 11.2 round 2
#    ngade       10/24/08 - Bug 7320939
#    rimmidi     21/11/08 - Bug fix 7459233
#    rimmidi     10/14/08 - Bug fix 7454546
#    rimmidi     10/07/08 - Fix Bug 7452324
#    sjconnol    09/12/08 - Rename logfiles for standby duplicate
#    rimmidi     08/20/08 - Include NOFILENAMECHECK for diffHost cloning
#    rimmidi     05/05/08 - Code slap from 11GC to 10.2.0.5
#    rimmidi     07/30/08 - Code slap from 10205 to 11.2DBControl
#    mreddych    02/13/08 - Backport mreddych_bug-6728722 from
#                           st_emgc_10.2.0.1.0
#    mreddych    12/06/07 - Backport of RFI bug#6660878 - bug#6214854
#    sxzhu       06/06/07 - Add getSharedMemorySize
#    sxzhu       06/05/07 - Fix bug 6025505
#    sxzhu       04/18/07 - Get file content before removing
#    sxzhu       03/30/07 - Get server version with RMAN
#    sxzhu       03/08/07 - Fix RMAN duplicate for diff host when FRA set
#    sxzhu       02/13/07 - Escape backslashes
#    sxzhu       02/01/07 - Check Oracle Home version
#    sxzhu       10/26/06 - Create temp service on Windows for RMAN backup
#    sxzhu       08/30/06 - Set linesize
#    sxzhu       08/25/06 - Workaround bug 5440354
#    sxzhu       06/16/06 - Support RMAN duplicate 
#    sxzhu       06/08/06 - Use RMAN backup 
#    sxzhu       06/23/05 - Support ftp on Windows
#    sxzhu       04/19/05 - Test local connection
#    sxzhu       03/25/05 - Check ESTABLISHED port for emca
#    sxzhu       01/27/05 - Skip raw device checking on NT
#    sxzhu       01/07/05 - Add checkRawDevices
#    sxzhu       11/15/04 - Add getFreePortAfterStartingPort
#    sxzhu       08/12/04 - Use warnings
#    sxzhu       07/30/04 - sxzhu_clone_0721
#    sxzhu       07/16/04 - Creation
#

require "$ENV{EMDROOT}/sysman/admin/scripts/db/dbclone/clone_util.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/db/dbclone/db_clone.pl";

use strict;
use warnings;
use File::stat;
use vars qw/$hostUserID $userID $OS $NT $S $TEMP $CP $MV $PS $DF $DELIMITER $Registry/;

#$ENV{EMAGENT_PERL_TRACE_LEVEL} = 0;  #DEBUG level.

# Get max stamp number
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# getMaxStamp()
sub getMaxStamp
{
  EMD_PERL_DEBUG("clone_util_10_2.getMaxStamp(): *** START ***");

  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "CONNECT $userID AS SYSDBA;\n";
  $sql_string .= "set serveroutput on;\n";
  $sql_string .= "set linesize 512;\n";
  $sql_string .= "variable max_stamp number;\n";
  $sql_string .= "BEGIN\n";
  $sql_string .= "  select MAX(checkpoint_change#) INTO :max_stamp from v\$datafile_copy;\n";
  $sql_string .= "  IF(:max_stamp IS NULL) then\n";
  $sql_string .= "    :max_stamp := 0;\n";
  $sql_string .= "  end if;\n";
  $sql_string .= "  dbms_output.put_line('Start printing max_stamp number: ');\n";
  $sql_string .= "  dbms_output.put_line('max_stamp# '||:max_stamp);\n";
  $sql_string .= "END;\n";
  $sql_string .= "/\n";
  $sql_string .= "EXIT;\n";

  my $hideOutput = "";
  (my $fh, my $filename) = &runSqlOnSource($sql_string, $hideOutput);

  open (MAX_STAMP_NUM, "$filename") || die "Unable to open tempfile for MAX_STAMP_NUM\n";
  while (<MAX_STAMP_NUM>)
  {
    if (($_=~/\d/) && ($_=~/\bmax_stamp#/))
    {
      chomp($_);
      print "$_\n";
      EMD_PERL_DEBUG("clone_util_10_2.getMaxStamp(): Max stamp number: $_");
    }
  }

  close MAX_STAMP_NUM;
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util_10_2.getMaxStamp(): *** END ***");
}

# Get file sizes (KBytes) for given file names
# getFilesSize(fileNameArray)
sub getFilesSize
{
  my ($fileNameArray) = @_;

  my @fileNames = split /$DELIMITER/, $fileNameArray;
  my $size = 0;
  my $kbytes = "";
  my $fileNames;

  foreach $fileNames (@fileNames)
  {
    $size = &getFileSize($fileNames);
    #add 1, this method truncate the decimal digits, the spec says it rounds up.
    $kbytes .= sprintf("%.0f", $size/1024 + 1 );
    $kbytes .= "###";
  }

  return $kbytes;
}

# This method is platform specific, will be dealt with later.
# Get free port for a host
# This method has to be used going forward instead of getFreePort() from clone_util.pl (Agent side perl)
# getFreePort_o()
sub getFreePort_o
{
  (my $netstat, my $key, my $column, my $separator) = &paramForGetFreePort_o();
  EMD_PERL_DEBUG("clone_util_10_2.getFreePort_o(): netstat: $netstat, column: $column, key: $key");

  my $freePort = 1521; #the starting port to be checked
  my $usedPortCol = "";
  my $usedPort = "";
  my $row;
  my @tokens;
  my $separatorIndex = 0;
  my $found = 1;

  my @temp = `$netstat`;

  if(@temp > 1)
  {
    EMD_PERL_DEBUG("clone_util_10_2.getFreePort_o(): examining listening port");
    while($found == 1)
    {
      $found = 0;
      foreach $row (@temp)
      {
        chop($row);
        if ($row =~ /$key/)  #only ckeck rows containing key
        {
          $_ = $row;
          @tokens = split;
          $usedPortCol = $tokens[$column];
          $separatorIndex = rindex($usedPortCol, $separator);
          $usedPort = substr($usedPortCol, $separatorIndex + 1);
          if($freePort eq $usedPort)
          {
            EMD_PERL_DEBUG("clone_util_10_2.getFreePort_o(): Port is being used: $freePort");
            $freePort = $freePort + 1;
            $found = 1;
            last;
          }
        }
      }
    }
        }

  EMD_PERL_DEBUG("clone_util_10_2.getFreePort_o(): Free port: $freePort");

  return $freePort;
}

# Find if a given port is free
# isPortFree(port)
sub isPortFree
{
  my ($port) = @_;
  (my $netstat, my $key, my $column, my $separator) = &paramForGetFreePort_o();
  EMD_PERL_DEBUG("clone_util_10_2.isPortFree(): netstat: $netstat, column: $column, key: $key");

  my $freePort = $port; #the starting port to be checked
  my $usedPortCol = "";
  my $usedPort = "";
  my $row;
  my @tokens;
  my $separatorIndex = 0;

  my @temp = `$netstat`;

  if(@temp > 1)
  {
    EMD_PERL_DEBUG("clone_util_10_2.isPortFree(): examining listening port");
        foreach $row (@temp)
      {
        chop($row);
        if ($row =~ /$key/)  #only ckeck rows containing key
        {
          $_ = $row;
          @tokens = split;
          $usedPortCol = $tokens[$column];
          $separatorIndex = rindex($usedPortCol, $separator);
          $usedPort = substr($usedPortCol, $separatorIndex + 1);
          if($freePort eq $usedPort)
          {
            EMD_PERL_DEBUG("clone_util_10_2.isPortFree(): Port is being used: $freePort");
            return "false";
          }
        }
      }
  }

  EMD_PERL_DEBUG("clone_util_10_2.isPortFree(): Free port: $freePort");

  return "true";
}
# This method is platform specific, will be dealt with later.
# Get free port for a host
# getFreePortAfterStartingPort(startingPort)
sub getFreePortAfterStartingPort
{
  my ($startingPort) = @_;

  (my $netstat, my $key, my $column, my $separator) = &paramForGetFreePort_o();
  EMD_PERL_DEBUG("clone_util_10_2.getFreePortAfterStartingPort(): netstat: $netstat, column: $column, key: $key");

  my $freePort = $startingPort; #the starting port to be checked
  my $usedPortCol = "";
  my $usedPort = "";
  my $row;
  my @tokens;
  my $separatorIndex = 0;
  my $found = 1;

  #EMCA fails if the specified port is ESTABLISHED
  my $key_1 = "ESTABLISHED";

  my @temp = `$netstat`;

  if(@temp > 1)
  {
    EMD_PERL_DEBUG("clone_util_10_2.getFreePortAfterStartingPort(): examining listening port");
    while($found == 1)
    {
      $found = 0;
      foreach $row (@temp)
      {
        chop($row);
        if (($row =~ /$key/) or ($row =~ /$key_1/)) #only ckeck rows containing key
        {
          $_ = $row;
          @tokens = split;
          $usedPortCol = $tokens[$column];
          $separatorIndex = rindex($usedPortCol, $separator);
          $usedPort = substr($usedPortCol, $separatorIndex + 1);
          if($freePort eq $usedPort)
          {
            EMD_PERL_DEBUG("clone_util_10_2.getFreePortAfterStartingPort(): Port is being used: $freePort");
            $freePort = $freePort + 1;
            $found = 1;
            last;
          }
        }
      }
    }
  }

  EMD_PERL_DEBUG("clone_util_10_2.getFreePortAfterStartingPort(): Free port: $freePort");

  return $freePort;
}

# --------- OS platform-specific (for "getFreePort" only) -------------

# Run command $netstat, the listening ports information shows at each row
# of $column.
# paramForGetFreePort_o()
sub paramForGetFreePort_o
{
  my $netstat = ""; 
  my $key = "";
  my $column = "";
  my $separator = "";
  my $cmd = "";
  my $args = "-an";
  
  if($^O =~ /solaris/i)
  {
    EMD_PERL_DEBUG("clone_util.paramForGetFreePort_o(): OS platform: Solaris");
    $cmd = '/bin/netstat';
    $key = "LISTEN";
    $column = 0;
    $separator = ".";
  }
  elsif($^O =~ /MSWin32/i)
  {
    EMD_PERL_DEBUG("clone_util.paramForGetFreePort_o(): OS platform: MSWin32");
    # Bug: 9457350: For windows, give it the complete path for the netstat.
    my $drive = 'c:';
    if(exists($ENV{SYSTEMDRIVE}))
    {
      $drive = $ENV{SYSTEMDRIVE};
    }

    $cmd = $drive."\\WINDOWS\\system32\\netstat.exe";
    $key = "LISTENING";
    $column = 1;
    $separator = ":";
  }
  elsif($^O =~ /linux/i)
  {
    EMD_PERL_DEBUG("clone_util.paramForGetFreePort_o(): OS platform: Linux");
    $cmd = '/bin/netstat';
    $key = "LISTEN";
    $column = 3;
    $separator = ":";
  }
  #Add other platforms here
  elsif($^O =~ /dec_osf/i)
  {
    EMD_PERL_DEBUG("clone_util.paramForGetFreePort_o(): OS platform: HP OSF");
    $cmd = '/usr/sbin/netstat';
    $key = "LISTEN";
    $column = 3;
    $separator = ".";
  }
  else #may be Unix
  {
    EMD_PERL_DEBUG("clone_util.paramForGetFreePort_o(): OS platform: Unknown");
    $cmd = '/bin/netstat';
    $key = "LISTEN";
    $column = 3;
    $separator = ".";
  }

  ## only put together final netstat command if it's actually accessible
  if(-x "$cmd"){
    $netstat = "$cmd $args ";
  }

  return ($netstat, $key, $column, $separator);
}

# Check if multiple files are raw devices
# Return an array containing OK and NOK.
# Flag OK is returned if the file is raw device, otherwise, NOK is returned.
# checkRawDevices(fileNameArray)
sub checkRawDevices
{
  my ($fileNameArray) = @_;

  my @fileNames = split /$DELIMITER/, $fileNameArray;
  my $existStatus = "";
  my $fileName;
  my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev);

  foreach $fileName (@fileNames)
  {
    if($NT)
    {
      EMD_PERL_DEBUG("clone_util_10_2.checkRawDevices(): NT platform.");
      $existStatus .= "OK:";
    }
    else
    {
      ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev) = stat($fileName);
      if(!defined $rdev)
      {
        EMD_PERL_DEBUG("clone_util_10_2.checkRawDevices(): $fileName is not a valid name");
        $existStatus .= "NOK:";
      }
      elsif($rdev > 0)
      {
        EMD_PERL_DEBUG("clone_util_10_2.checkRawDevices(): $fileName is raw device (not a regular file) rdev: $rdev");
        $existStatus .= "OK:";
      }
      else
      {
        EMD_PERL_DEBUG("clone_util_10_2.checkRawDevices(): $fileName is a regular file");
        $existStatus .= "NOK:";
      }
    }
  }
  return $existStatus;
}

# This version adds new parameter "skipOutputCheck" to skip output check
# Run given sql script on source DB
# The caller is responsible to close the returned fileHandle
# runSqlOnSource_10_2(sqlScript, hideOutput, skipOutputCheck) will hide standard output for any
# defined parameter "hideOutput", and will skip output check for defined skipOutputCheck.
sub runSqlOnSource_10_2
{
  EMD_PERL_DEBUG("clone_util.runSqlOnSource_10_2(): *** START ***");

  my ($sql_string) = $_[0];
  my $sql_string_debug = &filterDBCredential($sql_string);
  EMD_PERL_DEBUG("clone_util.runSqlOnSource_10_2(): SQL:\n$sql_string_debug");

  (my $fh, my $filename) = &create_temp_file();

  if($NT)
  {
    $filename = "$TEMP\\"."dbclone.$$";
    EMD_PERL_DEBUG("clone_util.runSqlOnSource_10_2(): temp file: $filename");
    open(SQL_SCRIPT, "|$ENV{ORACLE_HOME}/bin/sqlplus /nolog >$filename")
      || die "Cannot open pipe for SQL_SCRIPT";
    print SQL_SCRIPT $sql_string;
    close SQL_SCRIPT || die "Bad SQL_SCRIPT";
  }
  else
  {
    open(SQL_SCRIPT, "|$ENV{ORACLE_HOME}/bin/sqlplus /nolog >$filename")
      || die "Cannot open pipe for SQL_SCRIPT";
    print SQL_SCRIPT $sql_string;
    close SQL_SCRIPT || die "Bad SQL_SCRIPT";
  }

  #Open the temp file to print output to standard output and debug trace file
  open (OUT_PUT, "$filename") || die "Unable to open tempfile for OUT_PUT\n";
  my @output_content = <OUT_PUT>;
  my $output_string = "@output_content";
  close OUT_PUT;

  if(!defined($_[1]))
  {
    print STDOUT $output_string;
  }

  EMD_PERL_DEBUG("clone_util.runSqlOnSource_10_2(): OUT_PUT:\n$output_string");
  if(!defined($_[2]))
  {
    &parseOutput($output_string);
  }

  EMD_PERL_DEBUG("clone_util.runSqlOnSource_10_2(): *** END ***");

  return ($fh, $filename);
}

# Test a local connection
# testLocalConnection(oracleHome, oracleSid, sourceDBUserName, sourceDBPassword)
sub testLocalConnection
{
  EMD_PERL_DEBUG("clone_util_10_2.testLocalConnection(): *** START ***");

  my ($oracleHome, $oracleSid, $sourceDBUserName, $sourceDBPassword) = @_;

  set_env($oracleHome, $oracleSid);
  setSrcDBCredential($sourceDBUserName, $sourceDBPassword);

  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "CONNECT $userID AS SYSDBA;\n";
  $sql_string .= "EXIT;\n";

  my $hideOutput = "";
  my $skipOutputCheck = "";
  (my $fh, my $filename) = &runSqlOnSource_10_2($sql_string, $hideOutput, $skipOutputCheck);

  my $connection = "OK";

  open (TEST_LOCAL_CONNECTION, "$filename") || die "Unable to open tempfile for TEST_LOCAL_CONNECTION\n";
  while (<TEST_LOCAL_CONNECTION>)
  {
    if($_ =~ /ORA-[0-9]/)
    {
      $connection = "NOK";
      EMD_PERL_DEBUG("clone_util_10_2.testLocalConnection(): Test connection fails: $_");
    }
  }

  close TEST_LOCAL_CONNECTION;
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util_10_2.testLocalConnection(): Test connection: $connection");
  EMD_PERL_DEBUG("clone_util_10_2.testLocalConnection(): *** END ***");

  return $connection;
}

# Create a file with signature.
# createSignatureFile_10_2(dirName)
sub createSignatureFile_10_2
{
  my ($dirName) = @_;

  #create dir if not exist
  &mkDir($dirName);

  my $fh;
  my $fileName;

  if(!$NT)
  {
    EMD_PERL_DEBUG("clone_util.createSignatureFile_10_2: To create a file with signature");
    ($fh, $fileName) = tempfile(DIR => $dirName);
  }
  else
  {
    EMD_PERL_DEBUG("clone_util.createSignatureFile_10_2: To create a file with signature on NT");
    $fileName = "$dirName\\"."dbclone.$$";
  }

  #Open the file, add signature, then close it
  open (SIGNATURE_FILE, ">$fileName")
      || die "Unable to open a file for SIGNATURE_FILE\n";
  print SIGNATURE_FILE "createSignatureFile_SIGNATURE";
  close SIGNATURE_FILE || die "Bad SIGNATURE_FILE";

  EMD_PERL_DEBUG("clone_util.createSignatureFile_10_2: File name: $fileName");

  if(!$NT)
  {
    close $fh;
  }

  return $fileName;
}

# Run given rman script on DB
# The caller is responsible to close the returned fileHandle
# runRman(rmanScript, hideOutput, skipOutputCheck) will hide standard output for any
# defined parameter "hideOutput", will skip output check for any defined skipOutputCheck
# runRman(rmanScript) will print standard output
sub runRman
{
  EMD_PERL_DEBUG("clone_util.runRman(): *** START ***");

  my ($rman_string) = $_[0];
  my $rman_string_debug = &filterDBCredentialFromRmanScript($rman_string);
  EMD_PERL_DEBUG("clone_util.runRman(): RMAN Script:\n$rman_string_debug");

  (my $fh, my $filename) = &create_temp_file();

  if($NT)
  {
    $filename = "$TEMP\\"."clone_util.$$";
    EMD_PERL_DEBUG("clone_util.runRman(): temp file: $filename");
    open(RMAN_SCRIPT, "|$ENV{ORACLE_HOME}/bin/rman >$filename")
      || die "Cannot open pipe for RMAN_SCRIPT";
    print RMAN_SCRIPT $rman_string;
    close RMAN_SCRIPT || print "Could not close pipe for RMAN_SCRIPT";
  }
  else
  {
    open(RMAN_SCRIPT, "|$ENV{ORACLE_HOME}/bin/rman >$filename")
      || die "Cannot open pipe for RMAN_SCRIPT";
    print RMAN_SCRIPT $rman_string;
    close RMAN_SCRIPT || print "Could not close pipe for RMAN_SCRIPT";
  }

  my $rman_result = ($? >> 8);

  #Open the temp file to print output to standard output and debug trace file
  open (OUT_PUT, "$filename") || die "Unable to open tempfile for OUT_PUT\n";
  my @output_content = <OUT_PUT>;
  my $output_string = "@output_content";
  close OUT_PUT;

  if(!defined($_[1]))
  {
    print STDOUT $output_string;
  }

  EMD_PERL_DEBUG("clone_util.runRman(): OUT_PUT:\n$output_string");

  if(!defined($_[2]))
  {
    &parseOutputRMAN($output_string, $rman_result);
  }

  EMD_PERL_DEBUG("clone_util.runRman(): *** END ***");

  return ($fh, $filename);
}

# Filter out DB credential from rman script, which is written to trace file
# filterDBCredentialFromRmanScript(rmanScript)
sub filterDBCredentialFromRmanScript
{
  my ($rmanScript) = @_;

  my $position1 = index($rmanScript, "TARGET");
  my $position2 = index($rmanScript, ";");
  my $replacedLength = $position2 - $position1 - 7;
  substr($rmanScript, $position1 + 7, $replacedLength) = "username/password(Hiden intentionally)";

  $position1 = index($rmanScript, "AUXILIARY");
  if($position1 > 0)
  {
    $position2 = index($rmanScript, "\@");
    $replacedLength = $position2 - $position1 - 11;
    substr($rmanScript, $position1 + 11, $replacedLength) = "username/password(Hiden intentionally)";
  }

  return $rmanScript;
}

# Parse the output string to detect RMAN- errors
# parseOutputRMAN(output)
sub parseOutputRMAN
{
  EMD_PERL_DEBUG("clone_util.parseOutputRMAN(): *** START ***");

  my ($output) = $_[0];
  my ($rman_result) = $_[1];

  if (($rman_result != 0) && ($rman_result != 4) && ($rman_result != 5)){
      if (($output =~ /RMAN-07517/) || ($output =~ /RMAN-07518/) || ($output =~ /RMAN-07519/) || ($output =~ /RMAN-07527/)){
    EMD_PERL_DEBUG("clone_util.parseOutputRMAN(): Ignoring RMAN errors");
  }
      else{
    EMD_PERL_ERROR("clone_util.parseOutputRMAN(): RMAN errors; exiting");
    exit(1);
  }
  }
  elsif($rman_result != 0){
      EMD_PERL_WARN("clone_util.parseOutputRMAN(): RMAN warnings; continuing");
  }
  else{
    EMD_PERL_DEBUG("clone_util.parseOutputRMAN(): No Error found.");
  }

  EMD_PERL_DEBUG("clone_util.parseOutputRMAN(): *** END ***");
}

# Create init parameter file based on source DB's v$parameter
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# createSourceInitParamFileOMS(pfileFullName, filteredParams, hideOutput, skipCheckOutput)
sub createSourceInitParamFileOMS
{
  EMD_PERL_DEBUG("clone_util.createSourceInitParamFileOMS(): *** START ***");

  #hideOutput, skipCheckOutput are optional
  my ($pfileFullName, $filteredParamNames, $hideOutput, $skipCheckOutput) = @_;

  EMD_PERL_DEBUG("clone_util.createSourceInitParamFileOMS(): pfileFullName: $pfileFullName");
  EMD_PERL_DEBUG("clone_util.createSourceInitParamFileOMS(): filteredParamNames: $filteredParamNames");

  my @filteredParamNames = split /$DELIMITER/, $filteredParamNames;

  #get names and values from source DB v$parameter
  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "CONNECT $userID AS SYSDBA;\n";
  $sql_string .= "set serveroutput on;\n";
  $sql_string .= "set linesize 512;\n";
  $sql_string .= "declare\n";
  $sql_string .= "  i    binary_integer := 1;\n";
  $sql_string .= "  bigvalue varchar(4096);\n";
  $sql_string .= "  value varchar(255);\n";
  $sql_string .= "BEGIN\n";
  $sql_string .= "  dbms_output.enable(2000000);\n";
  $sql_string .= "  FOR dfrec IN (SELECT name, value FROM V\$PARAMETER WHERE ISDEFAULT = 'FALSE' )\n";
  $sql_string .= "  LOOP\n";
  $sql_string .= "    IF (dfrec.value IS NULL) then\n";
  $sql_string .= "      dfrec.value := '\"\"';\n";
  $sql_string .= "    end if;\n";
  $sql_string .= "    dbms_output.put_line('Parameter ' || i || ':');\n";
  $sql_string .= "    bigvalue := 'param# ' || dfrec.name || '=' || dfrec.value;\n";
  $sql_string .= "    IF (length(bigvalue) > 255) then\n";
  $sql_string .= "      while (length(bigvalue) > 255) LOOP\n";
  $sql_string .= "        value := substr(bigvalue, 1, 255);\n";
  $sql_string .= "        bigvalue := substr(bigvalue, 256);\n";
  $sql_string .= "        dbms_output.put_line(value);\n";
  $sql_string .= "      END LOOP;\n";
  $sql_string .= "      dbms_output.put_line(bigvalue);\n";
  $sql_string .= "    else\n";
  $sql_string .= "      dbms_output.put_line(bigvalue);\n";
  $sql_string .= "    end if;\n";
  $sql_string .= "    i := i + 1;\n";
  $sql_string .= "  END LOOP;\n";
  $sql_string .= "END;\n";
  $sql_string .= "/\n";
  $sql_string .= "EXIT;\n";

  (my $fh, my $filename) = &runSqlOnSource_10_2($sql_string, $hideOutput, $skipCheckOutput);

  #Make the $pfileFullName based on souce v$parameter and filter certain
  #parameters
  open (CREATE_SOURCE_INIT_PARAM, "$filename") || die "Unable to open tempfile for CREATE_SOURCE_INIT_PARAM\n";
  open(INIT_ORA, ">$pfileFullName") || die "Cannot open $pfileFullName";
  my $nameValue = "";
  my $isPrint = "true";
  while (<CREATE_SOURCE_INIT_PARAM>)
  {
    if ($_=~/\bparam#/)
    {
      chomp($_);
      $nameValue = substr $_, 7;  #7 is the position name starts

      foreach $filteredParamNames (@filteredParamNames)
      {
        if ($nameValue =~ /\b$filteredParamNames/)
        {
          $isPrint = "false";
          last;
        }
      }

      if($isPrint eq "true")
      {
        #nls_ parameters need quotes
        if($nameValue =~ /\bnls_/i)
        {
          my @values = split /=/, $nameValue;
          my $name = $values[0];
          my $value = "='".$values[1]."'";
          print INIT_ORA "$name"."$value\n";
        }

        #handle empty os_authent_prefix
        elsif($nameValue =~ /\bos_authent_prefix/i)
        {
          my @values = split /=/, $nameValue;
          my $name = $values[0];
          my $value = "=".$values[1];
          if(&trim($values[1]) eq '')
          {
            $value = "='".$values[1]."'";
          }
          print INIT_ORA "$name"."$value\n";
        }

        #control files could be on multiple lines
        elsif($nameValue =~ /\bcontrol_files/i)
        {
          print INIT_ORA "$nameValue\n";

          my $oneLine = "";
          open (FOR_CONTROL_FILE, "$filename") || die "Unable to open tempfile for FOR_CONTROL_FILE\n";
          my $value = "";
          while ($oneLine = <FOR_CONTROL_FILE>)
          {
            if (($oneLine=~/\bparam#/) && ($oneLine=~/\bcontrol_files/i))
            {
              my $oneControlFile = "";
              while (($oneControlFile eq <FOR_CONTROL_FILE>) && (!($oneControlFile =~ /\bparam#/)
                    && !($oneControlFile =~ /\bParameter/)))
              {
                $value = $oneControlFile;
                print INIT_ORA "$value";
              }
              last;
            }
          }
          close FOR_CONTROL_FILE;
        }

        #dispatchers could be on multiple lines
        elsif($nameValue =~ /\bdispatchers/i)
        {
          my $name = substr $nameValue, 0, 12; #position 0 to 11 contain "dispatchers="
          my $value = substr $nameValue, 12;  #12 is the position value starts
          if($value =~ /,/)
          {
            my @values = split /,/, $value;
            $value = "\"".$values[0]."\",";
          }
          else
          {
            $value = "\"".$value."\"";
          }
          print INIT_ORA "dispatchers=$value\n";

          my $oneLine = "";
          open (FOR_DISPATCHERS, "$filename") || die "Unable to open tempfile for FOR_DISPATCHERS\n";
          $value = "";
          while ($oneLine = <FOR_DISPATCHERS>)
          {
            if (($oneLine=~/\bparam#/) && ($oneLine=~/\bdispatchers/i))
            {
              my $oneDispatchers = "";
              while (($oneDispatchers eq <FOR_DISPATCHERS>) && (!($oneDispatchers =~ /\bparam#/)
                    && !($oneDispatchers =~ /\bParameter/)))
              {
                $value = $oneDispatchers;
                if($value =~ /,/)
                {
                  my @values = split /,/, $value;
                  $value = "\"".$values[0]."\",".$values[1];
                }
                else
                {
                  my @values = split /\n/, $value;
                  $value = "\"".$values[0]."\"\n";
                }
                print INIT_ORA "$value";
              }
              last;
            }
          }
          close FOR_DISPATCHERS;
        }

        #mts_dispatchers could be on multiple lines
        elsif($nameValue =~ /\bmts_dispatchers/i)
        {
          my $name = substr $nameValue, 0, 16; #position 0 to 15 contain "mts_dispatchers="
          my $value = substr $nameValue, 16;  #16 is the position value starts
          if($value =~ /,/)
          {
            my @values = split /,/, $value;
            $value = "\"".$values[0]."\",";
          }
          else
          {
            $value = "\"".$value."\"";
          }
          print INIT_ORA "mts_dispatchers=$value\n";

          my $oneLine = "";
          open (FOR_MTS_DISPATCHERS, "$filename") || die "Unable to open tempfile for FOR_MTS_DISPATCHERS\n";
          $value = "";
          while ($oneLine = <FOR_MTS_DISPATCHERS>)
          {
            if (($oneLine=~/\bparam#/) && ($oneLine=~/\bmts_dispatchers/i))
            {
              my $oneDispatchers = "";
              while (($oneDispatchers eq <FOR_MTS_DISPATCHERS>) && (!($oneDispatchers =~ /\bparam#/)
                    && !($oneDispatchers =~ /\bParameter/)))
              {
                $value = $oneDispatchers;
                if($value =~ /,/)
                {
                  my @values = split /,/, $value;
                  $value = "\"".$values[0]."\",".$values[1];
                }
                else
                {
                  my @values = split /\n/, $value;
                  $value = "\"".$values[0]."\"\n";
                }
                print INIT_ORA "$value";
              }
              last;
            }
          }
          close FOR_MTS_DISPATCHERS;
        }
        else
        {
          # generic look-ahead for parameters that are broken-up across
          #  more than one line
          my $oneLine = "";
          my $nameValue2 = escapeBackSlashes($nameValue);
          open (LOOK_AHEAD, "$filename") || die "Unable to open tempfile for LOOK_AHEAD\n";
          while ($oneLine = <LOOK_AHEAD>){
            if(($oneLine=~/\bparam#/) && ($oneLine=~/\b$nameValue2/i)){
                my $addline = "";
                while (($addline eq <LOOK_AHEAD>) && ($addline !~ /\bparam#/)
                       && ($addline !~ /\bParameter/) && ($addline !~ /^\n$/)){
                  chomp($addline);
                  $nameValue = $nameValue.$addline;
                }
                last;
            }
          }
          close LOOK_AHEAD;

          print INIT_ORA "$nameValue\n";
        }
      }
      else
      {
        $isPrint = "true";
      }
    }
  }
  close CREATE_SOURCE_INIT_PARAM;

  close INIT_ORA || die "Cannot close $pfileFullName";

  #For debug
  if($ENV{EMAGENT_PERL_TRACE_LEVEL} >= 0)
  {
    open (INIT_ORA_FILE, "$pfileFullName") || die "Unable to open tempfile for INIT_ORA_FILE\n";
    my @file_content = <INIT_ORA_FILE>;
    my $file_string = "@file_content";
    close INIT_ORA_FILE;
    EMD_PERL_DEBUG("clone_util.createSourceInitParamFileOMS(): INIT_ORA_FILE:\n $file_string");
  }

  close $fh;

  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.createSourceInitParamFileOMS(): *** END ***");
}

# Sort files by some stat properties in a given location
# Return filenames (from new to old)
# The accepted statFlag are: A (access time), C (change time), M (modify time), S (size)
# sortFileByStat(location, statFlag)
sub sortFileByStat
{
  EMD_PERL_DEBUG("clone_util.sortFileByStat(): *** START ***");

  my ($location, $statFlag) = @_;

  my @files = glob "${location}/*";

  EMD_PERL_DEBUG("clone_util.sortFileByStat(): File names: @files");
  EMD_PERL_DEBUG("clone_util.sortFileByStat(): statFlag: $statFlag");

  my $st;
  my $mtime;
  my @mtimes;

  foreach (0 .. $#files)
  {
    $st = stat($files[$_]) or die "Can't stat $files[$_]: $!";
    if((uc $statFlag) eq 'A')
    {
      $mtime = $st->atime;
    }
    elsif((uc $statFlag) eq 'C')
    {
      $mtime = $st->ctime;
    }
    elsif((uc $statFlag) eq 'M')
    {
      $mtime = $st->mtime;
    }
    elsif((uc $statFlag) eq 'S')
    {
      $mtime = $st->size;
    }
    else
    {
      $mtime = $st->mtime;
    }
    push(@mtimes, $mtime);
  }

  my @sortedFiles;
  my $largestIndex;
  my $largestValue;
  my $value;

  while ($#mtimes > 0)
  {
    $largestValue = $mtimes[0];
    $largestIndex = 0;
    foreach (1 .. $#mtimes)
    {
      $value = $mtimes[$_];
      if($value > $largestValue)
      {
        $largestValue = $value;
        $largestIndex = $_;
      }
    }
    splice(@mtimes, $largestIndex, 1);
    push(@sortedFiles, $files[$largestIndex]);
    splice(@files, $largestIndex, 1);
  }

  #the last  one
  push(@sortedFiles, $files[0]);

  EMD_PERL_DEBUG("clone_util.sortFileByStat(): Sorted file names: @sortedFiles");

  EMD_PERL_DEBUG("clone_util.sortFileByStat(): *** END ***");

  return (@sortedFiles);
}

# Filter files by removing certain file names
# Return filenames
# filterFiles(filesArray)
sub filterFiles
{
  EMD_PERL_DEBUG("clone_util.filterFiles(): *** START ***");

  my (@filesArray) = @_;

  EMD_PERL_DEBUG("clone_util.filterFiles(): Input file names: @filesArray");

  my @files;

  foreach (0 .. $#filesArray)
  {
    #only consider regular files (not directories or devices)
    #do not consider text files
    #filename not starting with "spfile"
    if((-f $filesArray[$_]) && (! -T $filesArray[$_]) && ($filesArray[$_] !~ /${S}spfile/))
    {
      push(@files, $filesArray[$_]);
    }
  }

  EMD_PERL_DEBUG("clone_util.filterFiles(): Resutled file names: @files");

  EMD_PERL_DEBUG("clone_util.filterFiles(): *** END ***");

  return (@files);
}

# escapeBackSlashes(value)
sub escapeBackSlashes
{
  my ($value) = @_;
  EMD_PERL_DEBUG("clone_util.escapeBackSlashes(): before $value");

  $value =~ s/\\/\\\\/gi;

  EMD_PERL_DEBUG("clone_util.escapeBackSlashes(): after $value");

  return $value;
}

############# methods for using RMAN backup ########

# checkRMANBackup includes:
# createInstance
# identifyControlfile
# mountInstance
# catalogBackup
# checkLevelOneIncrementalBackup
# identifyBackupPieces
# cleanupInstance
# It also prints out the identified controlfile, datafile, relog backup pieces
# checkRMANBackup(oracleHome, oracleSid, sourceDBUserName, sourceDBPassword,
#                 backupLocation, workDir, filteredParams)
sub checkRMANBackup
{
  EMD_PERL_DEBUG("clone_util.checkRMANBackup(): *** START ***");

  my ($oracleHome, $oracleSid, $sourceDBUserName, $sourceDBPassword,
      $backupLocation, $workDir, $filteredParams) = @_;

  EMD_PERL_DEBUG("clone_util.checkRMANBackup(): oracleHome: $oracleHome");
  EMD_PERL_DEBUG("clone_util.checkRMANBackup(): oracleSid: $oracleSid");
  EMD_PERL_DEBUG("clone_util.checkRMANBackup(): sourceDBUserName: $sourceDBUserName");
  EMD_PERL_DEBUG("clone_util.checkRMANBackup(): backupLocation: $backupLocation");
  EMD_PERL_DEBUG("clone_util.checkRMANBackup(): workDir: $workDir");
  EMD_PERL_DEBUG("clone_util.checkRMANBackup(): filteredParams: $filteredParams");

  my $CtlFileFullName = ${workDir}.${S}."ctl.f";

  my $dbs = 'dbs';
  if($NT)
  {
    $dbs = 'database';
  }
  my $dbsLocation = ${oracleHome}.${S}.${dbs};

  my $sid = &getFreeSid($oracleHome, $oracleSid);
  my $pfileFullName = ${workDir}.${S}."init".${sid}.".ora";

  my $status = &mkDir($workDir);
  EMD_PERL_DEBUG("clone_util.checkRMANBackup(): create dir $workDir: $status");

  &createInstance($oracleHome, $oracleSid, $sourceDBUserName, $sourceDBPassword, $pfileFullName, $filteredParams, $CtlFileFullName, $dbsLocation, $sid);
  &set_env($ENV{ORACLE_HOME}, $sid);
  my $controlfilePiece = &identifyControlfile($backupLocation, $CtlFileFullName);

  my $rtValue = "";
  if($controlfilePiece ne "")
  {
    &mountInstance($pfileFullName);
    &catalogBackup($backupLocation);

    (my $isLevelOne, my $archMode, my $backupPieces) = &checkLevelOneIncrementalBackup($backupLocation);
    $rtValue = "LEVELONE#".${DELIMITER}.${isLevelOne}.${DELIMITER}."ARCHMODE#".${DELIMITER}.${archMode}.${DELIMITER}."CONTROLFILE#".${DELIMITER}.${controlfilePiece}.${DELIMITER}."BACKUPPIECE#".${DELIMITER}.${backupPieces};

    if($isLevelOne eq "N")
    {
      (my $datafileIds, my $datafilePieces, my $redologPieces) = &identifyBackupPieces($backupLocation);
      $rtValue .= "DATAFILEID#".${DELIMITER}.${datafileIds}."DATAFILEPIECE#".${DELIMITER}.${datafilePieces}."REDOLOGPIECE#".${DELIMITER}.${redologPieces};
    }
  }
  else
  {
    $rtValue = "NO_CONTROLFILE#".${DELIMITER}."".${DELIMITER};
  }

  &cleanupInstance($workDir, $dbsLocation);

  EMD_PERL_DEBUG("clone_util.checkRMANBackup(): return value: $rtValue");

  EMD_PERL_DEBUG("clone_util.checkRMANBackup(): *** END ***");

  return ($rtValue);
}

# This routine gets a free sid in an Oracle Home based on given sid pattern.
# Free means no such process running, no such entry in oratab, no such init/spfile
# Return the found sid.
# getFreeSid(oracleHome, sidPattern)
sub getFreeSid
{
  my ($oracleHome, $sidPattern) = @_;
  EMD_PERL_DEBUG("clone_util.getFreeSid(): Get free sid in $oracleHome based on $sidPattern");

  my $index = 0;
  my $sid = ${sidPattern}.$index;

  my $instance = &instanceCheck($sid, $oracleHome);
  my $oratab = &oratabCheck($sid);
  my $initSpfile = &initoraSpfileCheck($oracleHome, $sid);

  if(($instance eq "OK") and ($oratab eq "OK") and ($initSpfile eq "OK"))
  {
    EMD_PERL_DEBUG("clone_util.getFreeSid(): Sid $sid is unique");
    return $sid;
  }

  while(($instance eq "NOK") or ($oratab eq "NOK") or ($initSpfile eq "NOK"))
  {
    EMD_PERL_DEBUG("clone_util.getFreeSid(): $sid already exists");
    $index = $index + 1;
    $sid = ${sidPattern}.$index;
    $instance = &instanceCheck($sid, $oracleHome);
    $oratab = &oratabCheck($sid);
    $initSpfile = &initoraSpfileCheck($oracleHome, $sid);
  }

  return $sid;
}

# Create a database instance
# createInstance(oracleHome, oracleSid, sourceDBUserName, sourceDBPassword, pfileFullName, filteredParams, CtlFileFullName, dbsLocation, sid)
sub createInstance
{
  EMD_PERL_DEBUG("clone_util.createInstance(): *** START ***");

  my ($oracleHome, $oracleSid, $sourceDBUserName, $sourceDBPassword,
      $pfileFullName, $filteredParams, $CtlFileFullName, $dbsLocation, $sid) = @_;

  EMD_PERL_DEBUG("clone_util.createInstance(): oracleHome: $oracleHome");
  EMD_PERL_DEBUG("clone_util.createInstance(): oracleSid: $oracleSid");
  EMD_PERL_DEBUG("clone_util.createInstance(): sourceDBUserName: $sourceDBUserName");
  EMD_PERL_DEBUG("clone_util.createInstance(): pfileFullName: $pfileFullName");
  EMD_PERL_DEBUG("clone_util.createInstance(): filteredParams: $filteredParams");
  EMD_PERL_DEBUG("clone_util.createInstance(): CtlFileFullName: $CtlFileFullName");
  EMD_PERL_DEBUG("clone_util.createInstance(): dbsLocation: $dbsLocation");
  EMD_PERL_DEBUG("clone_util.createInstance(): temp sid: $sid");

  &set_env($oracleHome, $oracleSid);
  &setSrcDBCredential($sourceDBUserName, $sourceDBPassword);

  #dump the init parameter file from source database, use the passed in filteredParams
  #fileter memory_target too since it may prevent the temp instance from starting
  my $memoryParams = "";
  if($OS eq "LINUX")
  {
    $memoryParams = "memory_target:::memory_max_target:::sga_target:::sga_max_size";
  }

  $filteredParams = ${filteredParams}.${memoryParams};
  &createSourceInitParamFileOMS($pfileFullName, $filteredParams, "", "");

  #modify the dump init file by adding the three parameters back along with new vlaues
  my $memoryValues = "";
  $memoryParams = "";
  if($OS eq "LINUX")
  {
    $memoryParams = ":::shared_pool_size";
    $memoryValues = ":::512M";
  }

  &modifyInitFile("control_files:::instance_name:::db_unique_name".${memoryParams}, "(${CtlFileFullName}):::${sid}:::${sid}".${memoryValues}, $pfileFullName);

  #copy password file if any
  my $srcPassFile = ${dbsLocation}.${S}."orapw"."$oracleSid";
  my $destPassFile = ${dbsLocation}.${S}."orapw"."$sid";
  &copyFile2($srcPassFile, $destPassFile);

  &set_env($ENV{ORACLE_HOME}, $sid);

  #run oradim to create the new service
  if($NT)
  {
    $srcPassFile = ${dbsLocation}.${S}."pwd"."$oracleSid".".ora";
    $destPassFile = ${dbsLocation}.${S}."pwd"."$sid".".ora";
    &copyFile2($srcPassFile, $destPassFile);
    if(! -e "$destPassFile")
    {
      EMD_PERL_DEBUG("clone_util.createInstance(): File $destPassFile does not exist, create a dummy one.");
      open(FH, "> $destPassFile") or die("Error: $!");
      print FH "";
      close(FH) or die("Error: $!");
    }
    &runOradim();
  }

  #kill the old instance
  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "CONNECT $userID AS SYSDBA;\n";
  $sql_string .= "shutdown abort;\n";
  $sql_string .= "exit;\n";

  my $hideOutput = "";
  my $skipOutputCheck = "";
  (my $fh, my $filename) = &runSqlOnSource_10_2($sql_string, $hideOutput, $skipOutputCheck);
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.createInstance(): Old instance has been killed.");

  #Create the server parameter file and start instance
  $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "CONNECT $userID AS SYSDBA;\n";
  $sql_string .= "startup force nomount pfile='$pfileFullName';\n";
  $sql_string .= "exit;\n";

  ($fh, $filename) = &runSqlOnSource_10_2($sql_string, $hideOutput, $skipOutputCheck);
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.createInstance(): *** END ***");
}

# Identify controlfile from a backup location
# Return the backup piece full name containing controlfile
# (passing output by looking for CONTROLFILE_BACKUP_PIECE#)
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# identifyControlfile(backupLocation, restoredName)
sub identifyControlfile
{
  EMD_PERL_DEBUG("clone_util.identifyControlfile(): *** START ***");

  my ($backupLocation, $restoredName) = @_;
  EMD_PERL_DEBUG("clone_util.identifyControlfile(): backupLocation: $backupLocation");
  EMD_PERL_DEBUG("clone_util.identifyControlfile(): restoredName: $restoredName");

  #files sorted by modification time (latest first)
  my @files = &sortFileByStat($backupLocation, "M");
  @files = &filterFiles(@files);
  if(!defined $#files)
  {
    EMD_PERL_DEBUG("clone_util.identifyControlfile(): no file found in $backupLocation");
    return "";
  }

  my $fileNum = $#files + 1;

  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "CONNECT $userID AS SYSDBA;\n";
  $sql_string .= "set serveroutput on;\n";
  $sql_string .= "set linesize 600;\n";
  $sql_string .= "variable devicename varchar2(255);\n";
  $sql_string .= "declare\n";
  $sql_string .= "  type t_varchar2s is table of varchar2(2000) index by binary_integer;\n";
  $sql_string .= "  v_varchar2s      t_varchar2s;\n";
  $sql_string .= "  done boolean;\n";
  $sql_string .= "  i    binary_integer := 1;\n";
  $sql_string .= "  ORA_19697 EXCEPTION;\n";
  $sql_string .= "  PRAGMA EXCEPTION_INIT(ORA_19697, -19697);\n";
  $sql_string .= "  ORA_19624 EXCEPTION;\n";
  $sql_string .= "  PRAGMA EXCEPTION_INIT(ORA_19624, -19624);\n";

  $sql_string .= "BEGIN\n";

  my $j = 0;
  for $j (0 .. $#files)
  {
    $sql_string .= "  v_varchar2s($j+1) := '$files[$j]';\n";
  }

  $sql_string .= "  :devicename := dbms_backup_restore.deviceAllocate;\n";
  $sql_string .= "  dbms_output.enable(2000000);\n";
  $sql_string .= "  dbms_backup_restore.restoreSetDataFile;\n";
  $sql_string .= "  dbms_backup_restore.restoreControlfileTo('$restoredName');\n";

  $sql_string .= "  FOR i IN 1..$fileNum\n";
  $sql_string .= "  LOOP\n";
  $sql_string .= "    BEGIN\n";
  $sql_string .= "      dbms_backup_restore.restoreBackupPiece(v_varchar2s(i), done);\n";
  $sql_string .= "      IF done then\n";
  $sql_string .= "        dbms_output.put_line('RESTORE: found controlfile backup piece');\n";
  $sql_string .= "        dbms_output.put_line('CONTROLFILE_BACKUP_PIECE# ' || v_varchar2s(i));\n";
  $sql_string .= "        EXIT;\n";
  $sql_string .= "      end if;\n";
  $sql_string .= "      EXCEPTION\n";
  $sql_string .= "      WHEN ORA_19697 THEN\n";
  $sql_string .= "        dbms_output.put_line('RESTORE: not the right piece ' || v_varchar2s(i));\n";
  $sql_string .= "      WHEN ORA_19624 THEN\n";
  $sql_string .= "        dbms_output.put_line('RESTORE: could not restore ' || v_varchar2s(i));\n";
  $sql_string .= "      WHEN others THEN\n";
  $sql_string .= "        RAISE;\n";
  $sql_string .= "    END;\n";
  $sql_string .= "  END LOOP;\n";
  $sql_string .= "END;\n";
  $sql_string .= "/\n";
  $sql_string .= "EXIT;\n";

  my $hideOutput = "";
  (my $fh, my $filename) = &runSqlOnSource_10_2($sql_string, $hideOutput, "");

  my @tokens;
  my $ctlFile = "";

  open (CONTROLFILE_PIECE, "$filename") || die "Unable to open tempfile for CONTROLFILE_PIECE\n";
  while (<CONTROLFILE_PIECE>)
  {
    if ($_=~/\bCONTROLFILE_BACKUP_PIECE#/)
    {
      chomp($_);
      @tokens = split;
      $ctlFile = trim($tokens[1]);
    }
  }

  close CONTROLFILE_PIECE;

  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.identifyControlfile(): controlfile backup piece: $ctlFile");

  EMD_PERL_DEBUG("clone_util.identifyControlfile(): *** END ***");

  return $ctlFile;
}

# Mount a database instance
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# mountInstance(pfileFullName)
sub mountInstance
{
  EMD_PERL_DEBUG("clone_util.mountInstance(): *** START ***");

  my ($pfileFullName) = @_;

  EMD_PERL_DEBUG("clone_util.mountInstance(): pfileFullName: $pfileFullName");

  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "CONNECT $userID AS SYSDBA;\n";
  $sql_string .= "startup force mount pfile='$pfileFullName';\n";
  $sql_string .= "exit;\n";

  my $hideOutput = "";
  (my $fh, my $filename) = &runSqlOnSource_10_2($sql_string, $hideOutput, "");
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.mountInstance(): *** END ***");
}

# Identify backup pieces for datafiles and redo logs
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# identifyBackupPieces(backupLocation)
sub identifyBackupPieces
{
  EMD_PERL_DEBUG("clone_util.identifyBackupPieces(): *** START ***");

  my ($backupLocation) = @_;
  EMD_PERL_DEBUG("clone_util.identifyControlfile(): backupLocation: $backupLocation");

  my $backupLocationMatch = ${backupLocation}.${S}."%";
  my $backupLocationSubMatch = ${backupLocation}.${S}."%".${S}."%";

  my $UPPER = "";
  if($NT)
  {
    $UPPER = "upper";
  }

  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "CONNECT $userID AS SYSDBA;\n";
  $sql_string .= "set serveroutput on;\n";
  $sql_string .= "set linesize 600;\n";  #at least 540 (number is 9, string 513)

  $sql_string .= "SELECT 'file# ' as \"F_FLAG\", df.file#, 'handle# ' as \"H_FLAG\", bp.handle \n";
  $sql_string .= "FROM v\$backup_piece bp, v\$backup_datafile bdf, v\$datafile df \n";
  $sql_string .= "WHERE ${UPPER}(bp.handle) like ${UPPER}('$backupLocationMatch') and ${UPPER}(bp.handle) not like ${UPPER}('$backupLocationSubMatch') and bp.status = 'A' and bdf.set_stamp = bp.set_stamp and \n";
  $sql_string .= "      bdf.set_count = bp.set_count and bdf.file# = df.file# and \n";
  $sql_string .= "      bdf.incremental_change# <= bdf.creation_change# \n";
  $sql_string .= "      order by df.file#; \n";

  $sql_string .= "SELECT 'redolog# ' as \"R_FLAG\", bp.handle \n";
  $sql_string .= "FROM v\$backup_piece bp, v\$backup_redolog brl \n";
  $sql_string .= "WHERE ${UPPER}(bp.handle) like ${UPPER}('$backupLocationMatch') and ${UPPER}(bp.handle) not like ${UPPER}('$backupLocationSubMatch') and bp.status = 'A' and brl.set_stamp = bp.set_stamp and \n";
  $sql_string .= "      brl.set_count = bp.set_count and brl.first_change# = \n";
  $sql_string .= "      (select max(first_change#) from v\$backup_redolog); \n";

  $sql_string .= "EXIT;\n";

  my $hideOutput = "";
  (my $fh, my $filename) = &runSqlOnSource_10_2($sql_string, $hideOutput, "");

  my $fileid = "";
  my $fileids = "";
  my $handle = "";
  my $handles = "";
  my $redolog = "";
  my $redologs = "";
  my @tokens;

  open (BACKUP_PIECES, "$filename") || die "Unable to open tempfile for BACKUP_PIECES\n";
  while (<BACKUP_PIECES>)
  {
    if (($_=~/\bfile#/) && ($_=~/handle#/))
    {
      chomp($_);
      @tokens = split;
      $fileid = trim($tokens[1]);
      $fileids .= ${fileid}.${DELIMITER};
      $handle = trim($tokens[3]);
      $handles .= ${handle}.${DELIMITER};
    }
    elsif ($_=~/\bredolog#/)
    {
      chomp($_);
      @tokens = split;
      $redolog = trim($tokens[1]);
      $redologs .= ${redolog}.${DELIMITER};
    }
  }

  close BACKUP_PIECES;
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.identifyBackupPieces(): datafile ids: $fileids");
  EMD_PERL_DEBUG("clone_util.identifyBackupPieces(): datafile backup pieces: $handles");
  EMD_PERL_DEBUG("clone_util.identifyBackupPieces(): redolog backup pieces: $redologs");

  EMD_PERL_DEBUG("clone_util.identifyBackupPieces(): *** END ***");

  return ($fileids, $handles, $redologs);
}

# Cleanup a database instance and related init file, ctl file, and password file
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# cleanupInstance(workDir, dbsLoc)
sub cleanupInstance
{
  EMD_PERL_DEBUG("clone_util.cleanupInstance(): *** START ***");

  my ($workDir, $dbsLoc) = @_;

  EMD_PERL_DEBUG("clone_util.cleanupInstance(): workDir: $workDir");
  EMD_PERL_DEBUG("clone_util.cleanupInstance(): dbsLoc: $dbsLoc");

  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "CONNECT $userID AS SYSDBA;\n";
  $sql_string .= "shutdown abort;\n";
  $sql_string .= "exit;\n";

  my $hideOutput = "";
  (my $fh, my $filename) = &runSqlOnSource_10_2($sql_string, $hideOutput, "");
  close $fh;
  if($NT)
  {
    my($cmd) = $ENV{ORACLE_HOME}."${S}bin${S}oradim.exe -delete -SID ".$ENV{ORACLE_SID};
    EMD_PERL_DEBUG("clone_util.cleanupInstance(): delete service: $cmd");
    my(@res) = `$cmd >$filename 2>&1`;
    EMD_PERL_DEBUG("clone_util.cleanupInstance(): delete service output: @res");
    &removeFile($filename);
  }

  #remove related files
  my $upperSid = uc $ENV{ORACLE_SID};
  my $passwdFile = ${dbsLoc}.${S}."orapw"."$ENV{ORACLE_SID}";
  my $hcFile = ${dbsLoc}.${S}."hc_"."$ENV{ORACLE_SID}".".dat";
  my $lkFile = ${dbsLoc}.${S}."lk".$upperSid;
  &removeDir($workDir);
  if(-e $passwdFile)
  {
    &removeFile($passwdFile);
  }
  if(-e $hcFile)
  {
    &removeFile($hcFile);
  }
  if(-e $lkFile)
  {
    &removeFile($lkFile);
  }

  EMD_PERL_DEBUG("clone_util.cleanupInstance(): *** END ***");
}

# Catalog the RMAN backup
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# catalogBackup(backupLocation)
sub catalogBackup
{
  EMD_PERL_DEBUG("clone_util.catalogBackup(): *** START ***");

  my ($backupLocation) = @_;
  EMD_PERL_DEBUG("clone_util.catalogBackup(): backupLocation: $backupLocation");

  my $rman_string = "";
  $rman_string .= "set echo off\n";
  $rman_string .= "CONNECT TARGET $userID;\n";
  $rman_string .= "set echo on\n";
  $rman_string .= "crosscheck backup;\n";
  $rman_string .= "catalog start with '${backupLocation}/'; \n";
  $rman_string .= "YES\n";
  $rman_string .= "EXIT;\n";

  my ($fh, $filename) = &runRman($rman_string, "", "");
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.catalogBackup(): *** END ***");
}

# Check if the backup is level 1 incremental backup
# call &set_env($oracleHome, $oracleSid) before calling this method.
# call catalogBackup(backupLocation) before calling this method.
# checkLevelOneIncrementalBackup(backupLocation)
sub checkLevelOneIncrementalBackup
{
  EMD_PERL_DEBUG("clone_util.checkLevelOneIncrementalBackup(): *** START ***");

  my ($backupLocation) = @_;
  EMD_PERL_DEBUG("clone_util.checkLevelOneIncrementalBackup(): backupLocation: $backupLocation");

  my $backupLocationMatch = ${backupLocation}.${S}."%";
  my $backupLocationSubMatch = ${backupLocation}.${S}."%".${S}."%";

  my $UPPER = "";
  if($NT)
  {
    $UPPER = "upper";
  }

  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "CONNECT $userID AS SYSDBA;\n";
  $sql_string .= "set serveroutput on;\n";
  $sql_string .= "set linesize 600;\n";  #at least 540 (number is 9, string 513)

  $sql_string .= "SELECT 'piece# ' as \"P_FLAG\", count(*) \n";
  $sql_string .= "FROM v\$backup_piece bp, v\$backup_datafile bdf, v\$datafile df \n";
  $sql_string .= "WHERE ${UPPER}(bp.handle) like ${UPPER}('$backupLocationMatch') and ${UPPER}(bp.handle) not like ${UPPER}('$backupLocationSubMatch') and bp.status = 'A' and bdf.set_stamp = bp.set_stamp and \n";
  $sql_string .= "      bdf.set_count = bp.set_count and bdf.file# = df.file# \n";
  $sql_string .= "      order by df.file#; \n";

  $sql_string .= "SELECT 'datafile# ' as \"D_FLAG\", count(*) \n";
  $sql_string .= "FROM v\$datafile; \n";

  $sql_string .= "SELECT 'archmode# ' as \"A_FLAG\", log_mode \n";
  $sql_string .= "FROM v\$database; \n";

  $sql_string .= "EXIT;\n";

  my $hideOutput = "";
  (my $fh, my $filename) = &runSqlOnSource_10_2($sql_string, $hideOutput, "");

  my $pieceNum = 0;
  my $dfNum = 0;
  my $archMode = "";
  my @tokens;

  open (LEVEL_ONE, "$filename") || die "Unable to open tempfile for LEVEL_ONE\n";
  while (<LEVEL_ONE>)
  {
    if ($_=~/\bpiece#/)
    {
      chomp($_);
      @tokens = split;
      $pieceNum = trim($tokens[1]);
    }
    elsif ($_=~/\bdatafile#/)
    {
      chomp($_);
      @tokens = split;
      $dfNum = trim($tokens[1]);
    }
    elsif ($_=~/\barchmode#/)
    {
      chomp($_);
      @tokens = split;
      $archMode = trim($tokens[1]);
    }
  }

  close LEVEL_ONE;
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.checkLevelOneIncrementalBackup(): pieceNum: $pieceNum");
  EMD_PERL_DEBUG("clone_util.checkLevelOneIncrementalBackup(): dfNum: $dfNum");
  EMD_PERL_DEBUG("clone_util.checkLevelOneIncrementalBackup(): archMode: $archMode");

  my $isLevelOne = "N";
  my $backupPieceNames = "";

  #level one incremental backup
  if($pieceNum > $dfNum)
  {
    $isLevelOne = "Y";
  }

  EMD_PERL_DEBUG("clone_util.checkLevelOneIncrementalBackup(): is Level One Backup: $isLevelOne");

  my @files = glob "${backupLocation}/*";
  if(!defined $#files)
  {
    EMD_PERL_DEBUG("clone_util.checkLevelOneIncrementalBackup(): no file found in $backupLocation");
    return ($isLevelOne, $archMode, $backupPieceNames);
  }

  my $fileNum = $#files + 1;

  my $j = 0;
  for $j (0 .. $#files)
  {
    #only consider regular files (not directories or devices)
    #do not consider text files
    if((-f $files[$j]) && (! -T $files[$j]))
    {
      $backupPieceNames .= $files[$j].${DELIMITER};
    }
  }

  EMD_PERL_DEBUG("clone_util.checkLevelOneIncrementalBackup(): backup piece names: $backupPieceNames");

  EMD_PERL_DEBUG("clone_util.checkLevelOneIncrementalBackup(): *** END ***");

  return ($isLevelOne, $archMode, $backupPieceNames);
}

# Restore and recover the database
# Run in destination Oracle Home
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# restoreRecoverDatabase(backupLocation, datafileNums, datafileNames,
#                        origLogfileNames, newLogfileNames,
#                        omfFlag, asmFlag, $isDG)
sub restoreRecoverDatabase
{
  EMD_PERL_DEBUG("clone_util.restoreRecoverDatabase(): *** START ***");

  my ($backupLocation, $datafileNums, $datafileNames, $origLogfileNames, $newLogfileNames,
      $omfFlag, $asmFlag, $isDG) = @_;

  EMD_PERL_DEBUG("clone_util.restoreRecoverDatabase(): backupLocation: $backupLocation");
  EMD_PERL_DEBUG("clone_util.restoreRecoverDatabase(): datafileNums: $datafileNums");
  EMD_PERL_DEBUG("clone_util.restoreRecoverDatabase(): datafileNames: $datafileNames");
  EMD_PERL_DEBUG("clone_util.restoreRecoverDatabase(): origLogfileNames: $origLogfileNames");
  EMD_PERL_DEBUG("clone_util.restoreRecoverDatabase(): newLogfileNames: $newLogfileNames");
  EMD_PERL_DEBUG("clone_util.restoreRecoverDatabase(): omfFlag: $omfFlag");
  EMD_PERL_DEBUG("clone_util.restoreRecoverDatabase(): asmFlag: $asmFlag");
  EMD_PERL_DEBUG("clone_util.restoreRecoverDatabase(): isDG: $isDG");

  if($omfFlag eq "Y")
  {
    $datafileNames = &getOMFfilename($datafileNums);
  }

  my @datafileNumList = split /$DELIMITER/, $datafileNums;
  my @datafileNameList = split /$DELIMITER/, $datafileNames;
  my @origLogfileNameList = split /$DELIMITER/, $origLogfileNames;
  my @newLogfileNameList = split /$DELIMITER/, $newLogfileNames;

  &catalogBackup($backupLocation);

  my $scn = &getScn();

  my $rman_string = "";
  $rman_string .= "set echo off\n";
  $rman_string .= "CONNECT TARGET $userID;\n";

  $rman_string .= "set echo on\n";

  $rman_string .= "run {\n";

  foreach (0 .. $#datafileNumList)
  {
    $rman_string .= "  SET NEWNAME FOR DATAFILE $datafileNumList[$_] TO '$datafileNameList[$_]';\n";
  }

  ## DG: Just restore database
  if($isDG eq "N")
  {
    if(($omfFlag ne "Y") && ($asmFlag ne "Y"))
    {
      foreach (0 .. $#origLogfileNameList)
      {
        $rman_string .= "  SQL \"ALTER DATABASE RENAME FILE ''$origLogfileNameList[$_]'' TO ''$newLogfileNameList[$_]''\";\n";
      }
    }

    $rman_string .= "  SET UNTIL SCN $scn;\n";
    $rman_string .= "  RESTORE DATABASE;\n";
    $rman_string .= "  SWITCH DATAFILE ALL;\n";
    $rman_string .= "  RECOVER DATABASE;\n";
  }
  else
  {
    $rman_string .= "  RESTORE DATABASE;\n";
  }

  $rman_string .= "} \n";

  $rman_string .= "EXIT;\n";

  my ($fh, $filename) = &runRman($rman_string);
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.restoreRecoverDatabase(): *** END ***");
}

# Get the SCN
# Return scn number
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# getScn()
sub getScn
{
  EMD_PERL_DEBUG("clone_util.getScn(): *** START ***");

  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "set serveroutput on;\n";
  $sql_string .= "set linesize 512;\n";

  $sql_string .= "select 'scn# ' as \"S_FLAG\", checkpoint_change# from v\$database;\n";

  $sql_string .= "EXIT;\n";

  my $hideOutput = "";
  (my $fh, my $filename) = &runSqlOnDestination($sql_string, $hideOutput);

  my $scn = "";
  my @tokens;

  open (DATABASE_SCN, "$filename") || die "Unable to open tempfile for DATABASE_SCN\n";
  while (<DATABASE_SCN>)
  {
    if ($_=~/\bscn#/)
    {
      chomp($_);
      @tokens = split;
      $scn = trim($tokens[1]);
    }
  }

  close DATABASE_SCN;
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.getScn(): database SCN: $scn");

  EMD_PERL_DEBUG("clone_util.getScn(): *** END ***");

  return ($scn);
}

# getOMFfilename(fileNums)
sub getOMFfilename
{
  EMD_PERL_DEBUG("clone_util.getOMFfilename(): *** START ***");

  my ($fileNums) = @_;

  EMD_PERL_DEBUG("clone_util.getOMFfilename(): File numbers: $fileNums");

  my @fileNumList = split /$DELIMITER/, $fileNums;

  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "set serveroutput on;\n";
  $sql_string .= "set linesize 600;\n";
  $sql_string .= "declare\n";
  $sql_string .= "  tbsName varchar2(30);\n";
  $sql_string .= "  omfname varchar2(512) := NULL;\n";

  $sql_string .= "BEGIN\n";
  $sql_string .= "    dbms_output.put_line('List of OMF file names:');\n";

  foreach (0 .. $#fileNumList)
  {
    $sql_string .= "    SELECT ts.name INTO tbsName FROM V\$DATAFILE df, V\$TABLESPACE ts WHERE df.file# = $fileNumList[$_] and df.ts# = ts.ts#;\n";
    $sql_string .= "    dbms_backup_restore.getOMFFileName(tbsName, omfname);\n";
    $sql_string .= "    dbms_output.put_line('omfname# '||omfname);\n";
  }

  $sql_string .= "END;\n";
  $sql_string .= "/\n";
  $sql_string .= "EXIT;\n\n";

  my $hideOutput = "";
  (my $fh, my $filename) = &runSqlOnDestination($sql_string, $hideOutput);

  my $omfname = "";
  my $omfnames = "";

  open (GET_OMFNAME, "$filename") || die "Unable to open tempfile for GET_OMFNAME\n";
  while (<GET_OMFNAME>)
  {
    if ($_=~/\bomfname#/)
    {
      chomp($_);
      $omfname = substr $_, 9; #omfname starts from position 9
      $omfnames .= ${omfname}.${DELIMITER};
    }
  }

  close GET_OMFNAME;
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.getOMFfilename(): OMF file names: $omfnames");

  EMD_PERL_DEBUG("clone_util.getOMFfilename(): *** END ***");

  return ($omfnames);
}
############# end methods for using RMAN backup ########

############# methods for using RMAN duplicate #########
# Duplicate the target (source) database to auxiliary database
# Run in source Oracle Home
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# duplicateDatabase(auxHost, auxPort, auxSid, auxDBName, datafileNums, datafileNames,
#                   tempfileNums, tempfileNames, logGroups, origlogfileNames, logfileNames,

#                   externalFile, parallelism, passwdFile, spfile, destTempDir,
#                   omfFlag, asmFlag, recFlag, clonePurpose, isSameHost, noOfChannelsAllocated)
sub duplicateDatabase
{
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): *** START ***");

  my ($auxHost, $auxPort, $auxSid, $auxDBName, $datafileNums, $datafileNames,
      $tempfileNums, $tempfileNames, $logGroups, $origLogfileNames, $logfileNames,
      $externalFile, $parallelism, $passwdFile, $spfile, $destTempDir,
      $omfFlag, $asmFlag, $recFlag, $clonePurpose, $isSameHost, $noOfChannelsAllocated) = @_;

  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): auxHost: $auxHost");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): auxPort: $auxPort");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): auxSid: $auxSid");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): auxDBName: $auxDBName");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): datafileNums: $datafileNums");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): datafileNames: $datafileNames");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): tempfileNums: $tempfileNums");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): tempfileNames: $tempfileNames");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): logGroups: $logGroups");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): origLogfileNames: $origLogfileNames");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): logfileNames: $logfileNames");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): externalFile: $externalFile");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): parallelism: $parallelism");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): passwdFile: $passwdFile");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): spfile: $spfile");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): destTempDir: $destTempDir");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): omfFlag: $omfFlag");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): asmFlag: $asmFlag");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): recFlag: $recFlag");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): isSameHost: $isSameHost");
  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): noOfChannelsAllocated: $noOfChannelsAllocated");

  my @datafileNumList = split /$DELIMITER/, $datafileNums;
  my @datafileNameList = split /$DELIMITER/, $datafileNames;
  my @tempfileNumList = split /$DELIMITER/, $tempfileNums;
  my @tempfileNameList = split /$DELIMITER/, $tempfileNames;
  my @logGroupList = split /$DELIMITER/, $logGroups;
  my @origLogfileNameList = split /$DELIMITER/, $origLogfileNames;
  my @logfileNameList = split /$DELIMITER/, $logfileNames;

  #my $format = &getLogArchiveFormat();
  #$format = "c".$format;

  my $rman_string = "";
  $rman_string .= "set echo off\n";
  $rman_string .= "CONNECT TARGET $userID;\n";
  $rman_string .= "CONNECT AUXILIARY \"$userID\@(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP) (HOST = $auxHost) (PORT = $auxPort)))(CONNECT_DATA = (SID = $auxSid)))\";\n";

  $rman_string .= "set echo on\n";

  $rman_string .= "run {\n";

  if(($omfFlag eq "N") && ($asmFlag eq "N"))
  {
    foreach (0 .. $#datafileNumList)
    {
      $rman_string .= "  SET NEWNAME FOR DATAFILE $datafileNumList[$_] TO '$datafileNameList[$_]';\n";
    }

    foreach (0 .. $#tempfileNumList)
    {
      $rman_string .= "  SET NEWNAME FOR TEMPFILE $tempfileNumList[$_] TO '$tempfileNameList[$_]';\n";
    }

    #$rman_string .= "  SQL CLONE \"ALTER SYSTEM SET log_archive_dest = ''$destTempDir''\";\n";

    ## For non-OMF standby, rename logfiles (using undocumented SET NEWNAME for LOGFILE)
    ## so that RMAN will create the logfiles under the new names.
    if($clonePurpose eq "STANDBY_NO_RECOVERY"){
      foreach (0 .. $#origLogfileNameList)
      {
        if($origLogfileNameList[$_] ne "OMF_FILE"){
          $rman_string .= "  SET NEWNAME FOR LOGFILE '$origLogfileNameList[$_]' TO '$logfileNameList[$_]';\n";
        }
      }
    }
  }

  for(my $count=1; $count<=$noOfChannelsAllocated; $count++)
  {
    $rman_string .= "allocate channel tgt$count type disk;\n";
  }
  $rman_string .= "allocate auxiliary channel dup1 type disk;\n";

  $rman_string .= " DUPLICATE TARGET DATABASE";

  if($clonePurpose eq "STANDBY_NO_RECOVERY"){
    $rman_string .= " FOR STANDBY \n";
  }
  else {
    $rman_string .= " TO '$auxDBName'\n";
  }
  $rman_string .= " FROM ACTIVE DATABASE\n";

  #Add options for DUPLICATE here and before LOGFILE part:


  ## logfile group option is not valid for standby duplicate.
  if($clonePurpose eq "STANDBY_NO_RECOVERY"){
    # Prevent RMAN from checking whether files on the target database that have the same names as the duplicated files are in use
    # only in case of cloning happening in different hosts.
    if($isSameHost eq "N"){
      $rman_string .= " NOFILENAMECHECK\n";
    }
    $rman_string .= "  ;\n";
  }
  elsif(($omfFlag ne "Y") && ($asmFlag ne "Y"))
  {
    $rman_string .= "  LOGFILE\n";
    my $prev_group = "";
    my $curr_group = "";
    my $next_group = "";
    foreach (0 .. $#logGroupList - 1)
    {
      $curr_group = $logGroupList[$_];
      $next_group = $logGroupList[$_ + 1];
      if(($curr_group ne $prev_group) && ($curr_group ne $next_group))
      {
        $rman_string .= "  GROUP $logGroupList[$_] ('$logfileNameList[$_]') size 20M reuse,\n";
      }
      elsif(($curr_group ne $prev_group) && ($curr_group eq $next_group))
      {
        $rman_string .= "  GROUP $logGroupList[$_] ('$logfileNameList[$_]',\n";
      }
      elsif(($curr_group eq $prev_group) && ($curr_group ne $next_group))
      {
        $rman_string .= "  '$logfileNameList[$_]') size 20M reuse,\n";
      }
      elsif(($curr_group eq $prev_group) && ($curr_group eq $next_group))
      {
        $rman_string .= "  '$logfileNameList[$_]',\n";
      }

      $prev_group = $curr_group;
    }
    $curr_group = $logGroupList[$#logGroupList];
    if($curr_group ne $prev_group)
    {
      $rman_string .= "  GROUP $logGroupList[$#logGroupList] ('$logfileNameList[$#logfileNameList]') size 20M reuse\n";
    }
    else
    {
      $rman_string .= "  '$logfileNameList[$#logfileNameList]') size 20M reuse\n";
    }
    # Prevent RMAN from checking whether files on the target database that have the same names as the duplicated files are in use
    # only in case of cloning happening in different hosts.
    if($isSameHost eq "N"){
      $rman_string .= " NOFILENAMECHECK;\n";
    } else {
      $rman_string .= ";\n";
    }
  }
  else
  {
      # Prevent RMAN from checking whether files on the target database that have the same names as the duplicated files are in use
      # only in case of cloning happening in different hosts.
      if($isSameHost eq "N"){
        $rman_string .= " NOFILENAMECHECK\n";
      }
    $rman_string .= "  ;\n";
  }

  #Do not add optoins for DUPLICATE command after LOGFILE part
  #But other RMAN commands could be added here:

  $rman_string .= "} \n";

  # The following code is commented as we dont see any requirement of emitting the text "YES" to RMAN
  #if(($clonePurpose ne "STANDBY_NO_RECOVERY") && (($omfFlag eq "Y") || ($asmFlag eq "Y") || ($recFlag eq "Y")))
  #{
  #  $rman_string .= "YES\n";
  #}

  $rman_string .= "EXIT;\n";

  my $hideOutput; #not defined
  my $skipCheck;

  my ($fh, $filename) = &runRman($rman_string, $hideOutput, $skipCheck);
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.duplicateDatabase(): *** END ***");
}

# Get the log_archive_format
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# getLogArchiveFormat()
sub getLogArchiveFormat
{
  EMD_PERL_DEBUG("clone_util.getLogArchiveFormat(): *** START ***");

  my $sql_string = "";
  $sql_string .= "set echo off\n";
  $sql_string .= "set serveroutput on;\n";
  $sql_string .= "set linesize 4096;\n";

  $sql_string .= "select 'format# ' as \"F_FLAG\", value from v\$parameter where name='log_archive_format';\n";

  $sql_string .= "EXIT;\n";

  my $hideOutput = "";
  (my $fh, my $filename) = &runSqlOnDestination($sql_string, $hideOutput);

  my $format = "";
  my @tokens;

  open (LOG_ARCHIVE_FORMAT, "$filename") || die "Unable to open tempfile for LOG_ARCHIVE_FORMAT\n";
  while (<LOG_ARCHIVE_FORMAT>)
  {
    if ($_=~/\bformat#/)
    {
      chomp($_);
      @tokens = split;
      $format = trim($tokens[1]);
    }
  }

  close LOG_ARCHIVE_FORMAT;
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  EMD_PERL_DEBUG("clone_util.getLogArchiveFormat(): log_archive_format: $format");

  EMD_PERL_DEBUG("clone_util.getLogArchiveFormat(): *** END ***");

  return ($format);
}

############# end methods for using RMAN duplicate #####

# check if the Oracle Home compatible with the given version.
# isOracleVersionCompatible(oracleHome, version)
sub isOracleVersionCompatible
{
  my $oracleHome = $_[0];
  my $version = $_[1];
  EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): the given oracleHome: $oracleHome");
  EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): the given version: $version");

  my $dirExist = dirExists($oracleHome);
  if( $dirExist ne "OK")
  {
    EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): Invalid directory: $oracleHome");
    return "NOK1";
  }

  set_env_var($oracleHome, "");
  my $nls_lang = $ENV{NLS_LANG};
  $ENV{NLS_LANG} = 'American_America.al32utf8';

  #use sqlplus to detect if this is a valid Oracle Home
  #we use sqlplus during cloning
  my @sqlplusString = `$oracleHome/bin/sqlplus -v 2>&1`;
  my $sqlplusString = "@sqlplusString";
  EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): sqlplusString: $sqlplusString");

  my $sqlplusPos = index($sqlplusString, "SQL*Plus:");
  if( $sqlplusPos < 0)
  {
    EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): Bad SQLPLUS in Oracle Home: $oracleHome");
    return "NOK2";
  }

  #check if rman executable exists
  my $rmanExe = "rman";
  if($NT)
  {
    $rmanExe = "rman.exe"
  }

  if(! -e "$oracleHome/bin/$rmanExe")
  {
    EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): RMAN executable file does not exist in Oracle Home: $oracleHome");
    return "NOK2";
  }

  my $rman_string = "";
  $rman_string .= "EXIT;\n";

  my ($fh, $filename) = &runRman($rman_string, "", "");

  my $versionString = getOutputFromFile($filename);
  EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): versionString: $versionString");

  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }

  if(defined($nls_lang))
  {
    $ENV{NLS_LANG} =$nls_lang;
  }

  my $startPos = index($versionString, "Recovery Manager:");
  if( $startPos < 0)
  {
    EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): Bad RMAN in Oracle Home: $oracleHome");
    return "NOK2";
  }

  #the length of Recovery Manager: plus a space is 18
  my $rmanVersion = trim(substr($versionString, $startPos + 18));
  EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): rmanVersion: $rmanVersion");

  $startPos = index($rmanVersion, $version);
  if($startPos < 0)
  {
    EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): $rmanVersion is not compatible with $version");
    return "NOK3";
  }
  else
  {
    #assume the last (fifth) part in version is at most two digits, such as 11.1.0.3.5
    #it should be one digit in almost all case, just remove the second one by trimming the space
    $rmanVersion = trim(substr($rmanVersion, $startPos, length($version) +2));
    EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): the exact RMAN version is $rmanVersion");
  }

  my $dbs = 'dbs';
  if($NT)
  {
    $dbs = 'database';
  }
  my $dbsLocation = ${oracleHome}.${S}.${dbs};
  my $wPermission = dirWritePermission($dbsLocation);
  if( $wPermission ne "OK")
  {
    EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): No write permission in: $dbsLocation");
    return "NOK4";
  }

  EMD_PERL_DEBUG("clone_util.isOracleVersionCompatible(): $rmanVersion is compatible with $version");
  return $rmanVersion;
}

# Get the available shared memory in bytes
# getSharedMemorySize()
sub getSharedMemorySize
{
  if($OS eq "LINUX")
  {
    my $memLoc = "/dev/shm";

    my $dirExist = &dirExists($memLoc);
    if($dirExist ne "OK")
    {
      return "-1";
    }

    my $freeSize = &getFreeSpace($memLoc);
    $freeSize = $freeSize * 1024;  #convert to bytes
    EMD_PERL_DEBUG("clone_util.getSharedMemorySize(): free space in $memLoc is: $freeSize bytes");
    return $freeSize;
  }
  EMD_PERL_DEBUG("clone_util.getSharedMemorySize(): Not LINUX platform");
  return "-2";
}

1;

#Tests
#removed main_clone_util_10_2