#!/bin/bash if [ "$EUID" -ne 0 ]; then echo "Error: This script must be run as root (e.g., sudo $0)" >&2 exit 1 fi if ! command -v smartctl >/dev/null 2>&1; then echo "Error: smartctl is not installed." >&2 exit 1 fi OUTPUT="${1:-diskreport.html}" escape_html() { sed 's/&/\&/g; s//\>/g' } cat << EOF > "$OUTPUT" DiskReport

DiskReport

GENERATED: $(date)
EOF for disk in $(lsblk -nd -o NAME,TYPE | awk '$2=="disk" {print $1}'); do dev="/dev/$disk" if smartctl -i "$dev" >/dev/null 2>&1; then raw_output=$(smartctl -a "$dev") model=$(echo "$raw_output" | grep -iE "^Device Model:|^Product:|^Model Number:|^Vendor:" | head -n 1 | awk -F: '{print $2}' | xargs) if [ -z "$model" ]; then model=$(lsblk -n -d -o MODEL "$dev" | xargs) fi interface=$(lsblk -n -d -o TRAN "$dev" | tr 'a-z' 'A-Z' | xargs) if [ -z "$interface" ] || [ "$interface" = "UNKNOWN" ]; then if echo "$raw_output" | grep -qi "Transport protocol:"; then interface=$(echo "$raw_output" | grep -i "Transport protocol:" | awk -F: '{print $2}' | xargs | cut -d' ' -f1) elif echo "$raw_output" | grep -qi "Protocol:.*NVM Express"; then interface="NVMe" elif echo "$raw_output" | grep -qi "SATA Version is:"; then interface=$(echo "$raw_output" | grep -i "SATA Version is:" | awk -F: '{print $2}' | xargs | cut -d, -f1) elif echo "$raw_output" | grep -qi "SCSI"; then interface="SCSI" else interface="Unknown" fi fi health=$(echo "$raw_output" | grep -iE "test result:|Health Status:" | awk -F: '{print $2}' | xargs) if [[ "$health" == *"PASSED"* || "$health" == *"OK"* ]]; then health_fmt="OK" else health_fmt="${health:-FAIL/UNKNOWN}" fi health_pct="" pct_used=$(echo "$raw_output" | grep -i "^Percentage Used:" | awk '{print $3}' | tr -d '%') if [ -z "$pct_used" ]; then pct_used=$(echo "$raw_output" | grep -i "Percentage used endurance indicator:" | awk '{print $5}' | tr -d '%') fi if [ -n "$pct_used" ] && [[ "$pct_used" =~ ^[0-9]+$ ]]; then health_pct=$((100 - pct_used)) else wearout=$(echo "$raw_output" | grep -iE "^[ ]*(231|233|202|177|169)[ ]" | head -n 1 | awk '{print $4}') if [ -n "$wearout" ] && [[ "$wearout" =~ ^[0-9]+$ ]]; then health_pct=$((10#$wearout)) fi fi if [ -n "$health_pct" ]; then if [ "$health_pct" -ge 80 ]; then health_str="${health_pct}% (Excellent)" elif [ "$health_pct" -ge 50 ]; then health_str="${health_pct}% (Good)" elif [ "$health_pct" -ge 20 ]; then health_str="${health_pct}% (Fair)" else health_str="${health_pct}% (Poor)" fi else if [[ "$health" == *"PASSED"* || "$health" == *"OK"* ]]; then health_str="100% (Excellent)" else health_str="0% (Failing)" fi fi perf_pct=100 perf_reason="" crc_err=$(echo "$raw_output" | grep -iE "^[ ]*199[ ]+UDMA_CRC_Error_Count" | awk '{print $10}') if [[ -n "$crc_err" && "$crc_err" -gt 0 ]]; then perf_pct=80 perf_reason=" (Degraded - Cable/Interface Errors)" fi nvme_err=$(echo "$raw_output" | grep -i "^Media and Data Integrity Errors:" | awk '{print $6}') if [[ -n "$nvme_err" && "$nvme_err" -gt 0 ]]; then perf_pct=70 perf_reason=" (Degraded - Integrity Errors)" fi scsi_defects=$(echo "$raw_output" | grep -i "Elements in grown defect list:" | awk -F: '{print $2}' | xargs) if [[ -n "$scsi_defects" && "$scsi_defects" -gt 0 ]]; then perf_pct=70 perf_reason=" (Degraded - Grown Defects)" fi realloc=$(echo "$raw_output" | grep -iE "^[ ]*5[ ]+Reallocated_Sector_Ct" | awk '{print $10}') if [[ -n "$realloc" && "$realloc" -gt 0 ]]; then if [ "$perf_pct" -gt 80 ]; then perf_pct=80; fi perf_reason=" (Degraded - Reallocated Sectors)" fi if [ "$perf_pct" -eq 100 ]; then perf_str="100% (Excellent)" elif [ "$perf_pct" -ge 80 ]; then perf_str="${perf_pct}%${perf_reason}" else perf_str="${perf_pct}%${perf_reason}" fi temp=$(echo "$raw_output" | grep -iE "^Temperature:|^Current Drive Temperature:" | head -n 1 | awk -F: '{print $2}' | xargs) pwr_raw=$(echo "$raw_output" | grep -iE "Power On Hours|Accumulated power on time|number of hours powered up") if echo "$pwr_raw" | grep -q "minutes"; then pwr=$(echo "$pwr_raw" | awk -F'hours:minutes ' '{print $2}' | cut -d: -f1) pwr="${pwr} Hours" elif echo "$pwr_raw" | grep -qi "number of hours powered up"; then pwr=$(echo "$pwr_raw" | awk -F= '{print $2}' | awk '{print $1}') pwr="${pwr} Hours" elif [ -n "$pwr_raw" ]; then pwr=$(echo "$pwr_raw" | awk -F: '{print $2}' | xargs | sed 's/,//g') pwr="${pwr} Hours" else pwr="N/A" fi written="N/A" if echo "$raw_output" | grep -q "Data Units Written:"; then written=$(echo "$raw_output" | grep "Data Units Written:" | awk -F'[][]' '{print $2}') elif echo "$raw_output" | grep -qi "gigabytes processed \[consume\]:"; then gb_written=$(echo "$raw_output" | grep -i "gigabytes processed \[consume\]:" | awk '{print $4}') written=$(awk -v gb="$gb_written" 'BEGIN { printf "%.2f TB", gb/1000 }') elif echo "$raw_output" | grep -qiE "^[ ]*241[ ]+Total_LBAs_Written"; then lbas=$(echo "$raw_output" | grep -iE "^[ ]*241[ ]+Total_LBAs_Written" | awk '{print $10}') written=$(awk -v lbas="$lbas" 'BEGIN { printf "%.2f TB", (lbas * 512) / 1000000000000 }') fi safe_dev=$(echo "$dev" | escape_html) safe_model=$(echo "${model:-Unknown}" | escape_html) safe_interface=$(echo "${interface:-Unknown}" | escape_html) safe_temp=$(echo "${temp:-N/A}" | escape_html) safe_pwr=$(echo "${pwr:-N/A}" | escape_html) safe_written=$(echo "${written:-N/A}" | escape_html) safe_raw=$(echo "$raw_output" | grep -v "Copyright" | grep -v "smartmontools.org" | escape_html) cat << EOF >> "$OUTPUT"
==========================================================
 DRIVE        : $safe_dev
 MODEL        : $safe_model
 INTERFACE    : $safe_interface
----------------------------------------------------------
 HEALTH       : $health_str
 PERFORMANCE  : $perf_str
 STATUS       : $health_fmt
 TEMP         : $safe_temp
 POWER ON     : $safe_pwr
 WRITTEN      : $safe_written
==========================================================
raw
$safe_raw
EOF fi done cat << 'EOF' >> "$OUTPUT"
EOF echo "DiskReport generated: $(pwd)/$OUTPUT"