Skip to content

Instantly share code, notes, and snippets.

@ZeroDot1
Created May 23, 2025 16:44
Show Gist options
  • Save ZeroDot1/3030fba09c049ccdcb1c7cbeec099543 to your computer and use it in GitHub Desktop.
Save ZeroDot1/3030fba09c049ccdcb1c7cbeec099543 to your computer and use it in GitHub Desktop.
SmartDriveCheckNG.sh: A Bash script for Arch Linux to generate detailed SMART/NVMe health reports for storage devices. Combines essential commands for quick status checks. Contributions via pull requests are welcome! Licensed under AGPLv3.

SmartDriveCheckNG

A Bash script for Arch Linux to generate detailed SMART/NVMe health reports for storage devices, including HDDs, SSDs, NVMe drives, floppies, and CDROMs. It combines essential commands to quickly check drive health, categorized as Healthy, Critical, or Failed, and saves reports in /tmp.

Purpose

I wrote this script to quickly and easily generate a status report on the health of my storage devices. The script combines all the commands that are personally important to me. Anyone who wants to contribute can make a pull request. I appreciate every contribution. Thanks to all the developers of the software used.

Features

  • Device Discovery: Scans all block devices using lsblk.
  • Interactive Menu: Allows users to select a device for health checking.
  • Comprehensive Reports: Generates reports with:
    • Device details (model, serial, firmware, capacity).
    • Health status (Healthy, Critical, Failed).
    • System information (CPU, memory, GPU, motherboard, BIOS).
    • Commands used and their outputs (smartctl or nvme-cli).
  • NVMe Support: Offers a choice between smartctl and nvme-cli for NVMe drives.
  • Report Storage: Saves reports in /tmp with timestamps and debug status.
  • Debug Mode: Run with --debug for verbose logging.
  • Dependency Management: Uses non-root yay for installing dependencies, with sudo for privileged operations.
  • License: Licensed under the GNU Affero General Public License v3 (AGPLv3).

Requirements

  • Operating System: Arch Linux
  • Dependencies:
    • smartmontools (provides smartctl)
    • util-linux (provides lsblk, numfmt, column)
    • procps-ng, pciutils (provide lscpu, free, lspci)
    • dmidecode
    • yay (AUR helper, must be installed manually as a non-root user)
    • leafpad (optional, for GUI report viewing)
    • nvme-cli (for NVMe drives)
  • Permissions: Some commands require sudo (configured automatically).

Installation

  1. Download the Script:

    curl -O https://gist.githubusercontent.com/ZeroDot1/<GIST_ID>/raw/SmartDriveCheckNG.sh

    Replace <GIST_ID> with the actual Gist ID.

  2. Make it Executable:

    chmod +x SmartDriveCheckNG.sh
  3. Install Dependencies: As a non-root user:

    yay -S smartmontools util-linux procps-ng pciutils dmidecode nvme-cli leafpad

    If running as root, use pacman:

    sudo pacman -S smartmontools util-linux procps-ng pciutils dmidecode nvme-cli leafpad

    Install yay manually if not present: https://aur.archlinux.org/yay.

Usage

Run the script:

./SmartDriveCheckNG.sh [--debug]
  • Use --debug to enable verbose logging.
  • Follow the interactive menu to select a drive.
  • For NVMe drives, choose between smartctl (recommended) or nvme-cli for health checks.
  • Reports are saved in /tmp/smart_report_XXXXXX.txt and displayed using leafpad (if installed), less, or cat.

Example Run

$ ./SmartDriveCheckNG.sh
======================================================
SmartDriveCheckNG - Drive Health Check Utility
A minimalist tool for SMART/NVMe reports on Arch Linux
Author: ZeroDot1 https://github.com/ZeroDot1
======================================================
INFO: Using sudo for privileged operations.
INFO: All dependencies satisfied.
INFO: Scanning drives...

--- Available Drives ---
1) /dev/nvme0n1 - Samsung SSD 990 EVO Plus 4TB (4.00TiB, Type: disk)
2) /dev/sda - ST2000DM008-2FR102 (2.00TiB, Type: disk)
3) Quit

Select a drive (or "q" to quit):

Example Report

Below is a sample report for an NVMe drive:

======================================================
SmartDriveCheckNG - Drive Health Report
======================================================
Generated: 2025-05-23 18:19:05 CEST
Debug Mode: YES
Author: ZeroDot1 <https://github.com/ZeroDot1>

--- Device Info ---
Path: /dev/nvme0n1
Model: Samsung SSD 990 EVO Plus 4TB
Serial: XXXXXXXXXXXXX
Firmware: XXXXXXXXX
Capacity: 4,000,787,030,016 [4.00 TB]

--- Health Assessment ---
Health Status: Healthy
Recommendation: Drive is healthy. Regular checks recommended.

--- System Info ---
Kernel: 6.14.6-2-cachyos
Hostname: archlinux
Uptime: up 477 days, 9 hours
--- CPU ---
Architecture: x86_64
Model name: Intel Cor i7 12700K
CPU(s): 12
--- Memory ---
Mem:  total  15.6Gi  used  3.5Gi
Swap: total  8.0Gi  used  0.0Gi
--- GPU ---
00:01.0 VGA compatible controller: NVIDIA GeForce RTX 3060
--- Motherboard/BIOS ---
BIOS: 2803

--- Commands Used ---
Identification: sudo smartctl --device=nvme -i /dev/nvme0n1
Health Check: sudo smartctl --device=nvme -H /dev/nvme0n1
Attributes: sudo smartctl --device=nvme -A /dev/nvme0n1

--- SMART/NVMe Attributes ---
[... smartctl -A output ...]

--- SMART/NVMe Health ---
[... smartctl -H output ...]

--- Identification Info ---
[... smartctl -i output ...]

======================================================
End of Report
======================================================

Contributing

Contributions are welcome! To contribute:

  • Ensure your code adheres to the AGPLv3 license.

Alternatively, suggest improvements via commenting on the Gist. I appreciate every contribution, no matter how small!

Acknowledgments

A huge thanks to the developers of the following tools, which make this script possible:

  • smartmontools (for smartctl)
  • nvme-cli
  • util-linux (for lsblk, numfmt, column)
  • procps-ng, pciutils (for lscpu, free, lspci)
  • dmidecode
  • yay
  • leafpad

License

This project is licensed under the GNU Affero General Public License v3 (AGPLv3). See the LICENSE file or https://www.gnu.org/licenses/agpl-3.0.html for details.

Contact

If you have questions, suggestions, or feedback, feel free to open an issue or contact me via GitHub.

#!/bin/bash
#
# SmartDriveCheckNG.sh - Drive Health Report Utility
#
# Copyright (C) 2025 ZeroDot1
# License: GNU Affero General Public License, Version 3 (AGPLv3)
#
# This script scans block devices (HDDs, SSDs, floppies, CDROMs) on Arch Linux,
# lets the user select a device, and generates a detailed SMART/NVMe health report.
# Reports are saved in /tmp and include system info, date, time, debug status,
# and drive health categorized as Healthy, Critical, or Failed.
#
# Usage: ./SmartDriveCheckNG.sh [--debug]
#
# Dependencies: smartctl lsblk numfmt column lscpu free lspci dmidecode yay leafpad nvme
# Author: ZeroDot1 <https://github.com/ZeroDot1>
#
# --- Configuration ---
PROG_NAME="SmartDriveCheckNG"
REPORT_BASE_DIR="/tmp"
_DEBUG=0
SUDO_CMD=""
REQUIRED_CMDS="smartctl lsblk numfmt column lscpu free lspci dmidecode yay leafpad nvme"
TEMP_FILES=()
# --- Bash Strict Mode ---
set -euo pipefail
IFS=$'\n\t'
# --- Cleanup Function ---
_cleanup() {
[ "$_DEBUG" -eq 1 ] && echo "DEBUG: Cleaning up temporary files..." >&2
for file in "${TEMP_FILES[@]}"; do
[ -f "$file" ] && { rm -f "$file" && [ "$_DEBUG" -eq 1 ] && echo "DEBUG: Removed $file" >&2; } || echo "ERROR: Failed to remove $file" >&2
done
}
trap _cleanup EXIT
# --- Utility Functions ---
_debug() { [ "$_DEBUG" -eq 1 ] && echo "DEBUG: $1" >&2; }
_error() { echo "ERROR: $1" >&2; }
_info() { echo "INFO: $1" >&2; }
_pause() { read -r -p "$1 (Press Enter to continue): " >&2; }
_ask_yes_no() {
local question="$1" default="${2:-y}" response
while true; do
read -r -p "$question ($( [ "$default" = "y" ] && echo "Y/n" || echo "y/N" )): " response
response="${response:-$default}"
case "${response,,}" in
y|yes) return 0 ;;
n|no) return 1 ;;
*) echo "Please enter 'y' or 'n'." >&2 ;;
esac
done
}
# --- Dependency Management ---
_install_deps() {
local missing=() cmd pkg
for cmd in $REQUIRED_CMDS; do
command -v "$cmd" &>/dev/null || missing+=("$cmd")
done
if [ ${#missing[@]} -gt 0 ]; then
_info "Missing dependencies: ${missing[*]}"
local packages=""
for cmd in "${missing[@]}"; do
case "$cmd" in
smartctl) packages+="smartmontools " ;;
numfmt|lsblk|column) packages+="util-linux " ;;
lscpu|free|lspci) packages+="util-linux procps-ng pciutils " ;;
dmidecode) packages+="dmidecode " ;;
yay) _error "yay is missing. Install it manually as a non-root user: https://aur.archlinux.org/yay"; return 1 ;;
leafpad) packages+="leafpad " ;;
nvme) packages+="nvme-cli " ;;
esac
done
if [ -n "$packages" ]; then
if [ "$(id -u)" -eq 0 ]; then
_error "Cannot run yay as root. Please install the following packages as a non-root user:"
echo " yay -S $packages" >&2
echo "Or use pacman: sudo pacman -S $packages" >&2
_pause "Install the packages and press Enter to continue"
for cmd in "${missing[@]}"; do
command -v "$cmd" &>/dev/null || { _error "$cmd still missing after manual installation attempt."; return 1; }
done
else
if _ask_yes_no "Install missing packages ($packages) with yay?"; then
yay -S $packages --noconfirm || { _error "Failed to install packages with yay."; return 1; }
for cmd in "${missing[@]}"; do
command -v "$cmd" &>/dev/null || { _error "$cmd still missing after installation."; return 1; }
done
else
_error "Dependency installation declined. Cannot proceed."
return 1
fi
fi
fi
fi
_info "All dependencies satisfied."
return 0
}
_check_deps() {
command -v yay &>/dev/null || { _error "yay not found. Install it manually as a non-root user: https://aur.archlinux.org/yay"; exit 1; }
_install_deps || { _error "Dependency check failed."; _pause "Exiting"; exit 1; }
}
# --- Sudo Setup ---
_set_sudo() {
if [ "$(id -u)" -eq 0 ]; then
SUDO_CMD=""
_info "Running as root. No sudo needed for privileged operations."
else
SUDO_CMD="sudo"
command -v sudo &>/dev/null || { _error "sudo not found. Cannot proceed."; _pause "Exiting"; exit 1; }
_info "Using sudo for privileged operations."
fi
}
# --- System Information ---
_get_system_info() {
local info=""
info+="Kernel: $(uname -r)\n"
info+="Hostname: $(hostname)\n"
info+="Uptime: $(uptime -p)\n"
info+="\n--- CPU ---\n"
info+="$($SUDO_CMD lscpu | grep -E 'Model name|Architecture|CPU\(s\):' | sed 's/^[ ]*//')\n"
info+="\n--- Memory ---\n"
info+="$($SUDO_CMD free -h | grep -E 'Mem:|Swap:')\n"
info+="\n--- GPU ---\n"
info+="$($SUDO_CMD lspci | grep -i vga || echo 'N/A')\n"
info+="\n--- Motherboard/BIOS ---\n"
info+="Board: $($SUDO_CMD dmidecode -s baseboard-product-name 2>/dev/null || echo 'N/A')\n"
info+="BIOS: $($SUDO_CMD dmidecode -s bios-version 2>/dev/null || echo 'N/A')\n"
echo -e "$info"
}
# --- Drive Discovery ---
_discover_drives() {
DRIVE_PATHS=()
DRIVE_NAMES=()
local tmp_file=$(mktemp -p "${TMPDIR:-/tmp}" "lsblk_data_XXXXXX.txt") || { _error "Failed to create temp file."; return 1; }
TEMP_FILES+=("$tmp_file")
$SUDO_CMD lsblk -d -o NAME,MODEL,SIZE,TYPE --bytes --noheadings | grep -Ev '^(part|zram|loop)' >"$tmp_file" || {
_error "lsblk failed. Check permissions or device availability."
return 1
}
_debug "lsblk output saved to $tmp_file"
while IFS= read -r line; do
local name=$(echo "$line" | awk '{print $1}')
local type=$(echo "$line" | awk '{print $NF}')
local size=$(echo "$line" | awk '{print $(NF-1)}')
local model=$(echo "$line" | awk '{$1=""; $(NF-1)=""; $NF=""; print $0}' | sed 's/^[ ]*//;s/[ ]*$//')
local path="/dev/$name"
_debug "Parsed: Name='$name', Model='$model', Size='$size', Type='$type'"
# Include all block devices (disk, rom for CDROMs/floppies)
[ -b "$path" ] || { _debug "Skipping $path: Not a block device"; continue; }
local is_nvme=0
[[ "$name" == nvme* ]] && is_nvme=1
local smart_ok=0 output=""
if [ "$is_nvme" -eq 1 ] && command -v smartctl &>/dev/null; then
_debug "Checking NVMe device $path with smartctl --device=nvme"
local cmd=(smartctl --device=nvme -i "$path")
[ -n "$SUDO_CMD" ] && cmd=("$SUDO_CMD" "${cmd[@]}")
_debug "Executing: ${cmd[*]}"
if output=$("${cmd[@]}" 2>&1); then
echo "$output" | grep -qE "Model Number:|Serial Number:|Firmware Version:|NVMe Version:" && smart_ok=1
_debug "smartctl --device=nvme -i: $( [ "$smart_ok" -eq 1 ] && echo "Success" || echo "Failed: $output" )"
else
_debug "smartctl --device=nvme -i failed: $output"
fi
fi
if [ "$smart_ok" -eq 0 ] && [ "$is_nvme" -eq 1 ] && command -v nvme &>/dev/null; then
_debug "Checking NVMe device $path with nvme-cli"
local cmd=(nvme id-ctrl "$path")
[ -n "$SUDO_CMD" ] && cmd=("$SUDO_CMD" "${cmd[@]}")
_debug "Executing: ${cmd[*]}"
if output=$("${cmd[@]}" 2>&1); then
echo "$output" | grep -qE "vid|sn|mn|fr" && smart_ok=1
_debug "nvme id-ctrl: $( [ "$smart_ok" -eq 1 ] && echo "Success" || echo "Failed: $output" )"
else
_debug "nvme id-ctrl failed: $output"
fi
fi
if [ "$smart_ok" -eq 0 ] && [ "$is_nvme" -eq 0 ] && command -v smartctl &>/dev/null; then
_debug "Checking $path with smartctl"
local cmd=(smartctl -i "$path")
[ -n "$SUDO_CMD" ] && cmd=("$SUDO_CMD" "${cmd[@]}")
_debug "Executing: ${cmd[*]}"
if output=$("${cmd[@]}" 2>&1); then
echo "$output" | grep -qE "Model Number:|Serial Number:|Firmware Version:" && smart_ok=1
_debug "smartctl -i: $( [ "$smart_ok" -eq 1 ] && echo "Success" || echo "Failed: $output" )"
else
_debug "smartctl -i failed: $output"
fi
fi
local size_human=$(numfmt --to=iec-i --suffix=B --format="%.2f" "$size" 2>/dev/null || echo "N/A")
DRIVE_PATHS+=("$path")
DRIVE_NAMES+=("$path - ${model:-Unknown Model} ($size_human, Type: $type)")
_debug "Added: $path"
done <"$tmp_file"
return 0
}
# --- Report Generation ---
_generate_report() {
local device="$1"
local report_file=$(mktemp -p "$REPORT_BASE_DIR" "smart_report_XXXXXX.txt") || { _error "Failed to create report file."; return 1; }
TEMP_FILES+=("$report_file")
_debug "Generating report for $device"
local datetime=$(date "+%Y-%m-%d %H:%M:%S %Z")
local model="N/A" serial="N/A" firmware="N/A" capacity="N/A"
local health="" attrs="" info=""
local health_status="Unknown" recommendation="Investigate detailed output below."
local cmd_info=() cmd_health=() cmd_attrs=()
local is_nvme=0
[[ "$device" == /dev/nvme* ]] && is_nvme=1
# Ask user to choose tool for NVMe devices
local use_smartctl=1
if [ "$is_nvme" -eq 1 ] && command -v nvme &>/dev/null && command -v smartctl &>/dev/null; then
_info "NVMe device detected: $device"
if _ask_yes_no "Use smartctl for health check (recommended)? (y/n)" y; then
use_smartctl=1
else
use_smartctl=0
fi
fi
if [ "$is_nvme" -eq 1 ] && [ "$use_smartctl" -eq 1 ] && command -v smartctl &>/dev/null; then
_debug "Using smartctl --device=nvme for $device"
cmd_info=(smartctl --device=nvme -i "$device")
cmd_health=(smartctl --device=nvme -H "$device")
cmd_attrs=(smartctl --device=nvme -A "$device")
[ -n "$SUDO_CMD" ] && {
cmd_info=("$SUDO_CMD" "${cmd_info[@]}")
cmd_health=("$SUDO_CMD" "${cmd_health[@]}")
cmd_attrs=("$SUDO_CMD" "${cmd_attrs[@]}")
}
_debug "Executing info: ${cmd_info[*]}"
info=$("${cmd_info[@]}" 2>&1 || echo "ERROR: smartctl --device=nvme -i failed")
_debug "Executing health: ${cmd_health[*]}"
health=$("${cmd_health[@]}" 2>&1 || echo "ERROR: smartctl --device=nvme -H failed")
_debug "Executing attrs: ${cmd_attrs[*]}"
attrs=$("${cmd_attrs[@]}" 2>&1 || echo "ERROR: smartctl --device=nvme -A failed")
model=$(echo "$info" | grep -E "^Model Number:|^Product:" | awk -F': ' '{print $2}' | head -n 1 | xargs || echo "N/A")
serial=$(echo "$info" | grep "Serial Number:" | awk -F': ' '{print $2}' | xargs || echo "N/A")
firmware=$(echo "$info" | grep "Firmware Version:" | awk -F': ' '{print $2}' | xargs || echo "N/A")
capacity=$(echo "$info" | grep "Total NVM Capacity:" | awk -F': ' '{print $2}' | xargs || echo "N/A")
if echo "$health" | grep -iq "PASSED"; then
health_status="Healthy"
recommendation="Drive is healthy. Regular checks recommended."
elif echo "$health" | grep -iq "FAILED"; then
health_status="Failed"
recommendation="CRITICAL: Drive failure detected. Back up data immediately and replace the drive."
else
# Check attributes for warning signs (e.g., wear leveling, reallocated sectors)
if echo "$attrs" | grep -iqE "Percentage Used:.*[1-9][0-9]*%|Media Wearout Indicator:.*[0-9]{1,2}%"; then
health_status="Critical"
recommendation="WARNING: Drive shows wear or errors. Back up data and monitor condition."
fi
fi
elif [ "$is_nvme" -eq 1 ] && [ "$use_smartctl" -eq 0 ] && command -v nvme &>/dev/null; then
_debug "Using nvme-cli for $device"
cmd_info=(nvme id-ctrl "$device")
cmd_health=(nvme smart-log "$device")
cmd_attrs=("N/A" "(nvme-cli does not provide detailed attributes)")
[ -n "$SUDO_CMD" ] && {
cmd_info=("$SUDO_CMD" "${cmd_info[@]}")
cmd_health=("$SUDO_CMD" "${cmd_health[@]}")
}
_debug "Executing info: ${cmd_info[*]}"
info=$("${cmd_info[@]}" 2>&1 || echo "ERROR: nvme id-ctrl failed")
_debug "Executing health: ${cmd_health[*]}"
health=$("${cmd_health[@]}" 2>&1 || echo "ERROR: nvme smart-log failed")
attrs="Note: Detailed attributes not available via nvme-cli. See smart-log output."
model=$(echo "$info" | grep -i "mn" | awk -F': ' '{print $2}' | xargs || echo "N/A")
serial=$(echo "$info" | grep -i "sn" | awk -F': ' '{print $2}' | xargs || echo "N/A")
firmware=$(echo "$info" | grep -i "fr" | awk -F': ' '{print $2}' | xargs || echo "N/A")
capacity=$(echo "$info" | grep -i "tnvmcap" | awk -F': ' '{print $2}' | xargs || echo "N/A")
if echo "$health" | grep -q "Critical Warning:[[:space:]]*0"; then
health_status="Healthy"
recommendation="Drive is healthy. Regular checks recommended."
elif echo "$health" | grep -q "Critical Warning:[[:space:]]*[1-9]"; then
# Check for specific critical warnings
if echo "$health" | grep -iqE "temperature.*threshold|available spare.*threshold"; then
health_status="Critical"
recommendation="WARNING: Drive reports critical conditions (e.g., temperature, spare capacity). Back up data and monitor condition."
else
health_status="Failed"
recommendation="CRITICAL: Drive reports severe errors. Back up data immediately and replace the drive."
fi
else
health_status="Critical"
recommendation="WARNING: Smart log unavailable or faulty. Back up data and check condition."
fi
else
_debug "Using smartctl for $device"
cmd_info=(smartctl -i "$device")
cmd_health=(smartctl -H "$device")
cmd_attrs=(smartctl -A "$device")
[ -n "$SUDO_CMD" ] && {
cmd_info=("$SUDO_CMD" "${cmd_info[@]}")
cmd_health=("$SUDO_CMD" "${cmd_health[@]}")
cmd_attrs=("$SUDO_CMD" "${cmd_attrs[@]}")
}
_debug "Executing info: ${cmd_info[*]}"
info=$("${cmd_info[@]}" 2>&1 || echo "ERROR: smartctl -i failed")
_debug "Executing health: ${cmd_health[*]}"
health=$("${cmd_health[@]}" 2>&1 || echo "ERROR: smartctl -H failed")
_debug "Executing attrs: ${cmd_attrs[*]}"
attrs=$("${cmd_attrs[@]}" 2>&1 || echo "ERROR: smartctl -A failed")
model=$(echo "$info" | grep -E "^Device Model:|^Product:" | awk -F': ' '{print $2}' | head -n 1 | xargs || echo "N/A")
serial=$(echo "$info" | grep "Serial Number:" | awk -F': ' '{print $2}' | xargs || echo "N/A")
firmware=$(echo "$info" | grep "Firmware Version:" | awk -F': ' '{print $2}' | xargs || echo "N/A")
capacity=$(echo "$info" | grep "User Capacity:" | awk -F': ' '{print $2}' | xargs || echo "N/A")
if echo "$health" | grep -iq "PASSED"; then
health_status="Healthy"
recommendation="Drive is healthy. Regular checks recommended."
elif echo "$health" | grep -iq "FAILED"; then
health_status="Failed"
recommendation="CRITICAL: Drive failure detected. Back up data immediately and replace the drive."
else
# Check attributes for warning signs (e.g., reallocated sectors)
if echo "$attrs" | grep -iqE "Reallocated_Sector_Ct.*[1-9]|Wear_Leveling_Count.*[0-9]{1,2}%"; then
health_status="Critical"
recommendation="WARNING: Drive shows wear or errors. Back up data and monitor condition."
fi
fi
fi
cat <<EOF >"$report_file"
======================================================
$PROG_NAME - Drive Health Report
======================================================
Generated: $datetime
Debug Mode: $( [ "$_DEBUG" -eq 1 ] && echo "YES" || echo "NO" )
Author: ZeroDot1 <https://github.com/ZeroDot1
Donate: https://www.amazon.de/hz/wishlist/ls/2DDEDPJU2996I/
--- Device Info ---
Path: $device
Model: $model
Serial: $serial
Firmware: $firmware
Capacity: $capacity
--- Health Assessment ---
Health Status: $health_status
Recommendation: $recommendation
--- System Info ---
$(_get_system_info)
--- Commands Used ---
Identification: $(printf "%q " "${cmd_info[@]}")
Health Check: $(printf "%q " "${cmd_health[@]}")
Attributes: $(printf "%q " "${cmd_attrs[@]}")
--- SMART/NVMe Attributes ---
$attrs
--- SMART/NVMe Health ---
$health
--- Identification Info ---
$info
======================================================
End of Report
======================================================
EOF
_info "Report generated: $report_file"
echo "$report_file"
}
# --- Report Display ---
_display_report() {
local file="$1"
[ -f "$file" ] || { _error "Report file $file not found."; return 1; }
_info "Displaying report..."
if command -v leafpad &>/dev/null; then
leafpad "$file" &
_pause "Review the report in Leafpad"
elif command -v less &>/dev/null; then
less -R "$file"
else
cat "$file"
_pause "End of report (install leafpad or less for better viewing)"
fi
}
# --- Main ---
main() {
[ "$#" -ge 1 ] && [ "$1" = "--debug" ] && _DEBUG=1 && _info "Debug mode enabled"
clear
echo "======================================================" >&2
echo "$PROG_NAME - Drive Health Check Utility" >&2
echo "A minimalist tool for SMART/NVMe reports on Arch Linux" >&2
echo "Author: ZeroDot1 <https://github.com/ZeroDot1>" >&2
echo "Donate: https://www.amazon.de/hz/wishlist/ls/2DDEDPJU2996I/" >&2
echo "======================================================" >&2
_set_sudo
_check_deps
while true; do
clear
_info "Scanning drives..."
_discover_drives || { _error "Drive discovery failed."; _pause "Exiting"; exit 1; }
if [ ${#DRIVE_PATHS[@]} -eq 0 ]; then
_pause "No drives found. Check connections, permissions, or install nvme-cli/smartmontools."
_ask_yes_no "Scan again?" || break
continue
fi
echo -e "\n--- Available Drives ---" >&2
PS3=$'\nSelect a drive (or "q" to quit): '
select name in "${DRIVE_NAMES[@]}" "Quit"; do
[[ "$name" == "Quit" ]] && break 2
local idx=$((REPLY - 1))
if [ "$idx" -ge 0 ] && [ "$idx" -lt "${#DRIVE_PATHS[@]}" ]; then
local device="${DRIVE_PATHS[$idx]}"
_info "Selected: $device"
local report=$(_generate_report "$device") || { _error "Report generation failed."; _pause "Returning to menu"; break; }
_display_report "$report"
_ask_yes_no "Check another drive?" || break 2
else
_error "Invalid selection. Try again."
fi
break
done
done
clear
_info "Exiting $PROG_NAME."
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment