+# mdstat syntax information: http://www-01.ibm.com/support/docview.wss?uid=isg3T1011259
+# note that this does NOT use either Disk or Partition information for now, ie, there
+# is no connection between the data types, but the output should still be consistent
+get_raid_data()
+{
+ eval $LOGFS
+
+ local mdstat=''
+
+ if [[ $B_MDSTAT_FILE == 'true' ]];then
+ mdstat="$( cat $FILE_MDSTAT 2>/dev/null )"
+ fi
+
+ if [[ -n $mdstat ]];then
+ # need to make sure there's always a newline in front of each record type, and
+ # also correct possible weird formats for the output from older kernels etc.
+ mdstat="$( sed -e 's/^md/\nmd/' -e 's/^unused[[:space:]]/\nunused /' \
+ -e 's/read_ahead/\nread_ahead/' -e 's/^resync=/\nresync=/' -e 's/^Event/\nEvent/' \
+ -e 's/^[[:space:]]*$//' -e 's/[[:space:]]read_ahead/\nread_ahead/' <<< "$mdstat" )"
+ # some fringe cases do not end as expected, so need to add newlines plus EOF to make sure while loop doesn't spin
+ mdstat=$( echo -e "$mdstat\n\nEOF" )
+
+ IFS=$'\n'
+ A_RAID_DATA=( $(
+ gawk '
+ BEGIN {
+ IGNORECASE=1
+ RS="\n"
+ }
+
+ /^personalities/ {
+ KernelRaidSupport = gensub(/personalities[[:space:]]*:[[:space:]]*(.*)/, "\\1", 1, $0)
+ # clean off the brackets
+ gsub(/[\[\]]/,"",KernelRaidSupport)
+ print "KernelRaidSupport," KernelRaidSupport
+ }
+ /^read_ahead/ {
+ ReadAhead=gensub(/read_ahead (.*)/, "\\1", 1 )
+ print "ReadAhead," ReadAhead
+ }
+ /^Event:/ {
+ print "raidEvent," $NF
+ }
+ # print logic will search for this value and use it to print out the unused devices data
+ /^unused devices/ {
+ unusedDevices = gensub(/^unused devices:[[:space:]][<]?([^>]*)[>]?.*/, "\\1", 1, $0)
+ print "UnusedDevices," unusedDevices
+ }
+
+ /^md/ {
+ # reset for each record loop through
+ deviceState = ""
+ bitmapValues = ""
+ blocks = ""
+ chunkSize = ""
+ components = ""
+ device = ""
+ deviceReport = ""
+ finishTime = ""
+ recoverSpeed = ""
+ recoveryProgressBar = ""
+ recoveryPercent = ""
+ raidLevel = ""
+ sectorsRecovered = ""
+ separator = ""
+ superBlock = ""
+ uData = ""
+
+ while ( !/^[[:space:]]*$/ ) {
+ gsub(/'"$BAN_LIST_ARRAY"'/, " ", $0 )
+ gsub(/[[:space:]]+/, " ", $0 )
+ if ( $0 ~ /^md/ ) {
+ device = gensub(/(md.*)[[:space:]]?:/, "\\1", "1", $1 )
+ }
+ if ( $0 ~ /mirror|raid[0-9]+/ ) {
+ raidLevel = gensub(/(.*)raid([0-9]+)(.*)/, "\\2", "g", $0 )
+ }
+ if ( $0 ~ /(active \(auto-read-only\)|active|inactive)/ ) {
+ deviceState = gensub(/(.*) (active \(auto-read-only\)|active|inactive) (.*)/, "\\2", "1", $0 )
+ }
+ # gawk will not return all the components using gensub, only last one
+ separator = ""
+ for ( i=3; i<=NF; i++ ) {
+ if ( $i ~ /[hs]d[a-z][0-9]*(\[[0-9]+\])?(\([SF]\))?/ ) {
+ components = components separator $i
+ separator=" "
+ }
+ }
+ if ( $0 ~ /blocks/ ) {
+ blocks = gensub(/(.*[[:space:]]+)?([0-9]+)[[:space:]]blocks.*/, "\\2", "1", $0)
+ }
+ if ( $0 ~ /super[[:space:]][0-9\.]+/ ) {
+ superBlock = gensub(/.*[[:space:]]super[[:space:]]([0-9\.]+)[[:space:]].*/, "\\1", "1", $0)
+ }
+ if ( $0 ~ /algorithm[[:space:]][0-9\.]+/ ) {
+ algorithm = gensub(/.*[[:space:]]algorithm[[:space:]]([0-9\.]+)[[:space:]].*/, "\\1", "1", $0)
+ }
+ if ( $0 ~ /\[[0-9]+\/[0-9]+\]/ ) {
+ deviceReport = gensub(/.*[[:space:]]\[([0-9]+\/[0-9]+)\][[:space:]].*/, "\\1", "1", $0)
+ uData = gensub(/.*[[:space:]]\[([U_]+)\]/, "\\1", "1", $0)
+ }
+ # need to avoid this: bitmap: 0/10 pages [0KB], 16384KB chunk
+ # while currently all the normal chunks are marked with k, not kb, this can change in the future
+ if ( $0 ~ /[0-9]+[k] chunk/ && $0 !~ /bitmap/ ) {
+ chunkSize = gensub(/(.*) ([0-9]+[k]) chunk.*/, "\\2", "1", $0)
+ }
+ if ( $0 ~ /^resync=/ ) {
+ sub(/resync=/,"")
+ print "resyncStatus," $0
+ }
+ if ( $0 ~ /\[[=]*>[\.]*\].*(resync|recovery)/ ) {
+ recoveryProgressBar = gensub(/.*(\[[=]*>[\.]*\]).*/, "\\1",1,$0)
+ }
+ if ( $0 ~ / (resync|recovery)[[:space:]]*=/ ) {
+ recoveryPercent = gensub(/.* (resync|recovery)[[:space:]]*=[[:space:]]*([0-9\.]+%).*/, "\\1~\\2", 1 )
+ if ( $0 ~ /[[:space:]]\([0-9]+\/[0-9]+\)/ ) {
+ sectorsRecovered = gensub(/.* \(([0-9]+\/[0-9]+)\).*/, "\\1", 1, $0 )
+ }
+ if ( $0 ~ /finish[[:space:]]*=/ ) {
+ finishTime = gensub(/.* finish[[:space:]]*=[[:space:]]*([[0-9\.]+)([a-z]+) .*/, "\\1 \\2", 1, $0 )
+ }
+ if ( $0 ~ /speed[[:space:]]*=/ ) {
+ recoverSpeed = gensub(/.* speed[[:space:]]*=[[:space:]]*([[0-9\.]+)([a-z]+\/[a-z]+)/, "\\1 \\2", 1, $0 )
+ }
+ }
+ if ( $0 ~ /bitmap/ ) {
+ bitmapValues = gensub(/(.*[[:space:]])?bitmap:(.*)/, "\\2", 1, $0 )
+ }
+
+ getline
+ }
+ raidString = device "," deviceState "," raidLevel "," components "," deviceReport "," uData
+ raidString = raidString "," blocks "," superBlock "," algorithm "," chunkSize "," bitmapValues
+ raidString = raidString "," recoveryProgressBar "," recoveryPercent "," sectorsRecovered "," finishTime "," recoverSpeed
+
+ print raidString
+ }
+ ' <<< "$mdstat" ) )
+ IFS="$ORIGINAL_IFS"
+ else
+ if [[ $BSD_TYPE == 'bsd' ]];then
+ get_raid_data_bsd
+ fi
+ fi
+ B_RAID_SET='true'
+ a_temp=${A_RAID_DATA[@]}
+ log_function_data "A_RAID_DATA: $a_temp"
+# echo -e "A_RAID_DATA:\n${a_temp}"
+
+ eval $LOGFE
+}
+
+get_raid_data_bsd()
+{
+ eval $LOGFS
+ local zpool_path=$( type -p zpool 2>/dev/null )
+ local zpool_data='' zpool_arg='v'
+
+ if [[ -n $zpool_path ]];then
+ B_BSD_RAID='true'
+ # bsd sed does not support inserting a true \n so use this trick
+ # some zfs does not have -v
+ if $zpool_path list -v &>/dev/null;then
+ zpool_data="$( $zpool_path list -v 2>/dev/null | sed $SED_RX 's/^([^[:space:]])/\
+\1/' )"
+ else
+ zpool_data="$( $zpool_path list 2>/dev/null | sed $SED_RX 's/^([^[:space:]])/\
+\1/' )"
+ zpool_arg='no-v'
+ fi
+# echo "$zpool_data"
+ IFS=$'\n'
+ A_RAID_DATA=( $(
+ gawk '
+ BEGIN {
+ IGNORECASE=1
+ raidString=""
+ separator=""
+ components=""
+ reportSize=""
+ blocksAvailable=""
+ chunkRaidAllocated=""
+ }
+ /SIZE.*ALLOC/ {
+ sub(/.*ALLOC.*/,"", $0)
+ }
+ # gptid/d874c7e7-3f6d-11e4-b7dc-080027ea466c
+ /^[^[:space:]]/ {
+ components=""
+ separator=""
+ raidLevel=""
+ device=$1
+ deviceState=$7
+ reportSize=$2
+ blocksAvailable=$4
+ chunkRaidAllocated=$3
+
+ getline
+ # raid level is the second item in the output, unless it is not, sometimes it is absent
+ if ( $1 != "" ) {
+ if ( $1 ~ /raid|mirror/ ) {
+ raidLevel="zfs " $1
+ }
+ else {
+ raidLevel="zfs-no-raid"
+ components = $1
+ separator=" "
+ }
+ }
+
+ while ( getline && $1 !~ /^$/ ) {
+ # https://blogs.oracle.com/eschrock/entry/zfs_hot_spares
+ if ($1 ~ /spares/) {
+ getline
+ }
+ # print $1
+ components = components separator $1
+ separator=" "
+ }
+ # some issues if we use ~ here
+ gsub(/\//,"%",components)
+ # print $1
+ raidString = device "," deviceState "," raidLevel "," components "," reportSize "," uData
+ raidString = raidString "," blocksAvailable "," superBlock "," algorithm "," chunkRaidAllocated
+ # none of these are used currently
+ raidString = raidString "," bitmapValues "," recoveryProgressBar "," recoveryPercent
+ raidString = raidString "," sectorsRecovered "," finishTime "," recoverSpeed
+ gsub(/~/,"",raidString)
+ print raidString
+ }' <<< "$zpool_data" ) )
+ IFS="$ORIGINAL_IFS"
+ # pass the zpool type, so we know how to get the components
+ get_raid_component_data_bsd "$zpool_arg"
+ fi
+ eval $LOGFE
+}
+
+# note, we've already tested for zpool so no further tests required
+# args: $1 - zpool type, v will have a single row output, no-v has stacked for components
+get_raid_component_data_bsd()
+{
+ eval $LOGFS
+ local a_raid_data='' array_string='' component='' component_string=''
+ local zpool_status='' device='' separator='' component_status=''
+
+ for (( i=0; i<${#A_RAID_DATA[@]}; i++))
+ do
+ IFS=","
+ a_raid_data=( ${A_RAID_DATA[i]} )
+ IFS="$ORIGINAL_IFS"
+ separator=''
+ component_string=''
+ component_status=''
+ zpool_status=''
+ device=${a_raid_data[0]}
+ zpool_status="$( zpool status $device )"
+ # we will remove ONLINE for status and only use OFFLINE/DEGRADED as tests
+ # for print output display of issues with components
+ # note: different zfs outputs vary, some have the components listed by line
+ if [[ $1 == 'v' ]];then
+ for component in ${a_raid_data[3]}
+ do
+ component_status=$( gawk '
+ BEGIN {
+ IGNORECASE=1
+ separator=""
+ }
+ {
+ gsub(/\//,"%",$1)
+ }
+ $1 ~ /^'$component'$/ {
+ sub( /ONLINE/, "", $2 )
+ print "'$component'" $2
+ exit
+ }' <<< "$zpool_status" )
+ component_string="$component_string$separator$component_status"
+ separator=' '
+ done
+ array_string="$device,${a_raid_data[1]},${a_raid_data[2]},${component_string//%/\/},${a_raid_data[4]}"
+ array_string="$array_string,${a_raid_data[5]},${a_raid_data[6]},${a_raid_data[7]},${a_raid_data[8]}"
+ array_string="$array_string,${a_raid_data[9]},${a_raid_data[10]},${a_raid_data[11]},${a_raid_data[12]},"
+ array_string="$array_string${a_raid_data[13]},${a_raid_data[14]},${a_raid_data[15]}"
+ else
+ component_string=$( gawk '
+ BEGIN {
+ IGNORECASE=1
+ separator=""
+ components=""
+ raidLevel=""
+ }
+ $1 ~ /^'$device'$/ {
+ while ( getline && !/^$/ ) {
+ # raid level is the second item in the output, unless it is not, sometimes it is absent
+ if ( $1 != "" ) {
+ if ( raidLevel == "" ) {
+ if ( $1 ~ /raid|mirror/ ) {
+ raidLevel="zfs " $1
+ getline
+ }
+ else {
+ raidLevel="zfs-no-raid"
+ }
+ }
+ }
+ # https://blogs.oracle.com/eschrock/entry/zfs_hot_spares
+ if ($1 ~ /spares/) {
+ getline
+ }
+ sub( /ONLINE/, "", $2 )
+ components=components separator $1 separator $2
+ separator=" "
+ }
+ print raidLevel "," components
+ }' <<< "$zpool_status" )
+ # note: component_string is raid type AND components
+ array_string="$device,${a_raid_data[1]},$component_string,${a_raid_data[4]}"
+ array_string="$array_string,${a_raid_data[5]},${a_raid_data[6]},${a_raid_data[7]},${a_raid_data[8]}"
+ array_string="$array_string,${a_raid_data[9]},${a_raid_data[10]},${a_raid_data[11]},${a_raid_data[12]},"
+ array_string="$array_string${a_raid_data[13]},${a_raid_data[14]},${a_raid_data[15]}"
+ fi
+ IFS=","
+ A_RAID_DATA[i]=$array_string
+ IFS="$ORIGINAL_IFS"
+ done
+
+ eval $LOGFE
+}
+# get_raid_data_bsd;exit
+
+get_ram_data()
+{
+ eval $LOGFS
+
+ local a_temp='' array_string=''
+
+ get_dmidecode_data
+
+ if [[ -n $DMIDECODE_DATA ]];then
+ if [[ $DMIDECODE_DATA == 'dmidecode-error-'* ]];then
+ A_MEMORY_DATA[0]=$DMIDECODE_DATA
+ # please note: only dmidecode version 2.11 or newer supports consistently the -s flag
+ else
+ IFS=$'\n'
+ A_MEMORY_DATA=( $(
+ gawk -F ':' '
+ BEGIN {
+ IGNORECASE=1
+ arrayHandle=""
+ bankLocator=""
+ clockSpeed=""
+ configuredClockSpeed=""
+ dataWidth=""
+ deviceManufacturer=""
+ devicePartNumber=""
+ deviceSerialNumber=""
+ deviceSpeed=""
+ deviceType=""
+ deviceTypeDetail=""
+ deviceSize=""
+ errorCorrection=""
+ formFactor=""
+ handle=""
+ location=""
+ locator=""
+ aArrayData[0,"maxCapacity5"]=0
+ aArrayData[0,"maxCapacity16"]=0
+ aArrayData[0,"usedCapacity"]=0
+ aArrayData[0,"maxModuleSize"]=0
+ aArrayData[0,"derivedModuleSize"]=0
+ aArrayData[0,"deviceCount5"]=0
+ aArrayData[0,"deviceCount16"]=0
+ aArrayData[0,"deviceCountFound"]=0
+ aArrayData[0,"moduleVoltage5"]=""
+ moduleVoltage=""
+ numberOfDevices=""
+ primaryType=""
+ totalWidth=""
+ use=""
+ i=0
+ j=0
+ k=0
+ bDebugger1="false"
+ dDebugger2="false"
+ bType5="false"
+ }
+ function calculateSize(data,size) {
+ if ( data ~ /^[0-9]+[[:space:]]*[GMTP]B/) {
+ if ( data ~ /GB/ ) {
+ data=gensub(/([0-9]+)[[:space:]]*GB/,"\\1",1,data) * 1024
+ }
+ else if ( data ~ /MB/ ) {
+ data=gensub(/([0-9]+)[[:space:]]*MB/,"\\1",1,data)
+ }
+ else if ( data ~ /TB/ ) {
+ data=gensub(/([0-9]+)[[:space:]]*TB/,"\\1",1,data) * 1024 * 1000
+ }
+ else if ( data ~ /PB/ ) {
+ data=gensub(/([0-9]+)[[:space:]]*TB/,"\\1",1,data) * 1024 * 1000 * 1000
+ }
+ if (data ~ /^[0-9][0-9]+$/ && data > size ) {
+ size=data
+ }
+ }
+ return size
+ }
+ /^Table[[:space:]]+at[[:space:]]/ {
+ bType5="false"
+ # we need to start count here because for testing > 1 array, and we want always to have
+ # the actual module data assigned to the right primary array, even when it is out of
+ # position in dmidecode output
+ i=0
+ j=0
+ k++
+ }
+ # {print k ":k:" $0}
+ /^Handle .* DMI[[:space:]]+type[[:space:]]+5(,|[[:space:]])/ {
+ while ( getline && !/^$/ ) {
+ if ( $1 == "Maximum Memory Module Size" ) {
+ aArrayData[k,"maxModuleSize"]=calculateSize($2,aArrayData[k,"maxModuleSize"])
+ # print "mms:" aArrayData[k,"maxModuleSize"] ":" $2
+ }
+ if ($1 == "Maximum Total Memory Size") {
+ aArrayData[k,"maxCapacity5"]=calculateSize($2,aArrayData[k,"maxCapacity5"])
+ }
+ if ( $1 == "Memory Module Voltage" ) {
+ aArrayData[k,"moduleVoltage5"]=$2
+ }
+ }
+ aArrayData[k,"data-type"]="memory-array"
+ # print k ":data5:"aArrayData[k,"data-type"]
+ bType5="true"
+ }
+ /^Handle .* DMI[[:space:]]+type[[:space:]]+6(,|[[:space:]])/ {
+ while ( getline && !/^$/ ) {
+ if ( $1 == "Installed Size" ) {
+ # get module size
+ aMemory[k,j,18]=calculateSize($2,0)
+ # get data after module size
+ sub(/ Connection/,"",$2)
+ sub(/^[0-9]+[[:space:]]*[MGTP]B[[:space:]]*/,"",$2)
+ aMemory[k,j,16]=$2
+ }
+ if ( $1 == "Current Speed" ) {
+ aMemory[k,j,17]=$2
+ }
+ }
+ j++
+ }
+
+ /^Handle .* DMI[[:space:]]+type[[:space:]]+16/ {
+ arrayHandle=gensub(/Handle[[:space:]]([0-9a-zA-Z]+)([[:space:]]|,).*/,"\\1",$0)
+ while ( getline && !/^$/ ) {
+ # print $0
+ if ( $1 == "Maximum Capacity") {
+ aArrayData[k,"maxCapacity16"]=calculateSize($2,aArrayData[k,"maxCapacity16"])
+ #print "mc:" aArrayData[k,"maxCapacity16"] ":" $2
+ }
+ # note: these 3 have cleaned data in get_dmidecode_data, so replace stuff manually
+ if ( $1 == "Location") {
+ sub(/[[:space:]]Or[[:space:]]Motherboard/,"",$2)
+ location=$2
+ if ( location == "" ){
+ location="System Board"
+ }
+ }
+ if ( $1 == "Use") {
+ use=$2
+ if ( use == "" ){
+ use="System Memory"
+ }
+ }
+ if ( $1 == "Error Correction Type") {
+ errorCorrection=$2
+ if ( errorCorrection == "" ){
+ errorCorrection="None"
+ }
+ }
+ if ( $1 == "Number of Devices") {
+ numberOfDevices=$2
+ }
+ }
+ aArrayData[k,"data-type"]="memory-array"
+ # print k ":data16:"aArrayData[k,"data-type"]
+ aArrayData[k,"handle"]=arrayHandle
+ aArrayData[k,"location"]=location
+ aArrayData[k,"deviceCount16"]=numberOfDevices
+ aArrayData[k,"use"]=use
+ aArrayData[k,"errorCorrection"]=errorCorrection
+
+ # reset
+ primaryType=""
+ arrayHandle=""
+ location=""
+ numberOfDevices=""
+ use=""
+ errorCorrection=""
+ moduleVoltage=""
+
+ aDerivedModuleSize[k+1]=0
+ aArrayData[k+1,"deviceCountFound"]=0
+ aArrayData[k+1,"maxCapacity5"]=0
+ aArrayData[k+1,"maxCapacity16"]=0
+ aArrayData[k+1,"maxModuleSize"]=0
+ }
+ /^Handle .* DMI[[:space:]]+type[[:space:]]+17/ {
+ while ( getline && !/^$/ ) {
+ if ( $1 == "Array Handle") {
+ arrayHandle=$2
+ }
+ if ( $1 == "Data Width") {
+ dataWidth=$2
+ }
+ if ( $1 == "Total Width") {
+ totalWidth=$2
+ }
+ if ( $1 == "Size") {
+ # do not try to guess from installed modules, only use this to correct type 5 data
+ aArrayData[k,"derivedModuleSize"]=calculateSize($2,aArrayData[k,"derivedModuleSize"])
+ workingSize=calculateSize($2,0)
+ if ( workingSize ~ /^[0-9][0-9]+$/ ){
+ aArrayData[k,"deviceCountFound"]++
+ # build up actual capacity found for override tests
+ aArrayData[k,"usedCapacity"]=workingSize + aArrayData[k,"usedCapacity"]
+ }
+ # print aArrayData[k,"derivedModuleSize"] " dm:" k ":mm " aMaxModuleSize[k] " uc:" aArrayData[k,"usedCapacity"]
+ # we want any non real size data to be preserved
+ if ( $2 ~ /^[0-9]+[[:space:]]*[MTPG]B/ ) {
+ deviceSize=workingSize
+ }
+ else {
+ deviceSize=$2
+ }
+ }
+ if ( $1 == "Locator") {
+ # sub(/.*_/,"",$2)
+ #sub(/RAM slot #|^DIMM/, "Slot",$2)
+ sub(/RAM slot #/, "Slot",$2)
+
+ #locator=toupper($2)
+ locator=$2
+ }
+ if ( $1 == "Bank Locator") {
+ #sub(/_.*/,"",$2)
+ #sub(/RAM slot #|Channel|Chan/,"bank",$2)
+ #sub(/RAM slot #|Channel|Chan/,"bank",$2)
+ #bankLocator=toupper($2)
+ bankLocator=$2
+ }
+ if ( $1 == "Form Factor") {
+ formFactor=$2
+ }
+ if ( $1 == "Type") {
+ deviceType=$2
+ }
+ if ( $1 == "Type Detail") {
+ deviceTypeDetail=$2
+ }
+ if ( $1 == "Speed") {
+ deviceSpeed=$2
+ }
+ if ( $1 == "Configured Clock Speed") {
+ configuredClockSpeed=$2
+ }
+ if ( $1 == "Manufacturer") {
+ gsub(/(^[0]+$|Undefined.*|.*Manufacturer.*)/,"",$2)
+ deviceManufacturer=$2
+ }
+ if ( $1 == "Part Number") {
+ sub(/(^[0]+$||.*Module.*|Undefined.*)/,"",$2)
+ devicePartNumber=$2
+ }
+ if ( $1 == "Serial Number") {
+ gsub(/(^[0]+$|Undefined.*)/,"",$2)
+ deviceSerialNumber=$2
+ }
+ }
+ # because of the wide range of bank/slot type data, we will just use
+ # the one that seems most likely to be right. Some have: Bank: SO DIMM 0 slot: J6A
+ # so we dump the useless data and use the one most likely to be visibly correct
+ if ( bankLocator ~ /DIMM/ ) {
+ mainLocator=bankLocator
+ }
+ else {
+ mainLocator=locator
+ }
+ # sometimes the data is just wrong, they reverse total/data. data I believe is
+ # used for the actual memory bus width, total is some synthetic thing, sometimes missing.
+ # note that we do not want a regular string comparison, because 128 bit memory buses are
+ # in our future, and 128 bits < 64 bits with string compare
+ intData=gensub(/(^[0-9]+).*/,"\\1",1,dataWidth)
+ intTotal=gensub(/(^[0-9]+).*/,"\\1",1,totalWidth)
+ if (intData != "" && intTotal != "" && intData > intTotal ) {
+ tempWidth=dataWidth
+ dataWidth=totalWidth
+ totalWidth=tempWidth
+ }
+
+ aMemory[k,i,0]="memory-device"
+ aMemory[k,i,1]=arrayHandle
+ aMemory[k,i,2]=deviceSize
+ aMemory[k,i,3]=bankLocator
+ aMemory[k,i,4]=locator
+ aMemory[k,i,5]=formFactor
+ aMemory[k,i,6]=deviceType
+ aMemory[k,i,7]=deviceTypeDetail
+ aMemory[k,i,8]=deviceSpeed
+ aMemory[k,i,9]=configuredClockSpeed
+ aMemory[k,i,10]=dataWidth
+ aMemory[k,i,11]=totalWidth
+ aMemory[k,i,12]=deviceManufacturer
+ aMemory[k,i,13]=devicePartNumber
+ aMemory[k,i,14]=deviceSerialNumber
+ aMemory[k,i,15]=mainLocator
+
+ primaryType=""
+ arrayHandle=""
+ deviceSize=""
+ bankLocator=""
+ locator=""
+ mainLocator=""
+ mainLocator=""
+ formFactor=""
+ deviceType=""
+ deviceTypeDetail=""
+ deviceSpeed=""
+ configuredClockSpeed=""
+ dataWidth=""
+ totalWidth=""
+ deviceManufacturer=""
+ devicePartNumber=""
+ deviceSerialNumber=""
+ i++
+ }
+ END {
+ ## CRITICAL: gawk keeps changing integers to strings, so be explicit with int() in math
+ # print primaryType "," arrayHandle "," location "," maxCapacity "," numberOfDevices "," use "," errorCorrection "," maxModuleSize "," moduleVoltage
+
+ # print primaryType "," arrayHandle "," deviceSize "," bankLocator "," locator "," formFactor "," deviceType "," deviceTypeDetail "," deviceSpeed "," configuredClockSpeed "," dataWidth "," totalWidth "," deviceManufacturer "," devicePartNumber "," deviceSerialNumber "," mainLocator
+
+ for ( m=1;m<=k;m++ ) {
+ estCap=""
+ estMod=""
+ unit=""
+ altCap=0
+ workingMaxCap=int(aArrayData[m,"maxCapacity16"])
+
+ if ( bDebugger1 == "true" ){
+ print ""
+ print "count: " m
+ print "1: mmods: " aArrayData[m,"maxModuleSize"] " :dmmods: " aArrayData[m,"derivedModuleSize"] " :mcap: " workingMaxCap " :ucap: " aArrayData[m,"usedCapacity"]
+ }
+ # 1: if max cap 1 is null, and max cap 2 not null, use 2
+ if ( workingMaxCap == 0 ) {
+ if ( aArrayData[m,"maxCapacity5"] != 0 ) {
+ workingMaxCap=aArrayData[m,"maxCapacity5"]
+ }
+ }
+ if ( aArrayData[m,"deviceCount16"] == "" ) {
+ aArrayData[m,"deviceCount16"] = 0
+ }
+ if ( bDebugger1 == "true" ){
+ print "2: mmods: " aArrayData[m,"maxModuleSize"] " :dmmods: " aArrayData[m,"derivedModuleSize"] " :mcap: " workingMaxCap " :ucap: " aArrayData[m,"usedCapacity"]
+ }
+ # 2: now check to see if actually found module sizes are > than listed max module, replace if >
+ if (aArrayData[m,"maxModuleSize"] != 0 && aArrayData[m,"derivedModuleSize"] != 0 && int(aArrayData[m,"derivedModuleSize"]) > int(aArrayData[m,"maxModuleSize"]) ) {
+ aArrayData[m,"maxModuleSize"]=aArrayData[m,"derivedModuleSize"]
+ estMod=" (est)"
+ }
+ aArrayData[m,"maxModuleSize"]=int(aArrayData[m,"maxModuleSize"])
+ aArrayData[m,"derivedModuleSize"]=int(aArrayData[m,"derivedModuleSize"])
+ aArrayData[m,"usedCapacity"]=int(aArrayData[m,"usedCapacity"])
+ workingMaxCap=int(workingMaxCap)
+
+ # note: some cases memory capacity == max module size, so one stick will fill it
+ # but I think only with cases of 2 slots does this happen, so if > 2, use the count of slots.
+ if ( bDebugger1 == "true" ){
+ print "3: fmod: " aArrayData[m,"deviceCountFound"] " :modc: " aArrayData[m,"deviceCount16"] " :maxc1: " aArrayData[m,"maxCapacity5"] " :maxc2: " aArrayData[m,"maxCapacity16"]
+ }
+ if (workingMaxCap != 0 && ( aArrayData[m,"deviceCountFound"] != 0 || aArrayData[m,"deviceCount16"] != 0 ) ) {
+ aArrayData[m,"deviceCount16"]=int(aArrayData[m,"deviceCount16"])
+ ## first check that actual memory found is not greater than listed max cap, or
+ ## checking to see module count * max mod size is not > used capacity
+ if ( aArrayData[m,"usedCapacity"] != 0 && aArrayData[m,"maxCapacity16"] != 0 ) {
+ if ( aArrayData[m,"usedCapacity"] > workingMaxCap ) {
+ if ( aArrayData[m,"maxModuleSize"] != 0 &&
+ aArrayData[m,"usedCapacity"] < aArrayData[m,"deviceCount16"] * aArrayData[m,"maxModuleSize"] ) {
+ workingMaxCap=aArrayData[m,"deviceCount16"] * aArrayData[m,"maxModuleSize"]
+ estCap=" (est)"
+ if ( bDebugger1 == "true" ){
+ print "A"
+ }
+ }
+ else if ( aArrayData[m,"derivedModuleSize"] != 0 &&
+ aArrayData[m,"usedCapacity"] < aArrayData[m,"deviceCount16"] * aArrayData[m,"derivedModuleSize"] ) {
+ workingMaxCap=aArrayData[m,"deviceCount16"] * aArrayData[m,"derivedModuleSize"]
+ estCap=" (est)"
+ if ( bDebugger1 == "true" ){
+ print "B"
+ }
+ }
+ else {
+ workingMaxCap=aArrayData[m,"usedCapacity"]
+ estCap=" (est)"
+ if ( bDebugger1 == "true" ){
+ print "C"
+ }
+ }
+ }
+ }
+ # note that second case will never really activate except on virtual machines and maybe
+ # mobile devices
+ if ( estCap == "" ) {
+ # do not do this for only single modules found, max mod size can be equal to the array size
+ if ( ( aArrayData[m,"deviceCount16"] > 1 && aArrayData[m,"deviceCountFound"] > 1 ) &&
+ ( workingMaxCap < aArrayData[m,"derivedModuleSize"] * aArrayData[m,"deviceCount16"] ) ) {
+ workingMaxCap = aArrayData[m,"derivedModuleSize"] * aArrayData[m,"deviceCount16"]
+ estCap=" (est)"
+ if ( bDebugger1 == "true" ){
+ print "D"
+ }
+ }
+ else if ( ( aArrayData[m,"deviceCountFound"] > 0 ) &&
+ ( workingMaxCap < aArrayData[m,"derivedModuleSize"] * aArrayData[m,"deviceCountFound"] ) ) {
+ workingMaxCap = aArrayData[m,"derivedModuleSize"] * aArrayData[m,"deviceCountFound"]
+ estCap=" (est)"
+ if ( bDebugger1 == "true" ){
+ print "E"
+ }
+ }
+ ## handle cases where we have type 5 data: mms x device count equals type 5 max cap
+ # however do not use it if cap / devices equals the derived module size
+ else if ( aArrayData[m,"maxModuleSize"] > 0 &&
+ ( aArrayData[m,"maxModuleSize"] * aArrayData[m,"deviceCount16"] == aArrayData[m,"maxCapacity5"] ) &&
+ aArrayData[m,"maxCapacity5"] != aArrayData[m,"maxCapacity16"] &&
+ aArrayData[m,"maxCapacity16"] / aArrayData[m,"deviceCount16"] != aArrayData[m,"derivedModuleSize"] ) {
+ workingMaxCap = aArrayData[m,"maxCapacity5"]
+ altCap=aArrayData[m,"maxCapacity5"] # not used
+ estCap=" (check)"
+ if ( bDebugger1 == "true" ){
+ print "F"
+ }
+ }
+ }
+ }
+ altCap=int(altCap)
+ workingMaxCap=int(workingMaxCap)
+ if ( bDebugger1 == "true" ){
+ print "4: mmods: " aArrayData[m,"maxModuleSize"] " :dmmods: " aArrayData[m,"derivedModuleSize"] " :mcap: " workingMaxCap " :ucap: " aArrayData[m,"usedCapacity"]
+ }
+ # some cases of type 5 have too big module max size, just dump the data then since
+ # we cannot know if it is valid or not, and a guess can be wrong easily
+ if ( aArrayData[m,"maxModuleSize"] != 0 && workingMaxCap != "" &&
+ ( aArrayData[m,"maxModuleSize"] > workingMaxCap ) ){
+ aArrayData[m,"maxModuleSize"] = 0
+ # print "yes"
+ }
+ if ( bDebugger1 == "true" ){
+ print "5: dms: " aArrayData[m,"derivedModuleSize"] " :dc: " aArrayData[m,"deviceCount16"] " :wmc: " workingMaxCap
+ }
+ ## prep for output ##
+ if (aArrayData[m,"maxModuleSize"] == 0 ){
+ aArrayData[m,"maxModuleSize"]=""
+ # ie: 2x4gB
+ if ( estCap == "" && int(aArrayData[m,"derivedModuleSize"]) > 0 &&
+ workingMaxCap > ( int(aArrayData[m,"derivedModuleSize"]) * int(aArrayData[m,"deviceCount16"]) * 4 ) ) {
+ estCap=" (check)"
+ if ( bDebugger1 == "true" ){
+ print "G"
+ }
+ }
+ }
+ else {
+ # case where listed max cap is too big for actual slots x max cap, eg:
+ # listed max cap, 8gb, max mod 2gb, slots 2
+ if ( estCap == "" && aArrayData[m,"maxModuleSize"] > 0 ) {
+ if ( int(workingMaxCap) > int(aArrayData[m,"maxModuleSize"]) * aArrayData[m,"deviceCount16"] ) {
+ estCap=" (check)"
+ if ( bDebugger1 == "true" ){
+ print "H"
+ }
+ }
+ }
+ if (aArrayData[m,"maxModuleSize"] > 1023 ) {
+ aArrayData[m,"maxModuleSize"]=aArrayData[m,"maxModuleSize"] / 1024 " GB"
+ }
+ else {
+ aArrayData[m,"maxModuleSize"]=aArrayData[m,"maxModuleSize"] " MB"
+ }
+ }
+ if ( aArrayData[m,"deviceCount16"] == 0 ) {
+ aArrayData[m,"deviceCount16"] = ""
+ }
+ if (workingMaxCap != 0 ) {
+ if ( workingMaxCap < 1024 ) {
+ workingMaxCap = workingMaxCap
+ unit=" MB"
+ }
+ else if ( workingMaxCap < 1024000 ) {
+ workingMaxCap = workingMaxCap / 1024
+ unit=" GB"
+ }
+ else if ( workingMaxCap < 1024000000 ) {
+ workingMaxCap = workingMaxCap / 1024000
+ unit=" TB"
+ }
+ # we only want a max 2 decimal places, this trick gives 0 to 2
+ workingMaxCap=gensub(/([0-9]+\.[0-9][0-9]).*/,"\\1",1,workingMaxCap)
+ workingMaxCap = workingMaxCap unit estCap
+
+ }
+ else {
+ workingMaxCap == ""
+ }
+
+ print aArrayData[m,"data-type"] "," aArrayData[m,"handle"] "," aArrayData[m,"location"] "," workingMaxCap "," aArrayData[m,"deviceCount16"] "," aArrayData[m,"use"] "," aArrayData[m,"errorCorrection"] "," aArrayData[m,"maxModuleSize"] estMod "," aArrayData[m,"voltage5"]
+ # print device rows next
+ for ( j=0;j<=100;j++ ) {
+ if (aMemory[m,j,0] != "" ) {
+ unit=""
+ workingSize=aMemory[m,j,2]
+ if ( workingSize ~ /^[0-9]+$/ ) {
+ workingSize=int(workingSize)
+ if ( workingSize < 1024 ) {
+ workingSize = workingSize
+ unit=" MB"
+ }
+ else if ( workingSize < 1024000 ) {
+ workingSize = workingSize / 1024
+ unit=" GB"
+ }
+ else if ( workingSize < 1024000000 ) {
+ workingSize = workingSize / 1024000
+ unit=" TB"
+ }
+ # we only want a max 2 decimal places, this trick gives 0 to 2
+ workingSize=gensub(/([0-9]+\.[0-9][0-9]).*/,"\\1",1,workingSize)
+ workingSize = workingSize unit
+ }
+ print aMemory[m,j,0] "," aMemory[m,j,1] "," workingSize "," aMemory[m,j,3] "," aMemory[m,j,4] "," aMemory[m,j,5] "," aMemory[m,j,6] "," aMemory[m,j,7] "," aMemory[m,j,8] "," aMemory[m,j,9] "," aMemory[m,j,10] "," aMemory[m,j,11] "," aMemory[m,j,12] "," aMemory[m,j,13] "," aMemory[m,j,14] "," aMemory[m,j,15] "," aMemory[m,j,16] "," aMemory[m,j,17]
+ }
+ else {
+ break
+ }
+ }
+ }
+ }' <<< "$DMIDECODE_DATA" ) )
+ fi
+ fi
+ IFS="$ORIGINAL_IFS"
+ a_temp=${A_MEMORY_DATA[@]}
+
+ # echo "${a_temp[@]}"
+ log_function_data "A_MEMORY_DATA: $a_temp"
+
+ eval $LOGFE
+}
+