You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
4.1 KiB
108 lines
4.1 KiB
#!/usr/bin/env lua54
|
|
|
|
-- Adjust paths so we can run the test script straight from the root directory
|
|
package.cpath = package.cpath .. ";../modules/lua/?.so"
|
|
|
|
local sysctl = require("sysctl")
|
|
local bsdiskinfo = require("bsdiskinfo")
|
|
|
|
-- S.M.A.R.T. Attribute Dictionary inside Lua wrapper layer
|
|
local smart_names = {
|
|
[1] = "Raw_Read_Error_Rate",
|
|
[3] = "Spin_Up_Time",
|
|
[4] = "Start_Stop_Count",
|
|
[5] = "Reallocated_Sector_Ct",
|
|
[7] = "Seek_Error_Rate",
|
|
[9] = "Power_On_Hours",
|
|
[10] = "Spin_Retry_Count",
|
|
[12] = "Power_Cycle_Count",
|
|
[184] = "End-to-End_Error",
|
|
[187] = "Reported_Uncorrect",
|
|
[188] = "Command_Timeout",
|
|
[189] = "High_Fly_Writes",
|
|
[190] = "Airflow_Temperature_Cel",
|
|
[193] = "Load_Cycle_Count",
|
|
[194] = "Temperature_Celsius",
|
|
[195] = "Hardware_ECC_Recovered",
|
|
[197] = "Current_Pending_Sector",
|
|
[198] = "Offline_Uncorrectable",
|
|
[199] = "UDMA_CRC_Error_Count",
|
|
[240] = "Head_Flying_Hours",
|
|
[241] = "Total_LBAs_Written",
|
|
[242] = "Total_LBAs_Read"
|
|
}
|
|
|
|
-- Utility function to format raw byte capacities into human readable text standards
|
|
local function format_size(bytes)
|
|
if not bytes or bytes == 0 then return "N/A" end
|
|
local gib = bytes / (1024 * 1024 * 1024)
|
|
if gib >= 1024 then
|
|
return string.format("%.1f TiB", gib / 1024)
|
|
else
|
|
return string.format("%.1f GiB", gib)
|
|
end
|
|
end
|
|
|
|
-- 1. Read available physical storage device names from active sysctl trees
|
|
local disks_str = sysctl.get("kern.disks")
|
|
if not disks_str then
|
|
print("Error: Failed to query kern.disks via native sysctl module.")
|
|
os.exit(1)
|
|
end
|
|
|
|
-- Parse disk tokens into a sequential array table
|
|
local disks = {}
|
|
for disk in disks_str:gmatch("%S+") do
|
|
table.insert(disks, disk)
|
|
end
|
|
table.sort(disks)
|
|
|
|
print("=========================================================================")
|
|
print(" bsdiskinfo Nested Architecture Tree Map View Emulator")
|
|
print("=========================================================================\n")
|
|
|
|
-- 2. Traverse detected disk arrays to build structural mappings loops
|
|
for _, disk in ipairs(disks) do
|
|
local props = bsdiskinfo.get_properties(disk)
|
|
|
|
if props then
|
|
print(string.format("Drive node: /dev/%s [%s, %s]", disk, props.type, format_size(props.mediasize)))
|
|
print(string.format(" ├─ Model : %s", props.model))
|
|
print(string.format(" ├─ Serial : %s", props.serial))
|
|
print(string.format(" ├─ Firmware : %s", props.fw_version))
|
|
print(string.format(" └─ WWN : %s", props.wwn))
|
|
|
|
-- 3. Gather active mounted partition layout tables
|
|
local mounts = bsdiskinfo.get_mounts(disk)
|
|
if mounts and #mounts > 0 then
|
|
print(" ├── Active Mounted Volumes:")
|
|
for _, mnt in ipairs(mounts) do
|
|
print(string.format(" │ └─ /dev/%-7s -> %-20s (%s)", mnt.device, mnt.path, mnt.fstype))
|
|
end
|
|
else
|
|
print(" ├── Active Mounted Volumes: None detected")
|
|
end
|
|
|
|
-- 4. Gather telemetry attributes matrix records
|
|
if props.smart_supported then
|
|
local smart = bsdiskinfo.get_smart_counters(disk)
|
|
if smart and #smart > 0 then
|
|
-- Discover current live operational temperatures from matrix attributes
|
|
local temp = "N/A"
|
|
for _, attr in ipairs(smart) do
|
|
if attr.id == 194 or attr.id == 190 then
|
|
temp = string.format("%d°C", math.floor(attr.raw_val % 256) or attr.raw_val)
|
|
break
|
|
end
|
|
end
|
|
print(string.format(" └── S.M.A.R.T. Operational Status: Enabled [Temp: %s, Metrics: %d]", temp, #smart))
|
|
else
|
|
print(" └── S.M.A.R.T. Operational Status: Read Failed")
|
|
end
|
|
else
|
|
print(" └── S.M.A.R.T. Operational Status: Not Supported")
|
|
end
|
|
print("-------------------------------------------------------------------------")
|
|
end
|
|
end
|
|
|
|
|