Unify SMART report format
This commit is contained in:
parent
a00f20c10a
commit
093c035fb2
1 changed files with 24 additions and 58 deletions
|
|
@ -64,19 +64,10 @@ main() {
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Detect drive type
|
# Check if it's NVMe (for attribute parsing differences)
|
||||||
local drive_type="UNKNOWN"
|
local is_nvme=false
|
||||||
if [[ "$device" == *"nvme"* ]]; then
|
if [[ "$device" == *"nvme"* ]]; then
|
||||||
drive_type="NVMe"
|
is_nvme=true
|
||||||
else
|
|
||||||
# Check if it's SSD or HDD based on rotation rate
|
|
||||||
local smart_info
|
|
||||||
smart_info=$(smartctl -i "$device" 2>/dev/null)
|
|
||||||
if echo "$smart_info" | grep -q "Rotation Rate:.*Solid State Device\|Rotation Rate:.*0 rpm"; then
|
|
||||||
drive_type="SSD"
|
|
||||||
elif echo "$smart_info" | grep -q "Rotation Rate:.*[0-9][0-9][0-9][0-9] rpm"; then
|
|
||||||
drive_type="HDD"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get SMART health
|
# Get SMART health
|
||||||
|
|
@ -91,7 +82,7 @@ main() {
|
||||||
# Get enhanced SMART data
|
# Get enhanced SMART data
|
||||||
local temp="N/A"
|
local temp="N/A"
|
||||||
local power_hours="N/A"
|
local power_hours="N/A"
|
||||||
local wear_info="N/A"
|
local wear_info=""
|
||||||
local data_info=""
|
local data_info=""
|
||||||
local error_info=""
|
local error_info=""
|
||||||
|
|
||||||
|
|
@ -99,8 +90,8 @@ main() {
|
||||||
local smart_data
|
local smart_data
|
||||||
smart_data=$(smartctl -A "$device" 2>/dev/null)
|
smart_data=$(smartctl -A "$device" 2>/dev/null)
|
||||||
|
|
||||||
if [[ "$drive_type" == "NVMe" ]]; then
|
if [[ "$is_nvme" == "true" ]]; then
|
||||||
# NVMe specific attributes
|
# NVMe attributes (different format)
|
||||||
temp=$(echo "$smart_data" | awk '/^Temperature:/ {print $2}' | head -1)
|
temp=$(echo "$smart_data" | awk '/^Temperature:/ {print $2}' | head -1)
|
||||||
if [[ -n "$temp" && "$temp" =~ ^[0-9]+$ ]]; then
|
if [[ -n "$temp" && "$temp" =~ ^[0-9]+$ ]]; then
|
||||||
temp="${temp}C"
|
temp="${temp}C"
|
||||||
|
|
@ -138,8 +129,10 @@ main() {
|
||||||
error_info=$(IFS=' '; echo "${error_parts[*]}")
|
error_info=$(IFS=' '; echo "${error_parts[*]}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
elif [[ "$drive_type" == "SSD" ]]; then
|
else
|
||||||
# SATA SSD - format similar to NVMe
|
# SATA/SAS drives - try to get all available attributes
|
||||||
|
|
||||||
|
# Temperature
|
||||||
temp=$(echo "$smart_data" | awk '/Temperature_Celsius/ {print $10}' | head -1)
|
temp=$(echo "$smart_data" | awk '/Temperature_Celsius/ {print $10}' | head -1)
|
||||||
if [[ -n "$temp" && "$temp" =~ ^[0-9]+$ ]]; then
|
if [[ -n "$temp" && "$temp" =~ ^[0-9]+$ ]]; then
|
||||||
temp="${temp}C"
|
temp="${temp}C"
|
||||||
|
|
@ -147,38 +140,35 @@ main() {
|
||||||
temp="N/A"
|
temp="N/A"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Power on hours
|
||||||
power_hours=$(echo "$smart_data" | awk '/Power_On_Hours/ {print $10}' | head -1)
|
power_hours=$(echo "$smart_data" | awk '/Power_On_Hours/ {print $10}' | head -1)
|
||||||
|
|
||||||
# Wear indicator - convert to percentage used (inverse of wear level)
|
# Wear indicators (for SSDs)
|
||||||
local wear_level media_wearout percentage_used
|
local wear_level media_wearout percentage_used
|
||||||
wear_level=$(echo "$smart_data" | awk '/Wear_Leveling_Count/ {print $4}' | head -1)
|
wear_level=$(echo "$smart_data" | awk '/Wear_Leveling_Count/ {print $4}' | head -1)
|
||||||
media_wearout=$(echo "$smart_data" | awk '/Media_Wearout_Indicator/ {print $4}' | head -1)
|
media_wearout=$(echo "$smart_data" | awk '/Media_Wearout_Indicator/ {print $4}' | head -1)
|
||||||
|
|
||||||
if [[ -n "$wear_level" ]]; then
|
if [[ -n "$wear_level" ]]; then
|
||||||
# Wear_Leveling_Count: 100 = new, 0 = worn out
|
|
||||||
percentage_used=$((100 - wear_level))
|
percentage_used=$((100 - wear_level))
|
||||||
wear_info="Wear: ${percentage_used}%"
|
wear_info="Wear: ${percentage_used}%"
|
||||||
elif [[ -n "$media_wearout" ]]; then
|
elif [[ -n "$media_wearout" ]]; then
|
||||||
# Media_Wearout_Indicator: 100 = new, 0 = worn out
|
|
||||||
percentage_used=$((100 - media_wearout))
|
percentage_used=$((100 - media_wearout))
|
||||||
wear_info="Wear: ${percentage_used}%"
|
wear_info="Wear: ${percentage_used}%"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Data read/written - convert LBAs to human readable
|
# Data read/written
|
||||||
local lbas_written lbas_read data_written data_read
|
local lbas_written lbas_read data_written data_read
|
||||||
lbas_written=$(echo "$smart_data" | awk '/Total_LBAs_Written/ {print $10}' | head -1)
|
lbas_written=$(echo "$smart_data" | awk '/Total_LBAs_Written/ {print $10}' | head -1)
|
||||||
lbas_read=$(echo "$smart_data" | awk '/Total_LBAs_Read/ {print $10}' | head -1)
|
lbas_read=$(echo "$smart_data" | awk '/Total_LBAs_Read/ {print $10}' | head -1)
|
||||||
|
|
||||||
if [[ -n "$lbas_written" && -n "$lbas_read" ]]; then
|
if [[ -n "$lbas_written" && -n "$lbas_read" ]]; then
|
||||||
# Convert LBAs to GB (1 LBA = 512 bytes)
|
# Convert LBAs to GB (1 LBA = 512 bytes)
|
||||||
# Using bash arithmetic (integer math) - divide by 2097152 to get GB (512 * LBAs / 1073741824)
|
|
||||||
local gb_written_int gb_read_int
|
local gb_written_int gb_read_int
|
||||||
gb_written_int=$((lbas_written / 2097152)) # LBAs * 512 / 1GB
|
gb_written_int=$((lbas_written / 2097152)) # LBAs * 512 / 1GB
|
||||||
gb_read_int=$((lbas_read / 2097152))
|
gb_read_int=$((lbas_read / 2097152))
|
||||||
|
|
||||||
# Format with appropriate units
|
# Format with appropriate units
|
||||||
if [[ $gb_written_int -gt 1000 ]]; then
|
if [[ $gb_written_int -gt 1000 ]]; then
|
||||||
# Convert to TB with one decimal place
|
|
||||||
local tb_written_int=$((gb_written_int / 1024))
|
local tb_written_int=$((gb_written_int / 1024))
|
||||||
local tb_written_dec=$(( (gb_written_int % 1024) * 10 / 1024 ))
|
local tb_written_dec=$(( (gb_written_int % 1024) * 10 / 1024 ))
|
||||||
data_written="${tb_written_int}.${tb_written_dec} TB"
|
data_written="${tb_written_int}.${tb_written_dec} TB"
|
||||||
|
|
@ -187,7 +177,6 @@ main() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $gb_read_int -gt 1000 ]]; then
|
if [[ $gb_read_int -gt 1000 ]]; then
|
||||||
# Convert to TB with one decimal place
|
|
||||||
local tb_read_int=$((gb_read_int / 1024))
|
local tb_read_int=$((gb_read_int / 1024))
|
||||||
local tb_read_dec=$(( (gb_read_int % 1024) * 10 / 1024 ))
|
local tb_read_dec=$(( (gb_read_int % 1024) * 10 / 1024 ))
|
||||||
data_read="${tb_read_int}.${tb_read_dec} TB"
|
data_read="${tb_read_int}.${tb_read_dec} TB"
|
||||||
|
|
@ -198,12 +187,12 @@ main() {
|
||||||
data_info="Data: R:${data_read} W:${data_written}"
|
data_info="Data: R:${data_read} W:${data_written}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check for errors (similar to NVMe's unsafe shutdowns and media errors)
|
# Check for various error indicators
|
||||||
local program_fail erase_fail reallocated power_cycles
|
local power_cycles reallocated pending_sectors offline_uncorrectable
|
||||||
program_fail=$(echo "$smart_data" | awk '/Program_Fail_Count/ {print $10}' | head -1)
|
|
||||||
erase_fail=$(echo "$smart_data" | awk '/Erase_Fail_Count/ {print $10}' | head -1)
|
|
||||||
reallocated=$(echo "$smart_data" | awk '/Reallocated_Sector_Ct/ {print $10}' | head -1)
|
|
||||||
power_cycles=$(echo "$smart_data" | awk '/Power_Cycle_Count/ {print $10}' | head -1)
|
power_cycles=$(echo "$smart_data" | awk '/Power_Cycle_Count/ {print $10}' | head -1)
|
||||||
|
reallocated=$(echo "$smart_data" | awk '/Reallocated_Sector_Ct/ {print $10}' | head -1)
|
||||||
|
pending_sectors=$(echo "$smart_data" | awk '/Current_Pending_Sector/ {print $10}' | head -1)
|
||||||
|
offline_uncorrectable=$(echo "$smart_data" | awk '/Offline_Uncorrectable/ {print $10}' | head -1)
|
||||||
|
|
||||||
local error_parts=()
|
local error_parts=()
|
||||||
if [[ -n "$power_cycles" && "$power_cycles" -gt 0 ]]; then
|
if [[ -n "$power_cycles" && "$power_cycles" -gt 0 ]]; then
|
||||||
|
|
@ -212,38 +201,15 @@ main() {
|
||||||
if [[ -n "$reallocated" && "$reallocated" -gt 0 ]]; then
|
if [[ -n "$reallocated" && "$reallocated" -gt 0 ]]; then
|
||||||
error_parts+=("Reallocated:$reallocated")
|
error_parts+=("Reallocated:$reallocated")
|
||||||
fi
|
fi
|
||||||
if [[ -n "$program_fail" && "$program_fail" -gt 0 ]]; then
|
if [[ -n "$pending_sectors" && "$pending_sectors" -gt 0 ]]; then
|
||||||
error_parts+=("ProgramFails:$program_fail")
|
error_parts+=("PendingSectors:$pending_sectors")
|
||||||
fi
|
fi
|
||||||
if [[ -n "$erase_fail" && "$erase_fail" -gt 0 ]]; then
|
if [[ -n "$offline_uncorrectable" && "$offline_uncorrectable" -gt 0 ]]; then
|
||||||
error_parts+=("EraseFails:$erase_fail")
|
error_parts+=("OfflineUncorrectable:$offline_uncorrectable")
|
||||||
fi
|
fi
|
||||||
if [[ ${#error_parts[@]} -gt 0 ]]; then
|
if [[ ${#error_parts[@]} -gt 0 ]]; then
|
||||||
error_info=$(IFS=' '; echo "${error_parts[*]}")
|
error_info=$(IFS=' '; echo "${error_parts[*]}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
elif [[ "$drive_type" == "HDD" ]]; then
|
|
||||||
# HDD specific attributes
|
|
||||||
temp=$(echo "$smart_data" | awk '/Temperature_Celsius/ {print $10}' | head -1)
|
|
||||||
if [[ -n "$temp" && "$temp" =~ ^[0-9]+$ ]]; then
|
|
||||||
temp="${temp}C"
|
|
||||||
else
|
|
||||||
temp="N/A"
|
|
||||||
fi
|
|
||||||
|
|
||||||
power_hours=$(echo "$smart_data" | awk '/Power_On_Hours/ {print $10}' | head -1)
|
|
||||||
|
|
||||||
local reallocated
|
|
||||||
reallocated=$(echo "$smart_data" | awk '/Reallocated_Sector_Ct/ {print $10}' | head -1)
|
|
||||||
if [[ -n "$reallocated" ]]; then
|
|
||||||
wear_info="Reallocated:$reallocated"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local power_cycles
|
|
||||||
power_cycles=$(echo "$smart_data" | awk '/Power_Cycle_Count/ {print $10}' | head -1)
|
|
||||||
if [[ -n "$power_cycles" ]]; then
|
|
||||||
data_info="PowerCycles:$power_cycles"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo " Temperature: $temp"
|
echo " Temperature: $temp"
|
||||||
|
|
@ -255,7 +221,7 @@ main() {
|
||||||
|
|
||||||
# Format output
|
# Format output
|
||||||
if [[ "$health" == "PASSED" ]]; then
|
if [[ "$health" == "PASSED" ]]; then
|
||||||
report+="[OK] $device_name ($drive_type): $health\\n"
|
report+="[OK] $device_name: $health\\n"
|
||||||
report+=" Temp: $temp"
|
report+=" Temp: $temp"
|
||||||
if [[ "$power_hours" != "N/A" ]]; then
|
if [[ "$power_hours" != "N/A" ]]; then
|
||||||
report+=", PowerOn: ${power_hours}h"
|
report+=", PowerOn: ${power_hours}h"
|
||||||
|
|
@ -272,7 +238,7 @@ main() {
|
||||||
fi
|
fi
|
||||||
healthy_drives=$((healthy_drives + 1))
|
healthy_drives=$((healthy_drives + 1))
|
||||||
else
|
else
|
||||||
report+="[FAIL] $device_name ($drive_type): $health\\n"
|
report+="[FAIL] $device_name: $health\\n"
|
||||||
if [[ "$temp" != "N/A" ]]; then
|
if [[ "$temp" != "N/A" ]]; then
|
||||||
report+=" Temp: $temp\\n"
|
report+=" Temp: $temp\\n"
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue