diskreport.sh
· 11 KiB · Bash
Raw
#!/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; s/>/\>/g'
}
cat << EOF > "$OUTPUT"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DiskReport</title>
<style>
:root {
--bg-color: #0f0f0f;
--box-bg: #1a1a1a;
--raw-bg: #0a0a0a;
--text-color: #d3d7cf;
--pass-color: #8ae234;
--fail-color: #ef2929;
--warn-color: #fce94f;
--link-color: #729fcf;
--border-color: #333333;
--muted-color: #888a85;
}
* {
scrollbar-width: thin;
scrollbar-color: var(--border-color) var(--bg-color);
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: var(--bg-color);
}
::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--muted-color);
}
html, body {
min-height: 100vh;
margin: 0;
padding: 0;
background-color: var(--bg-color);
color: var(--text-color);
font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "Courier New", monospace;
font-size: 16px;
line-height: 1.5;
}
body {
display: flex;
justify-content: center;
align-items: flex-start;
padding: 2rem;
box-sizing: border-box;
}
.container {
margin: auto;
width: 100%;
max-width: 800px;
}
.header-box {
border: 2px solid var(--pass-color);
text-align: center;
padding: 1.5rem;
border-radius: 8px;
margin-bottom: 2rem;
background: var(--box-bg);
box-shadow: 0 4px 6px rgba(0,0,0,0.3);
}
.header-title {
color: var(--pass-color);
margin: 0 0 0.5rem 0;
font-size: 2rem;
letter-spacing: 2px;
text-transform: uppercase;
}
.header-date {
color: var(--muted-color);
font-size: 0.9rem;
}
.drive-box {
margin-bottom: 2rem;
background: var(--box-bg);
padding: 1.5rem;
border-radius: 8px;
border: 1px solid var(--border-color);
box-shadow: 0 4px 6px rgba(0,0,0,0.3);
}
.pass { color: var(--pass-color); font-weight: bold; }
.fail { color: var(--fail-color); font-weight: bold; }
.warn { color: var(--warn-color); font-weight: bold; }
pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
summary {
cursor: pointer;
color: var(--link-color);
margin-top: 1.5rem;
outline: none;
font-weight: bold;
user-select: none;
transition: color 0.2s ease;
}
summary:hover { color: #ffffff; }
.raw-data {
color: var(--muted-color);
font-size: 14px;
margin-top: 1rem;
padding: 1rem;
background: var(--raw-bg);
border-left: 3px solid var(--border-color);
overflow-x: auto;
white-space: pre;
}
.raw-data::-webkit-scrollbar-track {
background: var(--raw-bg);
}
</style>
</head>
<body>
<div class="container">
<div class="header-box">
<h1 class="header-title">DiskReport</h1>
<div class="header-date">GENERATED: $(date)</div>
</div>
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="<span class='pass'>OK</span>"
else
health_fmt="<span class='fail'>${health:-FAIL/UNKNOWN}</span>"
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="<span class='pass'>${health_pct}% (Excellent)</span>"
elif [ "$health_pct" -ge 50 ]; then health_str="<span class='warn'>${health_pct}% (Good)</span>"
elif [ "$health_pct" -ge 20 ]; then health_str="<span class='warn'>${health_pct}% (Fair)</span>"
else health_str="<span class='fail'>${health_pct}% (Poor)</span>"
fi
else
if [[ "$health" == *"PASSED"* || "$health" == *"OK"* ]]; then
health_str="<span class='pass'>100% (Excellent)</span>"
else
health_str="<span class='fail'>0% (Failing)</span>"
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="<span class='pass'>100% (Excellent)</span>"
elif [ "$perf_pct" -ge 80 ]; then
perf_str="<span class='warn'>${perf_pct}%${perf_reason}</span>"
else
perf_str="<span class='fail'>${perf_pct}%${perf_reason}</span>"
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"
<div class='drive-box'>
<pre>
==========================================================
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
==========================================================
</pre>
<details>
<summary>raw</summary>
<pre class='raw-data'>$safe_raw</pre>
</details>
</div>
EOF
fi
done
cat << 'EOF' >> "$OUTPUT"
</div>
</body>
</html>
EOF
echo "DiskReport generated: $(pwd)/$OUTPUT"
| 1 | #!/bin/bash |
| 2 | |
| 3 | if [ "$EUID" -ne 0 ]; then |
| 4 | echo "Error: This script must be run as root (e.g., sudo $0)" >&2 |
| 5 | exit 1 |
| 6 | fi |
| 7 | |
| 8 | if ! command -v smartctl >/dev/null 2>&1; then |
| 9 | echo "Error: smartctl is not installed." >&2 |
| 10 | exit 1 |
| 11 | fi |
| 12 | |
| 13 | OUTPUT="${1:-diskreport.html}" |
| 14 | |
| 15 | escape_html() { |
| 16 | sed 's/&/\&/g; s/</\</g; s/>/\>/g' |
| 17 | } |
| 18 | |
| 19 | cat << EOF > "$OUTPUT" |
| 20 | <!DOCTYPE html> |
| 21 | <html lang="en"> |
| 22 | <head> |
| 23 | <meta charset="UTF-8"> |
| 24 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 25 | <title>DiskReport</title> |
| 26 | <style> |
| 27 | :root { |
| 28 | --bg-color: #0f0f0f; |
| 29 | --box-bg: #1a1a1a; |
| 30 | --raw-bg: #0a0a0a; |
| 31 | --text-color: #d3d7cf; |
| 32 | --pass-color: #8ae234; |
| 33 | --fail-color: #ef2929; |
| 34 | --warn-color: #fce94f; |
| 35 | --link-color: #729fcf; |
| 36 | --border-color: #333333; |
| 37 | --muted-color: #888a85; |
| 38 | } |
| 39 | |
| 40 | * { |
| 41 | scrollbar-width: thin; |
| 42 | scrollbar-color: var(--border-color) var(--bg-color); |
| 43 | } |
| 44 | |
| 45 | ::-webkit-scrollbar { |
| 46 | width: 10px; |
| 47 | height: 10px; |
| 48 | } |
| 49 | ::-webkit-scrollbar-track { |
| 50 | background: var(--bg-color); |
| 51 | } |
| 52 | ::-webkit-scrollbar-thumb { |
| 53 | background: var(--border-color); |
| 54 | border-radius: 5px; |
| 55 | } |
| 56 | ::-webkit-scrollbar-thumb:hover { |
| 57 | background: var(--muted-color); |
| 58 | } |
| 59 | |
| 60 | html, body { |
| 61 | min-height: 100vh; |
| 62 | margin: 0; |
| 63 | padding: 0; |
| 64 | background-color: var(--bg-color); |
| 65 | color: var(--text-color); |
| 66 | font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "Courier New", monospace; |
| 67 | font-size: 16px; |
| 68 | line-height: 1.5; |
| 69 | } |
| 70 | body { |
| 71 | display: flex; |
| 72 | justify-content: center; |
| 73 | align-items: flex-start; |
| 74 | padding: 2rem; |
| 75 | box-sizing: border-box; |
| 76 | } |
| 77 | .container { |
| 78 | margin: auto; |
| 79 | width: 100%; |
| 80 | max-width: 800px; |
| 81 | } |
| 82 | .header-box { |
| 83 | border: 2px solid var(--pass-color); |
| 84 | text-align: center; |
| 85 | padding: 1.5rem; |
| 86 | border-radius: 8px; |
| 87 | margin-bottom: 2rem; |
| 88 | background: var(--box-bg); |
| 89 | box-shadow: 0 4px 6px rgba(0,0,0,0.3); |
| 90 | } |
| 91 | .header-title { |
| 92 | color: var(--pass-color); |
| 93 | margin: 0 0 0.5rem 0; |
| 94 | font-size: 2rem; |
| 95 | letter-spacing: 2px; |
| 96 | text-transform: uppercase; |
| 97 | } |
| 98 | .header-date { |
| 99 | color: var(--muted-color); |
| 100 | font-size: 0.9rem; |
| 101 | } |
| 102 | .drive-box { |
| 103 | margin-bottom: 2rem; |
| 104 | background: var(--box-bg); |
| 105 | padding: 1.5rem; |
| 106 | border-radius: 8px; |
| 107 | border: 1px solid var(--border-color); |
| 108 | box-shadow: 0 4px 6px rgba(0,0,0,0.3); |
| 109 | } |
| 110 | .pass { color: var(--pass-color); font-weight: bold; } |
| 111 | .fail { color: var(--fail-color); font-weight: bold; } |
| 112 | .warn { color: var(--warn-color); font-weight: bold; } |
| 113 | pre { |
| 114 | margin: 0; |
| 115 | white-space: pre-wrap; |
| 116 | word-wrap: break-word; |
| 117 | } |
| 118 | summary { |
| 119 | cursor: pointer; |
| 120 | color: var(--link-color); |
| 121 | margin-top: 1.5rem; |
| 122 | outline: none; |
| 123 | font-weight: bold; |
| 124 | user-select: none; |
| 125 | transition: color 0.2s ease; |
| 126 | } |
| 127 | summary:hover { color: #ffffff; } |
| 128 | .raw-data { |
| 129 | color: var(--muted-color); |
| 130 | font-size: 14px; |
| 131 | margin-top: 1rem; |
| 132 | padding: 1rem; |
| 133 | background: var(--raw-bg); |
| 134 | border-left: 3px solid var(--border-color); |
| 135 | overflow-x: auto; |
| 136 | white-space: pre; |
| 137 | } |
| 138 | |
| 139 | .raw-data::-webkit-scrollbar-track { |
| 140 | background: var(--raw-bg); |
| 141 | } |
| 142 | </style> |
| 143 | </head> |
| 144 | <body> |
| 145 | <div class="container"> |
| 146 | |
| 147 | <div class="header-box"> |
| 148 | <h1 class="header-title">DiskReport</h1> |
| 149 | <div class="header-date">GENERATED: $(date)</div> |
| 150 | </div> |
| 151 | EOF |
| 152 | |
| 153 | for disk in $(lsblk -nd -o NAME,TYPE | awk '$2=="disk" {print $1}'); do |
| 154 | dev="/dev/$disk" |
| 155 | |
| 156 | if smartctl -i "$dev" >/dev/null 2>&1; then |
| 157 | raw_output=$(smartctl -a "$dev") |
| 158 | |
| 159 | model=$(echo "$raw_output" | grep -iE "^Device Model:|^Product:|^Model Number:|^Vendor:" | head -n 1 | awk -F: '{print $2}' | xargs) |
| 160 | if [ -z "$model" ]; then |
| 161 | model=$(lsblk -n -d -o MODEL "$dev" | xargs) |
| 162 | fi |
| 163 | |
| 164 | interface=$(lsblk -n -d -o TRAN "$dev" | tr 'a-z' 'A-Z' | xargs) |
| 165 | if [ -z "$interface" ] || [ "$interface" = "UNKNOWN" ]; then |
| 166 | if echo "$raw_output" | grep -qi "Transport protocol:"; then |
| 167 | interface=$(echo "$raw_output" | grep -i "Transport protocol:" | awk -F: '{print $2}' | xargs | cut -d' ' -f1) |
| 168 | elif echo "$raw_output" | grep -qi "Protocol:.*NVM Express"; then |
| 169 | interface="NVMe" |
| 170 | elif echo "$raw_output" | grep -qi "SATA Version is:"; then |
| 171 | interface=$(echo "$raw_output" | grep -i "SATA Version is:" | awk -F: '{print $2}' | xargs | cut -d, -f1) |
| 172 | elif echo "$raw_output" | grep -qi "SCSI"; then |
| 173 | interface="SCSI" |
| 174 | else |
| 175 | interface="Unknown" |
| 176 | fi |
| 177 | fi |
| 178 | |
| 179 | health=$(echo "$raw_output" | grep -iE "test result:|Health Status:" | awk -F: '{print $2}' | xargs) |
| 180 | if [[ "$health" == *"PASSED"* || "$health" == *"OK"* ]]; then |
| 181 | health_fmt="<span class='pass'>OK</span>" |
| 182 | else |
| 183 | health_fmt="<span class='fail'>${health:-FAIL/UNKNOWN}</span>" |
| 184 | fi |
| 185 | |
| 186 | health_pct="" |
| 187 | pct_used=$(echo "$raw_output" | grep -i "^Percentage Used:" | awk '{print $3}' | tr -d '%') |
| 188 | if [ -z "$pct_used" ]; then |
| 189 | pct_used=$(echo "$raw_output" | grep -i "Percentage used endurance indicator:" | awk '{print $5}' | tr -d '%') |
| 190 | fi |
| 191 | |
| 192 | if [ -n "$pct_used" ] && [[ "$pct_used" =~ ^[0-9]+$ ]]; then |
| 193 | health_pct=$((100 - pct_used)) |
| 194 | else |
| 195 | wearout=$(echo "$raw_output" | grep -iE "^[ ]*(231|233|202|177|169)[ ]" | head -n 1 | awk '{print $4}') |
| 196 | if [ -n "$wearout" ] && [[ "$wearout" =~ ^[0-9]+$ ]]; then |
| 197 | health_pct=$((10#$wearout)) |
| 198 | fi |
| 199 | fi |
| 200 | |
| 201 | if [ -n "$health_pct" ]; then |
| 202 | if [ "$health_pct" -ge 80 ]; then health_str="<span class='pass'>${health_pct}% (Excellent)</span>" |
| 203 | elif [ "$health_pct" -ge 50 ]; then health_str="<span class='warn'>${health_pct}% (Good)</span>" |
| 204 | elif [ "$health_pct" -ge 20 ]; then health_str="<span class='warn'>${health_pct}% (Fair)</span>" |
| 205 | else health_str="<span class='fail'>${health_pct}% (Poor)</span>" |
| 206 | fi |
| 207 | else |
| 208 | if [[ "$health" == *"PASSED"* || "$health" == *"OK"* ]]; then |
| 209 | health_str="<span class='pass'>100% (Excellent)</span>" |
| 210 | else |
| 211 | health_str="<span class='fail'>0% (Failing)</span>" |
| 212 | fi |
| 213 | fi |
| 214 | |
| 215 | perf_pct=100 |
| 216 | perf_reason="" |
| 217 | |
| 218 | crc_err=$(echo "$raw_output" | grep -iE "^[ ]*199[ ]+UDMA_CRC_Error_Count" | awk '{print $10}') |
| 219 | if [[ -n "$crc_err" && "$crc_err" -gt 0 ]]; then |
| 220 | perf_pct=80 |
| 221 | perf_reason=" (Degraded - Cable/Interface Errors)" |
| 222 | fi |
| 223 | |
| 224 | nvme_err=$(echo "$raw_output" | grep -i "^Media and Data Integrity Errors:" | awk '{print $6}') |
| 225 | if [[ -n "$nvme_err" && "$nvme_err" -gt 0 ]]; then |
| 226 | perf_pct=70 |
| 227 | perf_reason=" (Degraded - Integrity Errors)" |
| 228 | fi |
| 229 | |
| 230 | scsi_defects=$(echo "$raw_output" | grep -i "Elements in grown defect list:" | awk -F: '{print $2}' | xargs) |
| 231 | if [[ -n "$scsi_defects" && "$scsi_defects" -gt 0 ]]; then |
| 232 | perf_pct=70 |
| 233 | perf_reason=" (Degraded - Grown Defects)" |
| 234 | fi |
| 235 | |
| 236 | realloc=$(echo "$raw_output" | grep -iE "^[ ]*5[ ]+Reallocated_Sector_Ct" | awk '{print $10}') |
| 237 | if [[ -n "$realloc" && "$realloc" -gt 0 ]]; then |
| 238 | if [ "$perf_pct" -gt 80 ]; then perf_pct=80; fi |
| 239 | perf_reason=" (Degraded - Reallocated Sectors)" |
| 240 | fi |
| 241 | |
| 242 | if [ "$perf_pct" -eq 100 ]; then |
| 243 | perf_str="<span class='pass'>100% (Excellent)</span>" |
| 244 | elif [ "$perf_pct" -ge 80 ]; then |
| 245 | perf_str="<span class='warn'>${perf_pct}%${perf_reason}</span>" |
| 246 | else |
| 247 | perf_str="<span class='fail'>${perf_pct}%${perf_reason}</span>" |
| 248 | fi |
| 249 | |
| 250 | temp=$(echo "$raw_output" | grep -iE "^Temperature:|^Current Drive Temperature:" | head -n 1 | awk -F: '{print $2}' | xargs) |
| 251 | |
| 252 | pwr_raw=$(echo "$raw_output" | grep -iE "Power On Hours|Accumulated power on time|number of hours powered up") |
| 253 | if echo "$pwr_raw" | grep -q "minutes"; then |
| 254 | pwr=$(echo "$pwr_raw" | awk -F'hours:minutes ' '{print $2}' | cut -d: -f1) |
| 255 | pwr="${pwr} Hours" |
| 256 | elif echo "$pwr_raw" | grep -qi "number of hours powered up"; then |
| 257 | pwr=$(echo "$pwr_raw" | awk -F= '{print $2}' | awk '{print $1}') |
| 258 | pwr="${pwr} Hours" |
| 259 | elif [ -n "$pwr_raw" ]; then |
| 260 | pwr=$(echo "$pwr_raw" | awk -F: '{print $2}' | xargs | sed 's/,//g') |
| 261 | pwr="${pwr} Hours" |
| 262 | else |
| 263 | pwr="N/A" |
| 264 | fi |
| 265 | |
| 266 | written="N/A" |
| 267 | if echo "$raw_output" | grep -q "Data Units Written:"; then |
| 268 | written=$(echo "$raw_output" | grep "Data Units Written:" | awk -F'[][]' '{print $2}') |
| 269 | elif echo "$raw_output" | grep -qi "gigabytes processed \[consume\]:"; then |
| 270 | gb_written=$(echo "$raw_output" | grep -i "gigabytes processed \[consume\]:" | awk '{print $4}') |
| 271 | written=$(awk -v gb="$gb_written" 'BEGIN { printf "%.2f TB", gb/1000 }') |
| 272 | elif echo "$raw_output" | grep -qiE "^[ ]*241[ ]+Total_LBAs_Written"; then |
| 273 | lbas=$(echo "$raw_output" | grep -iE "^[ ]*241[ ]+Total_LBAs_Written" | awk '{print $10}') |
| 274 | written=$(awk -v lbas="$lbas" 'BEGIN { printf "%.2f TB", (lbas * 512) / 1000000000000 }') |
| 275 | fi |
| 276 | |
| 277 | safe_dev=$(echo "$dev" | escape_html) |
| 278 | safe_model=$(echo "${model:-Unknown}" | escape_html) |
| 279 | safe_interface=$(echo "${interface:-Unknown}" | escape_html) |
| 280 | safe_temp=$(echo "${temp:-N/A}" | escape_html) |
| 281 | safe_pwr=$(echo "${pwr:-N/A}" | escape_html) |
| 282 | safe_written=$(echo "${written:-N/A}" | escape_html) |
| 283 | safe_raw=$(echo "$raw_output" | grep -v "Copyright" | grep -v "smartmontools.org" | escape_html) |
| 284 | |
| 285 | cat << EOF >> "$OUTPUT" |
| 286 | <div class='drive-box'> |
| 287 | <pre> |
| 288 | ========================================================== |
| 289 | DRIVE : $safe_dev |
| 290 | MODEL : $safe_model |
| 291 | INTERFACE : $safe_interface |
| 292 | ---------------------------------------------------------- |
| 293 | HEALTH : $health_str |
| 294 | PERFORMANCE : $perf_str |
| 295 | STATUS : $health_fmt |
| 296 | TEMP : $safe_temp |
| 297 | POWER ON : $safe_pwr |
| 298 | WRITTEN : $safe_written |
| 299 | ========================================================== |
| 300 | </pre> |
| 301 | <details> |
| 302 | <summary>raw</summary> |
| 303 | <pre class='raw-data'>$safe_raw</pre> |
| 304 | </details> |
| 305 | </div> |
| 306 | EOF |
| 307 | fi |
| 308 | done |
| 309 | |
| 310 | cat << 'EOF' >> "$OUTPUT" |
| 311 | </div> |
| 312 | </body> |
| 313 | </html> |
| 314 | EOF |
| 315 | |
| 316 | echo "DiskReport generated: $(pwd)/$OUTPUT" |
| 317 |