# $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) = ¶mForGetFreePort_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) = ¶mForGetFreePort_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) = ¶mForGetFreePort_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"; ©File2($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"; ©File2($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