From 14598af614535e0fba165bc11a54eeeae9dd20a6 Mon Sep 17 00:00:00 2001 From: Satakun Utama Date: Thu, 15 Oct 2026 21:07:13 +0700 Subject: [PATCH] Improve organization & SAS support --- components/nvme.php | 33 ++++ components/sat.php | 27 ++++ device.php | 53 ++---- resources/smartctl-proxy.sh | 8 - resources/sudoers | 2 +- sakura.css | 315 +++++++++++++++++++----------------- 6 files changed, 249 insertions(+), 189 deletions(-) create mode 100644 components/nvme.php create mode 100644 components/sat.php delete mode 100755 resources/smartctl-proxy.sh diff --git a/components/nvme.php b/components/nvme.php new file mode 100644 index 0000000..db3a467 --- /dev/null +++ b/components/nvme.php @@ -0,0 +1,33 @@ +nvme_smart_health_information_log; ?> +

SMART data

+ + + + + + + + + + + + + + + + + + +
PropertyValue
Data Units Readdata_units_read) . + " (" . + data_unit($health->data_units_read) . + ")" ?>
Data Units Writtendata_units_written) . + " (" . + data_unit($health->data_units_written) . + ")" ?>
+ diff --git a/components/sat.php b/components/sat.php new file mode 100644 index 0000000..5ea3794 --- /dev/null +++ b/components/sat.php @@ -0,0 +1,27 @@ +ata_smart_self_test_log->standard->table; ?> +

SMART self-test log

+ + + + + + + + + + + + + + + + + + +
TypeStatusLifetime (hours)
type->string ?>status->string ?>lifetime_hours ?>
+ diff --git a/device.php b/device.php index 586fa9c..823aad0 100644 --- a/device.php +++ b/device.php @@ -1,4 +1,7 @@ ["pipe", "w"]], $pipes); if (!is_resource($proc)) { @@ -17,10 +27,7 @@ function get_data() fclose($pipes[1]); $retval = proc_close($proc); - if ($retval == 0) { - return json_decode($data); - } - return $data . "\nProcess exited with $retval"; + return json_decode($data); } const NVME_DATA_UNIT = 1000 * 512; @@ -81,37 +88,11 @@ $data = get_data(); -

SMART data

- - - - - - - - - - device->type == "nvme") { - $health = $data->nvme_smart_health_information_log; ?> - - - - - - - - - - - -
PropertyValue
Data Units Readdata_units_read) . - " (" . - data_unit($health->data_units_read) . - ")" ?>
Data Units Writtendata_units_written) . - " (" . - data_unit($health->data_units_written) . - ")" ?>
+ device->type == "nvme") { + nvme_data($data); + } elseif ($data->device->type == "sat") { + sat_data($data); + } ?>
Original Output diff --git a/resources/smartctl-proxy.sh b/resources/smartctl-proxy.sh deleted file mode 100755 index 647e560..0000000 --- a/resources/smartctl-proxy.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -dev="${1:-}" - -exec /usr/bin/smartctl --json=co -a "/dev/$dev" - diff --git a/resources/sudoers b/resources/sudoers index ed61143..da75fbb 100644 --- a/resources/sudoers +++ b/resources/sudoers @@ -1 +1 @@ -linesofcodes ALL=(root) NOPASSWD: /usr/local/sbin/smartctl-proxy.sh sd[a-z], /usr/local/sbin/smartctl-proxy.sh nvme[0-9]n[0-9] +linesofcodes ALL=(root) NOPASSWD: /usr/bin/smartctl diff --git a/sakura.css b/sakura.css index 7d1886a..7c65a84 100644 --- a/sakura.css +++ b/sakura.css @@ -5,239 +5,266 @@ */ /* Body */ html { - font-size: 62.5%; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 62.5%; + font-family: + -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", + Arial, "Noto Sans", sans-serif; } body { - font-size: 1.8rem; - line-height: 1.618; - max-width: 38em; - margin: auto; - color: #4a4a4a; - background-color: #f9f9f9; - padding: 13px; + font-size: 1.8rem; + line-height: 1.618; + max-width: 48em; + margin: auto; + color: #4a4a4a; + background-color: #f9f9f9; + padding: 13px; } @media (max-width: 684px) { - body { - font-size: 1.53rem; - } + body { + font-size: 1.53rem; + } } @media (max-width: 382px) { - body { - font-size: 1.35rem; - } + body { + font-size: 1.35rem; + } } -h1, h2, h3, h4, h5, h6 { - line-height: 1.1; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; - font-weight: 700; - margin-top: 3rem; - margin-bottom: 1.5rem; - overflow-wrap: break-word; - word-wrap: break-word; - -ms-word-break: break-all; - word-break: break-word; +h1, +h2, +h3, +h4, +h5, +h6 { + line-height: 1.1; + font-family: + -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", + Arial, "Noto Sans", sans-serif; + font-weight: 700; + margin-top: 3rem; + margin-bottom: 1.5rem; + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; } h1 { - font-size: 2.35em; + font-size: 2.35em; } h2 { - font-size: 2em; + font-size: 2em; } h3 { - font-size: 1.75em; + font-size: 1.75em; } h4 { - font-size: 1.5em; + font-size: 1.5em; } h5 { - font-size: 1.25em; + font-size: 1.25em; } h6 { - font-size: 1em; + font-size: 1em; } p { - margin-top: 0px; - margin-bottom: 2.5rem; + margin-top: 0px; + margin-bottom: 2.5rem; } -small, sub, sup { - font-size: 75%; +small, +sub, +sup { + font-size: 75%; } hr { - border-color: #1d7484; + border-color: #1d7484; } a { - text-decoration: none; - color: #1d7484; + text-decoration: none; + color: #1d7484; } a:visited { - color: #144f5a; + color: #144f5a; } a:hover { - color: #982c61; - border-bottom: 2px solid #4a4a4a; + color: #982c61; + border-bottom: 2px solid #4a4a4a; } ul { - padding-left: 1.4em; - margin-top: 0px; - margin-bottom: 2.5rem; + padding-left: 1.4em; + margin-top: 0px; + margin-bottom: 2.5rem; } li { - margin-bottom: 0.4em; + margin-bottom: 0.4em; } blockquote { - margin-left: 0px; - margin-right: 0px; - padding-left: 1em; - padding-top: 0.8em; - padding-bottom: 0.8em; - padding-right: 0.8em; - border-left: 5px solid #1d7484; - margin-bottom: 2.5rem; - background-color: #f1f1f1; + margin-left: 0px; + margin-right: 0px; + padding-left: 1em; + padding-top: 0.8em; + padding-bottom: 0.8em; + padding-right: 0.8em; + border-left: 5px solid #1d7484; + margin-bottom: 2.5rem; + background-color: #f1f1f1; } blockquote p { - margin-bottom: 0; + margin-bottom: 0; } -img, video { - height: auto; - max-width: 100%; - margin-top: 0px; - margin-bottom: 2.5rem; +img, +video { + height: auto; + max-width: 100%; + margin-top: 0px; + margin-bottom: 2.5rem; } /* Pre and Code */ pre { - background-color: #f1f1f1; - display: block; - padding: 1em; - overflow-x: auto; - margin-top: 0px; - margin-bottom: 2.5rem; - font-size: 0.9em; + background-color: #f1f1f1; + display: block; + padding: 1em; + overflow-x: auto; + margin-top: 0px; + margin-bottom: 2.5rem; + font-size: 0.9em; } -code, kbd, samp { - font-size: 0.9em; - padding: 0 0.5em; - background-color: #f1f1f1; - white-space: pre-wrap; +code, +kbd, +samp { + font-size: 0.9em; + padding: 0 0.5em; + background-color: #f1f1f1; + white-space: pre-wrap; } pre > code { - padding: 0; - background-color: transparent; - white-space: pre; - font-size: 1em; + padding: 0; + background-color: transparent; + white-space: pre; + font-size: 1em; } /* Tables */ table { - text-align: justify; - width: 100%; - border-collapse: collapse; - margin-bottom: 2rem; + text-align: justify; + width: 100%; + border-collapse: collapse; + margin-bottom: 2rem; } -td, th { - padding: 0.5em; - border-bottom: 1px solid #f1f1f1; +td, +th { + padding: 0.5em; + border-bottom: 1px solid #f1f1f1; } /* Buttons, forms and input */ -input, textarea { - border: 1px solid #4a4a4a; +input, +textarea { + border: 1px solid #4a4a4a; } -input:focus, textarea:focus { - border: 1px solid #1d7484; +input:focus, +textarea:focus { + border: 1px solid #1d7484; } textarea { - width: 100%; + width: 100%; } -.button, button, -input[type=submit], -input[type=reset], -input[type=button], -input[type=file]::file-selector-button { - display: inline-block; - padding: 5px 10px; - text-align: center; - text-decoration: none; - white-space: nowrap; - background-color: #1d7484; - color: #f9f9f9; - border-radius: 1px; - border: 1px solid #1d7484; - cursor: pointer; - box-sizing: border-box; +.button, +button, +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="file"]::file-selector-button { + display: inline-block; + padding: 5px 10px; + text-align: center; + text-decoration: none; + white-space: nowrap; + background-color: #1d7484; + color: #f9f9f9; + border-radius: 1px; + border: 1px solid #1d7484; + cursor: pointer; + box-sizing: border-box; } -.button:hover, button:hover, -input[type=submit]:hover, -input[type=reset]:hover, -input[type=button]:hover, -input[type=file]::file-selector-button:hover { - background-color: #982c61; - color: #f9f9f9; - outline: 0; +.button:hover, +button:hover, +input[type="submit"]:hover, +input[type="reset"]:hover, +input[type="button"]:hover, +input[type="file"]::file-selector-button:hover { + background-color: #982c61; + color: #f9f9f9; + outline: 0; } -.button[disabled], button[disabled], -input[type=submit][disabled], -input[type=reset][disabled], -input[type=button][disabled], -input[type=file][disabled] { - cursor: default; - opacity: 0.5; +.button[disabled], +button[disabled], +input[type="submit"][disabled], +input[type="reset"][disabled], +input[type="button"][disabled], +input[type="file"][disabled] { + cursor: default; + opacity: 0.5; } -.button:focus-visible, button:focus-visible, -input[type=submit]:focus-visible, -input[type=reset]:focus-visible, -input[type=button]:focus-visible, -input[type=file]:focus-visible { - outline-style: solid; - outline-width: 2px; +.button:focus-visible, +button:focus-visible, +input[type="submit"]:focus-visible, +input[type="reset"]:focus-visible, +input[type="button"]:focus-visible, +input[type="file"]:focus-visible { + outline-style: solid; + outline-width: 2px; } -textarea, select, input { - color: #4a4a4a; - padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */ - margin-bottom: 10px; - background-color: #f1f1f1; - border: 1px solid #f1f1f1; - border-radius: 4px; - box-shadow: none; - box-sizing: border-box; +textarea, +select, +input { + color: #4a4a4a; + padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */ + margin-bottom: 10px; + background-color: #f1f1f1; + border: 1px solid #f1f1f1; + border-radius: 4px; + box-shadow: none; + box-sizing: border-box; } -textarea:focus, select:focus, input:focus { - border: 1px solid #1d7484; - outline: 0; +textarea:focus, +select:focus, +input:focus { + border: 1px solid #1d7484; + outline: 0; } -input[type=checkbox]:focus { - outline: 1px dotted #1d7484; +input[type="checkbox"]:focus { + outline: 1px dotted #1d7484; } -label, legend, fieldset { - display: block; - margin-bottom: 0.5rem; - font-weight: 600; +label, +legend, +fieldset { + display: block; + margin-bottom: 0.5rem; + font-weight: 600; }