# DCasm.ctl:402:Collects Automatic Storage Management Information # $Id: DCasm.ctl,v 1.19 2015/08/13 20:29:37 RDA Exp $ # ARCS: $Header: /home/cvs/cvs/RDA_8/src/scripting/lib/collect/DB/DCasm.ctl,v 1.19 2015/08/13 20:29:37 RDA Exp $ # # Change History # 20150813 MSC Eliminate Perl 5.22 warnings. =head1 NAME DB:DCasm - Collects Automatic Storage Management Information =head1 DESCRIPTION This module collects Automatic Storage Management (ASM) information (Oracle Database 10g or later). This module must be run as SYSDBA to collect all information. The following reports can be generated and are regrouped under C: =cut echo tput('bold'),'Processing DB.ASM module ...',tput('off') # Initialization var $ALERT_TEXT = ${B_ALERT_TEXT:true} var $ALERT_SUMMARY = ${B_ALERT_SUMMARY} var $ALLOCATION = ${B_ALLOCATION:true} var $ADVANCED = ${B_ADVANCED} var $ASM_DGS = ${B_ASM_DGS:false} var $BDUMP_MAX = ${N_TRACE_BDUMP:2} var $DEVICES = ${B_DEVICES:true} var $DISTINCT_HOME = ${B_DISTINCT_HOME:false} var $LOG_AGE = ${R_TRACE_AGE/T:15} var $LOG_ERRORS = max(1,${N_TRACE_ERRORS:250}) var $LOG_TRESHOLD = ${N_TRACE_TRESHOLD:20480} var $LOG_RATIO = max(1,${N_TRACE_RATIO:10}) var $LOG_VOLUME = ${R_TRACE_VOLUME/T:10} var $ORACLE_HOME = ${D_ORACLE_HOME:''} var $ORACLE_SID = ${T_ORACLE_SID:'+ASM'} var $UDUMP_AGE = ${R_TRACE_UDUMP/T:0} var $DG_TBL = cond($ASM_DGS,'v$asm_diskgroup_stat','v$asm_diskgroup') var $OSN = getOsName() var $TOC = '%TOC%' var $TOP = '[[#Top][Back to top]]' toc '1:ASM' # Load the libraries run DB:DBalert() run DB:DBinfo() run RDA:INVinfo() run RDA:library() =head2 product_info - Product Information Gathers the ASM product information if ASM is installed in a separate Oracle Home. =cut if $DISTINCT_HOME {debug ' Inside ASM module, processing Product Information (can take time)' report product_info write '---+!! ASM Oracle Home Product Information' write '---## From ',encode($ORACLE_HOME),' ' write $TOC write '---+ Files in Oracle Home' call statDir('an',$ORACLE_HOME) write $TOP call inventory_details(catDir($ORACLE_HOME,'inventory'),${B_INTERIM}) toc '2:[[',getFile(),'][rda_report][Product Information]]' } =head2 no_access - No Instance Access Reports database access issue. =cut var $SQL_ACCESS = true if testSql() {report no_access write 'Cannot connect to the ASM instance (',getSqlMessage(),')' toc '2:[[',getFile(),'][rda_report][No Instance Access]]' var $SQL_ACCESS = false } =head2 init_ora - INIT.ORA Determines if the C is used. RDA connects to the database and looks for a value coming from the C parameter. If a value is found, RDA does not search for F. A select for C is executed to determine whether to skip the search for F. =cut else {debug ' Inside ASM module, processing INIT.ORA' report init_ora set $sql {SELECT '|' || p.name || '|' || p.value || '|' " FROM v$parameter p " WHERE p.name = 'spfile' " AND p.value IS NOT NULL; } var $SPFile_In_Use = grepSql($sql,'\|spfile\|','f') } if $SPFile_In_Use write 'SPFile appears to be in use on this server%BR%\ Review "V$Parameters" and "SPFile Parameters" links \ for parameter settings.' elsif ${B_PFILE_LOCAL/P} {if ?${F_PFILE_LOCATION/P} var $fil = replace(last,'\*',$ORACLE_SID) else {if or(isWindows(),isCygwin()) var $dir = catDir($ORACLE_HOME,'database') else var $dir = catDir($ORACLE_HOME,'dbs') var ($fil) = grepDir($dir,concat('^init',verbatim($ORACLE_SID),'\.ora$'),'p') } if $fil {var %treated = () prefix {write '---+!! INIT.ORA Information' write $TOC write '---+ Contents of INIT.ORA ',encode($fil) } if writeFile($fil) {write $TOP # Extract the IFILE, ignoring comments in the Oracle supplied INIT.ORA var $treated{$fil} = 1 while value(grepFile($fil,'^[^#]*ifile','fi')) {var $fil = trim(last) var $fil = replace($fil,"'",'',true) var $fil = replace($fil,'\?',$ORACLE_HOME) var $fil = replace($fil,'\$ORACLE_HOME',$ORACLE_HOME) var $fil = replace($fil,'\$\{ORACLE_HOME\}',$ORACLE_HOME) var $fil = replace($fil,'%ORACLE_HOME%',$ORACLE_HOME) break exists($treated{$fil}) write '---+ Contents of IFILE ',encode($fil) call writeFile($fil) write $TOP var $treated{$fil} = 1 } } else {unprefix write encode($fil),' is not readable or does not exist.%BR%\ File permissions are as follows:%BR%' call statFile('b',$fil) write '%BR%User: ',id(),'%BR%' } } else write 'INIT.ORA not located on this server.' } toc '2:[[',getFile(),'][rda_report][INIT.ORA]]' =for stopwords SPFile =head2 vspparameters - SPFile Parameters Gets C information. =cut if $SQL_ACCESS {debug ' Inside ASM module, processing V$SPParameter' debug ' SPFile_In_Use is ',$SPFile_In_Use report vspparameters if $SPFile_In_Use {write '---+!! SPFile Parameter Values' write '|*SID*|*Name*|*Value*|*Is Specified?*| *Ordinal*|*Update Comment*|' set $sql {SELECT '|' || " s.sid || '|' || " s.name || '|' || " NVL(s.value, ' ') || '|' || " s.isspecified || '| ' || " s.ordinal || '|' || " NVL(s.update_comment, ' ') || '|' " FROM v$spparameter s " ORDER BY s.name, s.sid; } call writeSql($sql) if getSqlMessage() write last,'%BR%' } else {write '---+!! SPFile Parameter Values' write 'This database instance is not using an spfile.' } if isCreated() toc '2:[[',getFile(),'][rda_report][SPFile Parameters]]' =head2 vparameters - V$Parameters Gets C information. =cut debug ' Inside ASM module, processing V$Parameter' report vparameters var $TTL = undef var @TTL = ('',\ '---+!! Automatic Storage Management Parameters') var @HDR = ('',\ '|*Parameter Name*|*Value*|*Default*|*Modified*|') set $sql {SELECT '|' || " SUBSTR(name, 0, 512) || '|' || " NVL(SUBSTR(value, 0, 512), '%NULL%') || '|' || " isdefault || '|' || " ismodified || '|' " FROM v$parameter " ORDER BY name; } call separator(1) call writeSql($sql) call separator(0,'V$Parameters') =head2 overview - Overview Extracts the ASM information from the database. =cut debug ' Inside ASM module, gathering overview information' report overview var $TTL = '---+!! Automatic Storage Management Overview' if $ADVANCED {var @TTL = ('',\ '---+ Disk Groups',\ '---+ Partner Information',\ '---+ Robust Disk Information',\ '---+ ASM Attribute Information') var @HDR = ('',\ '| *Grp*|*Name*|*State*|*Type*| *Total (MiB)*| *Free (MiB)*|',\ '| *Grp*| *Disk*| *number_kfdpartner*| *parity_kfdpartner*| \ *active_kfdpartner*|',\ '| *Group Number*| *Disk Number*| *Incarnation*|*Mount Status*|\ *Header Status*|*Mode Status*|*State*|*Library*| \ *Total (MiB)*| *Free (MiB)*|*Name*|*FailGroup*|*Label*|*Path*|\ *Create Date*|*Mount Date*| *Reads*| *Writes*| *Read Errs*| \ *Write Errs*|*Read Time*|*Write Time*| *Bytes Read*| \ *Bytes Written*|',\ '|*Diskgroup Name*|*Attribute Name*|*Value*|') set $sql {SELECT '| ' || " group_number || '|' || " name || '|' || " state || '|' || " type || '| ' || " total_mb || '| ' || " free_mb || '|' " FROM :1; "PROMPT ___Macro_separator(2)___ "SELECT '| ' || " grp || '| ' || " disk || '| ' || " number_kfdpartner || '| ' || " parity_kfdpartner || '| ' || " active_kfdpartner || '|' " FROM x$kfdpartner; "PROMPT ___Macro_separator(3)___ "SELECT '[[[' || CHR(10) || '| ' || " group_number || '| ' || " disk_number || '| ' || " incarnation || '|' || " mount_status || ' |' || " header_status || ' |' || " mode_status || ' |' || " state || ' |' || " library || ' | ' || " total_mb || '| ' || " free_mb || '| ' || " name || '| ' || " failgroup || ' |' || " label || ' |' || " path || ' |' || " TO_CHAR(create_date,'DD-Mon-YYYY') || ' |' || " TO_CHAR(mount_date,'DD-Mon-YYYY') || ' | ' || " reads || '| ' || " writes || '| ' || " read_errs || '| ' || " write_errs || '| ' || " read_time || ' | ' || " write_time || '| ' || " bytes_read || '| ' || " bytes_written || '|' || " CHR(10) || ']]]' " FROM v$asm_disk; } var (undef,$col) = getSqlColumns('RDA','','V$ASM_ATTRIBUTE') call clearSqlColumns('RDA') if $col {append $sql {PROMPT ___Macro_separator(4)___ "SELECT '|' || " g.name || ' |' || " a.name || ' |' || " a.value || ' |' " FROM :1 g, " v$asm_attribute a " WHERE g.group_number=a.group_number " ORDER BY g.name, a.name; } } call separator(1) call writeSql(bindSql($sql,$DG_TBL),2) call separator(0,'Overview') if $ALLOCATION {# Creating separate data files for the long-running queries. prefix write '---+ Allocation Information' suspend overview output D,kfdat prefix {write '---+ Allocation Information (Disk)' write '| *group_kfdat*| *number_kfdat*| *aunum_kfdat*| *v_kfdat*| \ *fnum_kfdat*| *i_kfdat*| *xnum_kfdat*|*raw_kfdat*|' } set $sql {SELECT '| ' || " group_kfdat || '| ' || " number_kfdat || '| ' || " aunum_kfdat || '| ' || " v_kfdat || '| ' || " fnum_kfdat || '| ' || " i_kfdat || '| ' || " xnum_kfdat || '|' || " raw_kfdat || '|' " FROM x$kfdat; } call writeSql($sql,2) if isCreated() {var $url = getHtmlLink(true) resume overview write '|*Disk*|',concat('[[',$url,'][_blank][x$kfdat]]'),'|' suspend overview } output D,kffxp prefix {write '---+ Allocation Information (ASM File)' write '| *Grp*| *Num*|*Incarn*|*pxn_kffxp*| *xnum_kffxp*| *Lxn*| *Disk*| \ *au_kffxp*| *Flg*| *Chk*|' } set $sql {SELECT '| ' || " group_kffxp || '| ' || " number_kffxp || '|' || " incarn_kffxp || '|' || " pxn_kffxp || '| ' || " xnum_kffxp || '| ' || " lxn_kffxp || '| ' || " disk_kffxp || '|' || " au_kffxp || '| ' || " flags_kffxp || '| ' || " chk_kffxp || '|' " FROM x$kffxp; } call writeSql($sql,2) if isCreated() {var $url = getHtmlLink(true) resume overview write '|*ASM File*|',concat('[[',$url,'][_blank][x$kffxp]]'),'|' } else resume overview if hasOutput(true) write $TOP } } else {var @TTL = ('',\ '---+ Disk Group Information ',\ '---+ Disk Information',\ '---+ ASM Attribute Information') var @HDR = ('',\ '| *Grp*|*Name*|*State*|*Type*| *Total (MiB)*| *Free (MiB)*|',\ '| *Group Number*| *Disk Number*|*Name*|*Mount Status*|\ *Header Status*|*Mode Status*|*State*|*Redundancy*|\ *Failgroup*|*Path*| *Total (MiB)*| *Free (MiB)*|',\ '|*Diskgroup Name*|*Attribute Name*|*Value*|') set $sql {SELECT '| ' || " group_number || '|' || " name || '|' || " state || '|' || " type || '| ' || " total_mb || '| ' || " free_mb || '|' " FROM :1; "PROMPT ___Macro_separator(2)___ "SELECT '[[[' || CHR(10) || '| ' || " group_number || '| ' || " disk_number || '| ' || " name || '| ' || " mount_status || ' |' || " header_status || ' |' || " mode_status || ' |' || " state || ' |' || " redundancy || ' |' || " failgroup || ' |' || " path || ' |' || " total_mb || ' | ' || " free_mb || '| ' || " CHR(10) || ']]]' " FROM v$asm_disk " ORDER BY group_number,disk_number; } var (undef,$col) = getSqlColumns('RDA','','V$ASM_ATTRIBUTE') call clearSqlColumns('RDA') if $col {append $sql {PROMPT ___Macro_separator(3)___ "SELECT '|' || " g.name || ' |' || " a.name || ' |' || " a.value || ' |' " FROM :1 g, " v$asm_attribute a " WHERE g.group_number=a.group_number " ORDER BY g.name, a.name; } } call separator(1) call writeSql(bindSql($sql,$DG_TBL),2) call separator(0,'Overview') } =head2 storage_info - Storage Information Gathers the ASM storage information. =cut debug ' Inside ASM module, gathering storage information' report storage_info var $TTL = '---+!! Storage Information' var @TTL = ('',\ '---+ List of DB clients connected to ASM instance',\ '---+ List of templates',\ '---+ V$ASM_ALIAS Information',\ concat('---+ ',uc($DG_TBL),' Information'),\ '---+ V$ASM_FILE Information',\ '---+ V$ASM_OPERATION Information') var ($HDR[1],$col1) = getSqlColumns('RDA','','V$ASM_CLIENT') call clearSqlColumns('RDA') var ($HDR[2],$col2) = getSqlColumns('RDA','','V$ASM_TEMPLATE') call clearSqlColumns('RDA') if $ADVANCED {var ($HDR[3],$col3) = getSqlColumns('RDA','','V$ASM_ALIAS') call clearSqlColumns('RDA') var ($HDR[4],$col4) = getSqlColumns('RDA','',$DG_TBL) call clearSqlColumns('RDA') var $HDR[4] = replace($HDR[4],'\sMb\*\|',' (MiB)*|',true) var ($HDR[5],$col5) = getSqlColumns('RDA','','V$ASM_FILE') call clearSqlColumns('RDA') var ($HDR[6],$col6) = getSqlColumns('RDA','','V$ASM_OPERATION') call clearSqlColumns('RDA') } if and($col6,$col5,$col4,$col3,$col2,$col1) {set $sql {SELECT :3 " FROM v$asm_alias; "PROMPT ___Macro_separator(1)___ "SELECT :1 " FROM v$asm_client; "PROMPT ___Macro_separator(4)___ "SELECT :4 " FROM :7; "PROMPT ___Macro_separator(5)___ "SELECT :5 " FROM v$asm_file; "PROMPT ___Macro_separator(6)___ "SELECT :6 " FROM v$asm_operation; "PROMPT ___Macro_separator(2)___ "SELECT :2 " FROM v$asm_template; } call separator(3) call writeSql(bindSql($sql,$col1,$col2,$col3,$col4,$col5,$col6,$DG_TBL),2) call separator(0,'Storage Information') } elsif and($col2,$col1) {set $sql {SELECT :1 " FROM v$asm_client; "PROMPT ___Macro_separator(2)___ "SELECT :2 " FROM v$asm_template; } call separator(1) call writeSql(bindSql($sql,$col1,$col2),2) call separator(0,'Storage Information') } =head2 space_info - File/Space Related Information Gathers the file/space-related information. =cut debug ' Inside ASM module, gathering file/space related information' report space_info var $TTL = '---+!! File/Space Related Information' if $ADVANCED {var @TTL = ('',\ '---+ Files Stored in Diskgroup',\ '---+ Number of Allocation Units per Disk Group',\ '---+ Number of Allocation Units per Diskgroup,Disk',\ '---+ Number of Allocated (V) and Free (F) Allocation Units',\ '---+ Number of AUs per ASM file ordered by AU : Metadata Only',\ '---+ Number of AUs per ASM file ordered by AU : Non Metadata',\ '---+ File Utilization') var @HDR = ('',\ '| *Group Number*| *File Number*|*Full Alias Path*|*File Type*|',\ '| *AU Count*| *DG#*|',\ '| *AU Count*|*Group#,Diskno*|',\ '| *Group#*| *Disk#*|*VF*| *Count*|',\ '| *AU Count*| *File#*| *DG#*|',\ '| *Group Kffxp*| *Number Kffxp*|*Name*| *Count*|',\ '| *Group No*| *File No*| *Bytes*| *Space*| *Space (MiB)*|\ *Name*|') set $sql {SELECT '| ' || " x.gnum || '| ' || " x.filnum || '|' || " x.full_alias_path || ' |' || " f.ftype || ' |' " FROM (SELECT gnum, " filnum, " CONCAT('+'||gname, sys_connect_by_path(aname, '/')) " full_alias_path " FROM (SELECT g.name gname, " a.parent_index pindex, " a.name aname, " a.reference_index rindex, " a.group_number gnum, " a.file_number filnum " FROM v$asm_alias a, " :1 g " WHERE a.group_number = g.group_number) " START WITH (MOD(pindex, POWER(2, 24))) = 0 " CONNECT BY PRIOR rindex = pindex) x, " (SELECT group_number gnum, " file_number filnum, " type ftype " FROM v$asm_file " ORDER BY group_number,file_number) f " WHERE x.filnum != 4294967295 " AND x.gnum=f.gnum " AND x.filnum=f.filnum; "PROMPT ___Macro_separator(2)___ "SELECT '| ' || " COUNT(number_kfdat) || '| ' || " group_kfdat || '|' " FROM x$kfdat " GROUP BY group_kfdat; "PROMPT ___Macro_separator(3)___ "SELECT '| ' || " COUNT(*) || '|' || " group_kfdat||','||number_kfdat || ' |' " FROM x$kfdat " GROUP BY group_kfdat,number_kfdat; "PROMPT ___Macro_separator(4)___ "SELECT '| ' || " group_kfdat || '| ' || " number_kfdat || '|' || " v_kfdat || ' | ' || " COUNT(*) || '|' " FROM x$kfdat " GROUP BY group_kfdat, number_kfdat, v_kfdat; "PROMPT ___Macro_separator(5)___ "SELECT '| ' || " COUNT(xnum_kffxp) || '| ' || " number_kffxp || '| ' || " group_kffxp || '|' " FROM x$kffxp WHERE number_kffxp < 256 " GROUP BY number_kffxp, group_kffxp " ORDER BY COUNT(xnum_kffxp); "PROMPT ___Macro_separator(6)___ "SELECT '| ' || " group_kffxp || '| ' || " number_kffxp || '|' || " name || ' | ' || " COUNT(*) || '|' " FROM x$kffxp, v$asm_alias " WHERE group_kffxp = group_number " AND number_kffxp = file_number " AND system_created = 'Y' " GROUP BY group_kffxp, number_kffxp, name " ORDER BY group_kffxp, number_kffxp; "PROMPT ___Macro_separator(7)___ "SELECT '| ' || " f.group_number || '| ' || " f.file_number || '| ' || " bytes || '| ' || " space || '| ' || " space/1048576 || '|' || " a.name || ' |' " FROM v$asm_file f, v$asm_alias a " WHERE f.group_number = a.group_number " AND f.file_number = a.file_number " AND system_created = 'N' " ORDER BY f.group_number, f.file_number; } } else {var @TTL = ('',\ '---+ File Utilization',\ '---+ File utilization but using the Alias names.',\ '---+ Files stored in Diskgroup') var @HDR = ('',\ '| *Group No*| *File No*| *Bytes*| *Space*| *Space (MiB)*|\ *Name*|',\ '| *Group No*| *File No*| *Bytes*| *Space*| *Space (MiB)*|\ *Name*|',\ '| *Group No*| *File No*|*Full Alias Path*|') set $sql {SELECT '| ' || " f.group_number || '| ' || " f.file_number || '| ' || " bytes || '| ' || " space || '| ' || " space/1048576 || '|' || " a.name || ' |' " FROM v$asm_file f,v$asm_alias a " WHERE f.group_number = a.group_number " AND f.file_number = a.file_number " AND system_created = 'Y' " ORDER BY f.group_number,f.file_number; "PROMPT ___Macro_separator(2)___ "SELECT '| ' || " f.group_number || '| ' || " f.file_number || '| ' || " bytes || '| ' || " space || '| ' || " space/1048576 || '|' || " a.name || ' |' " FROM v$asm_file f,v$asm_alias a " WHERE f.group_number = a.group_number " AND f.file_number = a.file_number " AND system_created = 'N' " ORDER BY f.group_number,f.file_number; "PROMPT ___Macro_separator(3)___ "SELECT '| ' || " gnum || '|' || " filnum || ' |' || " concat('+'||gname,sys_connect_by_path(aname, '/')) || '| ' " FROM (SELECT g.name gname, a.parent_index pindex, " a.name aname, a.reference_index rindex, " a.group_number gnum,a.file_number filnum " FROM v$asm_alias a,:1 g " WHERE a.group_number = g.group_number) " START WITH (mod(pindex, power(2, 24))) = 0 " CONNECT BY PRIOR rindex = pindex; } } call separator(1) call writeSql(bindSql($sql,$DG_TBL),2) call separator(0,'File/Space Related Information') } =head2 lspv - Physical Volume Information For AIX, it gets physical volume information. =cut if match($OSN,'aix') {var $cmd = '/usr/sbin/lspv' debug ' Inside ASM module, getting physical volume information' report lspv prefix {write '---+!! Physical Volume Information' write '---## Using: ',encode($cmd) } call writeCommand($cmd) if isCreated(true) toc '2:[[',getFile(),'][rda_report][Physical Volume Information]]' } =head2 ASMLIB =head3 rpm_info - ASM Library Information For Linux, it gets related package manager information. =cut elsif match($OSN,'linux') {pretoc '2:ASMLIB' debug ' Inside ASM module, getting ASM library information' report rpm_info prefix {write '---+!! ASM Library Information' write '---## Using: rpm -qa | grep oracleasm' write '' } loop $lin (grepCommand('rpm -qa','oracleasm')) write $lin if isCreated(true) {write '' toc '3:[[',getFile(),'][rda_report][ASM Library Information]]' } =for stopwords fs oracleasm proc =head3 asmlog_mask - /proc/fs/oracleasm/log_mask Contents For Linux, it collects the F file. =cut debug ' Inside ASM module, collecting /proc/fs/oracleasm/log_mask file' report asmlog_mask var $fil = '/proc/fs/oracleasm/log_mask' prefix write '---+!! Contents of /proc/fs/oracleasm/log_mask' call writeFile($fil) if isCreated(true) toc '4:[[',getFile(),'][rda_report][/proc/fs/oracleasm/log_mask Contents]]' =head3 asm_log - /var/log/oracleasm Contents For Linux, it collects the F file. =cut debug ' Inside ASM module, collecting /var/log/oracleasm file' report asm_log var $fil = '/var/log/oracleasm' prefix write '---+!! Contents of /var/log/oracleasm' call writeFile($fil) if isCreated(true) toc '4:[[',getFile(),'][rda_report][/var/log/oracleasm Contents]]' =head3 asmlib_config - ASM Library Configuration For Linux, it collects the F file. =cut debug ' Inside ASM module, collecting /etc/sysconfig/oracleasm file' report asmlib_config var $fil = '/etc/sysconfig/oracleasm' prefix {write '---+!! ASM Library Configuration' write '---## From ',encode($fil) } call writeFile($fil) if isCreated(true) toc '3:[[',getFile(),'][rda_report][ASM Library Configuration]]' =head3 asmlib_conlist - ASM Library Configuration List For Linux, it collects the list of F files. =cut debug ' Inside ASM module, collecting /etc/sysconfig/oracleasm* list' report asmlib_conlist var $dir = '/etc/sysconfig' prefix write '---+!! ASM Library Configuration List' call statFile('b',grepDir($dir,'^oracleasm','np')) if isCreated(true) toc '3:[[',getFile(),'][rda_report][ASM Library Configuration List]]' =head3 asmlib_discovery - ASM Library Discovery Information For Linux, it collects ASM library discovery information. =cut debug ' Inside ASM module, collecting ASM library discovery information' report asmlib_discovery var $cmd = "/usr/sbin/oracleasm-discover 'ORCL:*'" prefix {write '---+!! ASM Library Discovery Information' write '---## Using ',encode($cmd) } call writeCommand($cmd) if isCreated(true) toc '3:[[',getFile(),'][rda_report][ASM Library Discovery Information]]' =head3 asmlib_disks - ASM Library Disk Information For Linux, it gets ASM library disk information. =cut debug ' Inside ASM module, getting ASM library disk information' report asmlib_disks var $cmd = '/bin/ls -l /dev/oracleasm/disks' prefix {write '---+!! ASM Library Disk Information' write $TOC write '---+ List of ASM Devices' write '---## Using: ',encode($cmd) } call writeCommand($cmd) if hasOutput(true) write $TOP var $cmd = '/sbin/blkid' prefix {write '---+ Devices Used With ASMLIB' write '---## Using: ',encode($cmd),' | grep oracleasm' call beginBlock(true) } loop $lin (grepCommand($cmd,'oracleasm')) write $lin if hasOutput(true) {call endBlock(['C',concat($cmd,' | grep oracleasm')]) write $TOP } var $cmd = '/etc/init.d/oracleasm listdisks' if loadCommand($cmd) {prefix {write '---+ List of ASM Disks' write '---## Using: ',encode($cmd) } call writeLastFile() if hasOutput(true) write $TOP loop $dsk (grepLastFile('.')) {var $cmd = concat('/etc/init.d/oracleasm querydisk ',quote($dsk)) prefix {write '---+ Disk Information for ',$dsk write '---## Using: ',encode($cmd) } call writeCommand($cmd) if hasOutput(true) write $TOP } } if isCreated(true) toc '3:[[',getFile(),'][rda_report][ASM Library Disk Information]]' unpretoc =head2 partitions - Disk Partitions For Linux, it gets the disk partition information used to identify the physical devices with the ASM disk. =cut debug ' Inside ASM module, getting disk partitions information' report partitions var $fil = '/proc/partitions' prefix {write '---+!! Disk Partition Information' write '---## From ',encode($fil) } call writeFile($fil) if isCreated(true) toc '2:[[',getFile(),'][rda_report][Disk Partitions]]' =for stopwords Udev udev =head2 udev - Udev Settings For Linux, it gets the udev settings information. It excludes some rules files. =cut debug ' Inside ASM module, getting udev settings information' report udev var $dir = '/etc/udev/rules.d' pretoc '2:Udev Settings' prefix {write '---+!! Udev Settings Information' write '---## From ',encode($dir) } call sort_files(3,0,grepDir($dir,'((alsa|bluetooth|fuse|kexec|libsane|net|\ pam\-console|pcmcia|pcscd_ccid|wacom)\.rules|fuse\.rules\.rpmnew)$','pv')) unpretoc } =head2 vis_disks - ASM Visible Disks Lists the ASM visible disks. =cut debug ' Inside ASM module, getting ASM visible disks' var $cmd = concat(catCommand($ORACLE_HOME,'bin','kfod'),\ ' disks=all status=true 2>/dev/null') report vis_disks prefix {write '---+!! ASM Visible Disks' write '---## Using: ',encode($cmd) } call writeCommand($cmd) if isCreated(true) toc '2:[[',getFile(),'][rda_report][ASM Visible Disks]]' =head2 dev_list - Device List Lists the devices from the F directory. =cut debug ' Inside ASM module, getting device information' report dev_list macro stat_dev {var ($dir) = @arg import $TOP call statDir('an',$dir) write $TOP loop $pth (findDir($dir,'^\.+$','npv')) {next ?testFile('l',$pth) call stat_dev($pth) } } var $dir = '/dev' prefix write '---+!! Listing of Devices from ',encode($dir) if ?testFile('dr',$dir) call stat_dev($dir) if isCreated(true) toc '2:[[',getFile(),'][rda_report][Device List]]' =head2 dev_header - ASM Devices Header Information Collects the ASM devices header information. =cut if $DEVICES {var ($pat0,$pat1,%dev,%fil) = (\ '^(\.+|agp|arp|audio|audit|bd\.off|bmc|bus|cd|ce|clone|conslog|console|\ control|core|cua|diskette|dmp|dri|dsp|dssa|dump|dvd|echo|ecp|envctrl|\ eri|error|event|fb|fd|full|ge|gxme|hdlc|hme|hpet|icmp|inet_cots|\ infiniband|input|ip|ipldevice|isa|iscsi|kb|key|kstat|ksyms|lan|le|lft|\ llc|lofictl|log|loop|lp|MAKEDEV|md|mem|mice|mixer|mouse|nca|net|nrst|nul|\ openprom|paging|par0|pci|pm|poll|port|ppp|print|ptc|ptmajor|ptmx|pts|pty|\ qe|qfe|ram|random|rawctl|rawip|rcd|rcm|refresh|rmt|root|rtape|rtc|rts|\ sad|sctp|sdp|sequencer|sg|slog|snap|snd|spx|ssa|stcpmap|stderr|stdin|\ stdout|strlog|swap|SWAP|syscon|systrace|systrctl|tape|tcp|telnetm|term|\ tic.?ts|tlclts|tlcots|tnf|tod|tty|tu|udp|unixdg|unixst|usb|vbi|vcs|video|\ volctl|vx|watchdog|winlock|wrsmd|wscons|X0R|zero)',\ '^(\.+|agp|arp|audio|audit|bd\.off|bmc|bus|cd|clone|conslog|console|control|\ core|cua|diskette|dmp|dri|dsp|dssa|dump|dvd|echo|ecp|envctrl|error|event|\ fd|full|gxme|hdlc|hpet|icmp|inet_cots|infiniband|input|ipldevice|isa|\ iscsi|key|kstat|ksyms|lan|lft|llc|lofictl|loop|MAKEDEV|md|mem|mice|mixer|\ mouse|net|nrst|openprom|paging|par0|poll|port|ppp|print|ptmajor|ptmx|pts|\ ram|random|rawctl|rawip|refresh|root|rtape|rtc|sctp|sdp|sequencer|sg|\ snap|snd|stcpmap|stderr|stdin|stdout|strlog|swap|SWAP|syscon|systrace|\ systrctl|tape|tcp|telnetm|term|tic.?ts|tlclts|tlcots|tnf|tty|tu|udp|\ unixdg|unixst|usb|vbi|vcs|video|volctl|watchdog|winlock|wrsmd|wscons|X0R|\ zero)') # Get the devices macro get_devices {var (\%dev,$dir,$pat,$nxt) = @arg # Analyze the directory loop $fil (grepDir($dir,$pat,'nv')) {var $pth = catFile($dir,$fil) if ?testDir('d',$pth) var $sub{$pth} = true else var $dev{$pth} = true } # Treat the subdirectories loop $sub (keys(%sub)) call get_devices(\%dev,$sub,$nxt,$nxt) } call get_devices(\%dev,$dir,$pat0,$pat1) # Collect ASM header properties if ?testFile('x',catFile($ORACLE_HOME,'bin','kfed')) {debug ' Inside ASM module, getting devices header information' report dev_header prefix {write '---+ Display of ASM Devices Header Information' write '|*Device*|*Header Information*|' } loop $fil (keys(%dev)) {if loadCommand(concat(lastCommand(),' read ',$fil,' 2>&1'),true,1) {next !grepLastFile('kfbh\.type','f') next match(last,'KFBTYP_INVALID|Unknown\s*Enum') next $fil{$fil} if grepLastFile('ausize|blksize|driver\.provstr|dskname|dsknum|dsksize|\ fgname|grpname|grptyp|hdrsts') {var @dev = last var $fil{$fil} = replace(join("\001",@dev),'\s+','',true) var @tbl = () loop $dev (@dev) {var ($nam,$val,$off,$det) = split('\s*[:;]\s*',$dev,4) call push(@tbl,concat($nam,' %NEXT% ',$val,'%NEXT% ',$off,'%NEXT%',$det)) } write '|',encode($fil),\ ' |%TBL%%ID:name:value:offset:detail%',join('%BR%',@tbl),'%ENDTBL%|' } } } if hasOutput(true) {write $TOP toc '2:[[',getFile(),'][rda_report][ASM Devices Header Information]]' } =head2 dev_duplicates - Potential Duplicate Devices Collects the potential duplicate devices information. =cut # Collect ASMLIB devices information debug ' Inside ASM module, getting duplicate devices information' report dev_duplicates prefix write '---+ Display of Potential Duplicate Devices' var @fil = keys(%fil) var $cnt = @fil decr $cnt for $off1 (0,$cnt,1) {var $lin1 = $fil{$fil[$off1]} for $off2 ($off1,$cnt,1) {next expr('==',$off1,$off2) var $lin2 = $fil{$fil[$off2]} if compare('eq',$lin1,$lin2) {if match($fil[$off1],'oracleasm',true) write '|``',encode($fil[$off1]),\ ' is the ASMLIB device corresponding to ',\ encode($fil[$off2]),'``|' elsif match($fil[$off2],'oracleasm',true) write '|``',encode($fil[$off2]),\ ' is the ASMLIB device corresponding to ',\ encode($fil[$off1]),'``|' else write '|``',encode($fil[$off1]),' is a duplicate of ',\ encode($fil[$off2]),'``|' } } } if hasOutput(true) {write $TOP toc '2:[[',getFile(),'][rda_report][Potential Duplicate Devices]]' } } } # Get the dump destinations call find_dest() var $BDUMP_DIR = get_bdump() var $CDUMP_DIR = get_cdump() var $UDUMP_DIR = get_udump() var $ADR_BASE = get_adr_base() var $ADR_HOME = get_adr_home() var $ALERT_TAIL = ${N_ALERT_TAIL:30000} var $TRACE_DIR = cond($ADR_HOME,catDir($ADR_HOME,'trace'),$BDUMP_DIR) # Define a macro to estimate the size after compression macro get_size {var ($fil) = @arg import $LOG_RATIO,$LOG_TRESHOLD keep $LOG_RATIO,$LOG_TRESHOLD var $siz = getSize($fil) if expr('>',$siz,$LOG_TRESHOLD) var $siz = expr('/',$siz,$LOG_RATIO) return $siz } =head2 alert_log - Alert Log Gathers the alert log information. =head2 alert_sum - Alert.log Analysis When requested, RDA analyzes the lines extracted from the alert log and produces a summary. =cut var @err = () if and($ADR_HOME,not($ALERT_TEXT)) {debug ' Inside ASM module, found diagdir ',$ADR_HOME,', get log info' var $fil = catFile($ADR_HOME,'alert','log.xml') if createBuffer('ALR','R',$fil) {# Parse the alert log for errors and last startup macro push_err {var (\@err,$lin,$max) = @arg if expr('<',scalar(@err),$max) call push(@err,$lin) else var (undef,@err) = (@err,$lin) return -1 } var $lst = undef call parseReset() call parsePattern('TOP',\ '^',$lst,$min) var $lst = undef } if $lst {var $cnt = expr('-',$max,$lst) incr $cnt call setPos('ALR',$pos) } else {call setPos('ALR') while getLine('ALR',$min) {var $lin = chomp(last) break match($lin,'^',$out,' 2>',$err)) pretoc '2:Diagnostic Repository' report diag_problems if ?testFile('z',$out) {echo 'Error encountered with ADRCI' write '** Error encountered with ADRCI **' write call writeFile($err) } elsif createBuffer('ADR','R',$out) {var ($cnt,$min,$cut,$src,$hdr) = (0,0,true) prefix {write '---+ List of Diagnostic Problems' write '---## Using: SHOW PROBLEM -ALL -ORDERBY LASTINC_TIME DSC' if $src write '---## From: ',replace(encode($src),'\s',' ',true) if $hdr write $hdr } while getLine('ADR') {var $lin = chomp(last) if match($lin,'^ADR Home\s+=\s*(.*):$') var ($cut,$row,$src) = (false,false,last) elsif match($lin,'^DIA\-(\d+):') {if $src write '**',$lin,'**' break } elsif $cut next elsif match($lin,'^\d+\s+rows\s+fetched$') {if !isCreated() {var $hdr = undef write '**No problems found**' } break } elsif $row {next expr('<',length($lin),$min) var @tbl = () for $pos (0,$cnt) var $tbl[$pos] = trim(substr($lin,$tb_off[$pos],$tb_lgt[$pos])) if @tbl write '|',join(' |',@tbl),' |' } elsif match($lin,'^[\-\s]+$') var $row = true elsif match($lin,'^\w+\s+') {var ($min,@tb_key,@tb_lgt,@tb_off) = (0) var %tbl = ('PROBLEM_ID','Problem ID',\ 'PROBLEM_KEY','Problem Key',\ 'LAST_INCIDENT','Last Incident',\ 'LASTINC_TIME','Last Incident Time') var $lin = trim($lin) while match($lin,'^(\w+\s+)') {var ($key) = last var $lgt = length($key) var $key = trim($key) var $tb_key[$cnt] = nvl($tbl{$key},$key) var $tb_off[$cnt] = $min var $tb_lgt[$cnt] = $lgt var $lin = substr($lin,$lgt) incr $min,$lgt incr $cnt } var $tb_key[$cnt] = nvl($tbl{$lin},$lin) var $tb_off[$cnt] = $min if $cnt var $hdr = concat('|*',join('*|*',@tb_key),'*|') } } call deleteBuffer('ADR') } call unlinkTemp('job') call unlinkTemp('out') call unlinkTemp('err') if isCreated(true) toc '3:[[',getFile(),'][rda_report][Problem Overview]]' =head3 diag_incidents - Most Recent Incidents Gathers diagnostic incidents. An incident is a single occurrence of a problem. When a problem (critical error) occurs repeatedly, an incident is created for each occurrence. Incidents are time stamped and tracked in the Automatic Diagnostic Repository. By default, RDA collects the last 10 incidents. It requires the availability of the ADRCI utility. =cut var $MAX = ${N_INCIDENTS:10} var $max = $MAX if $max {var ($cut,@inc,%lnk) = (true) # Get the incident list var $job = createTemp('job') var $out = getTemp('out') call writeTemp('job','SET BASE ',$ADR_BASE) call writeTemp('job','SET HOMEPATH ',$hom) call writeTemp('job','QUERY (INCIDENT_ID) INCIDENT -ORDERBY CREATE_TIME DSC') call writeTemp('job','EXIT') call closeTemp('job') call command(concat($cmd,' script=',$job,' >',$out)) if createBuffer('ADR','R',$out) {while getLine('ADR') {var $lin = chomp(last) if match($lin,'^-+\s*$') var $cut = false elsif $cut next elsif match($lin,'^(\d+)\s*$') call push(@inc,last) elsif match($lin,'^\d+\s+rows\s+fetched$') break } call deleteBuffer('ADR') } # Get the incident details loop $inc (@inc) {var $job = createTemp('job') var $out = getTemp('out') call writeTemp('job','SET BASE ',$ADR_BASE) call writeTemp('job','SET HOMEPATH ',$hom) call writeTemp('job','SHOW INCIDENT -MODE DETAIL -P "INCIDENT_ID=',$inc,'"') call writeTemp('job','EXIT') call closeTemp('job') call command(concat($cmd,' script=',$job,' >',$out)) if createBuffer('ADR','R',$out) {report concat('incident_',$inc) var ($cut,$src) = (true) prefix {write '---+ Display of Incident ',$inc write '---## Using: SHOW INCIDENT -MODE DETAIL -P "INCIDENT_ID=',$inc,'"' if $src write '---## From: ',replace(encode($src),'\s',' ',true) write '|*Name*|*Value*|' } while getLine('ADR') {var $lin = chomp(last) if match($lin,'^ADR Home\s+=\s*(.*):$') var ($cut,$src) = (false,last) elsif $cut next elsif match($lin,'^\s+\w+\s') {var (undef,$nam,$val) = split('\s+',$lin,3) write '|',$nam,' |',$val,' |' } elsif match($lin,'^\d+\s+rows\s+fetched$') break } if isCreated(true) {write $TOP var $lnk{$inc} = getHtmlLink(true) } call deleteBuffer('ADR') } call unlinkTemp('job') call unlinkTemp('out') # Limit the incident number decr $max break !$max } report diag_incidents prefix {write '---+ Display of Last ',$MAX,' Incidents' write '| *Incident ID*|' } loop $inc (@inc) {if exists($lnk{$inc}) write '| [[',$lnk{$inc},'][_blank][',$inc,']]|' } if isCreated(true) toc '3:[[',getFile(),'][rda_report][Most Recent Incidents]]' } unpretoc } =head2 log_trace - Trace/Log Directory Listings Lists the contents of the trace/dump directories. =cut debug ' Inside ASM module, doing list of Oracle trace/log directories' report log_trace write '---+!!Listing of Files from Oracle Log/Trace Directories' write $TOC if $ADR_HOME {write '---+ Diagnostic Traces' if !statDir('at',catDir($ADR_HOME,'trace')) write 'Could not list files in ',encode(lastDir()),'%BR%' write $TOP write '---+ Incidents' if !statDir('at',catDir($ADR_HOME,'incident')) write 'Could not list files in ',encode(lastDir()),'%BR%' write $TOP write '---+ Incident Packages' if !statDir('at',catDir($ADR_HOME,'incpkg')) write 'Could not list files in ',encode(lastDir()),'%BR%' write $TOP write '---+ Core Dumps' if !statDir('at',catDir($ADR_HOME,'cdump')) write 'Could not list files in ',encode(lastDir()),'%BR%' write $TOP if match(getOsName(),'solaris') {run OS:COREinfo() call run_coreadm((concat('_',$ORACLE_SID,'\b'))) } } write '---+ Background Dump Destination' if !$BDUMP_DIR write 'Background Dump destination could not be determined.%BR%' elsif !statDir('at',$BDUMP_DIR) write 'Could not list files in ',encode($BDUMP_DIR),'%BR%' write $TOP var $dir = catDir($ORACLE_HOME,'rdbms','log') if compare('ne',$BDUMP_DIR,$dir) {write '---+ Default Background Dump Destination.%BR%' if !statDir('at',$dir) write 'Could not list files in ',encode($dir),'%BR%' write $TOP } write '---+ Core Dump Destination' if !$CDUMP_DIR write 'Core Dump destination could not be determined.%BR%' elsif !statDir('at',$CDUMP_DIR) write 'Could not list files in ',encode($CDUMP_DIR),'%BR%' write $TOP var $dir = catDir($ORACLE_HOME,'dbs') if compare('ne',$CDUMP_DIR,$dir) {write '---+ Default Core Dump Destination' if !statDir('at',$dir) write 'Could not list files in ',encode($dir),'%BR%' write $TOP if match(getOsName(),'solaris') {run OS:COREinfo() call run_coreadm((concat('_',$ORACLE_SID,'\b'))) } } write '---+ User Dump Destination' if !$UDUMP_DIR write 'User Dump destination could not be determined.%BR%' elsif compare('eq',$UDUMP_DIR,$BDUMP_DIR) write 'User Dump destination and Background Dump destination are the same.\ %BR%See Background Dump destination for listing.%BR%' elsif !statDir('at',$UDUMP_DIR) write 'Could not list files in ',encode($UDUMP_DIR),'%BR%' write $TOP var $dir = catDir($ORACLE_HOME,'rdbms','trace') write '---+ RDBMS Trace Destination' if !statDir('at',$dir) write 'Could not list files in ',encode($dir),'%BR%' write $TOP toc '2:[[',getFile(),'][rda_report][Trace/Log Directory Listings]]' =head2 Most recent trace files Collects the most recent trace files for each type of background process. Older files are not considered. When requested, RDA can collect the most recent user dumps. =cut var @tbl = () if and($UDUMP_DIR,$UDUMP_AGE) var @tbl = grepDir($UDUMP_DIR,concat('^',verbatim($ORACLE_SID),'_.*\.trc$'),\ concat('iptm',$UDUMP_AGE)) if and($TRACE_DIR,$BDUMP_MAX) {var %ref = () loop $fil (grepDir($TRACE_DIR,\ concat('^',verbatim($ORACLE_SID),'_[^_\.]+_.*\.trc$'),'it')) {var $typ = field('_',1,$fil) var $fil = catFile($TRACE_DIR,$fil) next !isNewer($fil,$LOG_AGE) incr $ref{$typ} next expr('>',$ref{$typ},$BDUMP_MAX) call push(@tbl,$fil) } } call sort_files(3,0,@tbl) =head2 asmcmd - ASM Command Line Utility Collects information using F utility. This report applies to Oracle Database 11g Release 2 or later. =cut var $cmd = catFile($ORACLE_HOME,'bin','asmcmd') if grepCommand(concat($cmd,' -V 2>/dev/null'),'11.2','f') {debug ' Inside ASM module, getting information from asmcmd' report asmcmd macro dsp_title {var ($ttl,$cmd) = @arg if !isCreated() {write '---+!! ASM Command Line Utility Information' import $TOC write $TOC } write '---+ ',$ttl write '---## Using: ',$cmd } prefix call dsp_title('ASM SPFILE Location from Grid Plug and Play (GPnP) Profile',\ 'asmcmd spget') call writeCommand(concat($cmd,' spget 2>/dev/null')) if hasOutput(true) write $TOP prefix call dsp_title('Discovery Diskstring Value','asmcmd dsget') call writeCommand(concat($cmd,' dsget 2>/dev/null')) if hasOutput(true) write $TOP prefix call dsp_title('Open Files of Local Clients','asmcmd lsof') call writeCommand(concat($cmd,' lsof 2>/dev/null')) if hasOutput(true) write $TOP prefix call dsp_title('ASM Users in a Disk Group','asmcmd lsusr') call writeCommand(concat($cmd,' lsusr 2>/dev/null')) if hasOutput(true) write $TOP prefix call dsp_title('ASM User Groups','asmcmd lsgrp') call writeCommand(concat($cmd,' lsgrp 2>/dev/null')) if hasOutput(true) write $TOP prefix call dsp_title('Current Operations on a Disk Group or ASM Instance',\ 'asmcmd lsop') call writeCommand(concat($cmd,' lsop 2>/dev/null')) if hasOutput(true) write $TOP prefix call dsp_title('ASM Dynamic Volume Manager (ADVM) Volumes',\ 'asmcmd volinfo -a') call writeCommand(concat($cmd,' volinfo -a 2>/dev/null')) if hasOutput(true) write $TOP prefix call dsp_title('I/O Statistics for ASM Dynamic Volume Manager Volumes',\ 'asmcmd volstat') call writeCommand(concat($cmd,' volstat 2>/dev/null')) if hasOutput(true) write $TOP if isCreated(true) toc '2:[[',getFile(),'][rda_report][ASM Command Line Utility]]' } =head2 asmtool - ASM Disks Information Collects Automatic Storage Management disks information using F utility. =cut if and(or(isCygwin(),isWindows()),\ defined(testFile('f',catFile($ORACLE_HOME,'bin',${AS.EXE:'asmtool'})))) {debug ' Inside ASM module, getting information from asmtool' var $cmd = concat(lastTestCommand(),' -list') report asmtool prefix {write '---+ ASM Disks Information' write '---## Using: ',encode($cmd) } call writeCommand($cmd) if isCreated(true) toc '2:[[',getFile(),'][rda_report][ASM Disks Information]]' } =head2 Installation Files Collects the contents of the installation files. =cut debug ' Inside ASM module, getting installation files contents' pretoc '2:Installation Files' call sort_files(3,0,\ grepDir(catDir($ORACLE_HOME,'cfgtoollogs','opatch'),'\.log$',\ concat('dirm',$LOG_AGE)),\ grepDir(catDir($ORACLE_HOME,'.patch_storage'),'^\.+$',\ concat('drvm',$LOG_AGE))) unpretoc =head1 SEE ALSO L, L, L, L, L, L, L =begin credits =over 10 =item RDA 4.2: Michael Ferrante, Noriyuki Kamei, Roger Snowden. =item RDA 4.4: Bane Radulovic, Guttula Srinivas. =item RDA 4.5: Bob Caldwell, Jaime Figueroa, Guttula Srinivas, Jens Voigt. =item RDA 4.7: Weifeng Xie. =item RDA 4.13: Jean-Marc Gaudron. =item RDA 4.14: Jean-Marc Gaudron. =item RDA 4.15: Jean-Marc Gaudron. =item RDA 4.16: Jean-Marc Gaudron. =item RDA 4.17: Jean-Marc Gaudron, Scott Jesse. =item RDA 4.18: Jaime Alcoreza. =item RDA 4.19: Jaime Alcoreza. =item RDA 4.20: Jean-Marc Gaudron. =item RDA 4.22: Jean-Marc Gaudron, Ionut Utescu. =item RDA 4.23: Jaime Alcoreza. =item RDA 4.25: Jean-Marc Gaudron. =item RDA 4.26: Masato Kataoka. =item RDA 4.28: Adam Nunes. =item RDA 8.03: Jaime Alcoreza. =item RDA 8.05: John Hoelscher. =back =end credits =head1 COPYRIGHT NOTICE Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. =head1 TRADEMARK NOTICE Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners. =cut