102 lines
4.7 KiB
Bash
Executable File
102 lines
4.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# astro-menu system-monitor backend — the ship's "Systems Diagnostic".
|
|
# Emits one TAB-separated record per subsystem:
|
|
#
|
|
# CATEGORY <TAB> NAME <TAB> USAGE_PCT <TAB> TEMP_C <TAB> DETAIL
|
|
#
|
|
# CATEGORY is cpu|gpu|ram|disk (drives the icon). USAGE_PCT is 0..100. TEMP_C is
|
|
# an integer °C or empty when no sensor exists. One `disk` row per mounted real
|
|
# filesystem. Reads everything from /proc + /sys (no extra deps).
|
|
set -uo pipefail
|
|
|
|
milli_to_c() { awk '{printf "%d", ($1 + 500) / 1000}'; }
|
|
|
|
hwmon_temp() { # $1 = chip-name substring; first temp input of that chip, in °C
|
|
local h n t
|
|
for h in /sys/class/hwmon/hwmon*; do
|
|
n=$(cat "$h/name" 2>/dev/null) || continue
|
|
[[ "$n" == *"$1"* ]] || continue
|
|
for t in "$h"/temp*_input; do
|
|
[[ -r "$t" ]] && { milli_to_c < "$t"; return 0; }
|
|
done
|
|
done
|
|
return 1
|
|
}
|
|
|
|
hwmon_dir_temp() { # $1 = hwmon dir, $2 = preferred label substring
|
|
local d="$1" pref="$2" lf lbl base
|
|
for lf in "$d"/temp*_label; do
|
|
[[ -r "$lf" ]] || continue
|
|
[[ "$(cat "$lf" 2>/dev/null)" == *"$pref"* ]] || continue
|
|
base="${lf%_label}_input"
|
|
[[ -r "$base" ]] && { milli_to_c < "$base"; return 0; }
|
|
done
|
|
for base in "$d"/temp*_input; do
|
|
[[ -r "$base" ]] && { milli_to_c < "$base"; return 0; }
|
|
done
|
|
return 1
|
|
}
|
|
|
|
nvme_temp() { # $1 = disk (e.g. nvme0n1); temp of that specific controller, in °C
|
|
local ctrl h t
|
|
ctrl=$(basename "$(readlink -f "/sys/block/$1/device" 2>/dev/null)")
|
|
for h in /sys/class/hwmon/hwmon*; do
|
|
[[ "$(cat "$h/name" 2>/dev/null)" == "nvme" ]] || continue
|
|
[[ "$(basename "$(readlink -f "$h/device" 2>/dev/null)")" == "$ctrl" ]] || continue
|
|
for t in "$h"/temp*_input; do
|
|
[[ -r "$t" ]] && { milli_to_c < "$t"; return 0; }
|
|
done
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# --- CPU: Thrusters ---------------------------------------------------------
|
|
cpu_snapshot() { awk '/^cpu /{t=0; for (i=2; i<=NF; i++) t+=$i; print t, $5}' /proc/stat; }
|
|
read t1 idle1 < <(cpu_snapshot); sleep 0.2; read t2 idle2 < <(cpu_snapshot)
|
|
dtotal=$(( t2 - t1 )); didle=$(( idle2 - idle1 )); cpu_usage=0
|
|
(( dtotal > 0 )) && cpu_usage=$(( ((dtotal - didle) * 100 + dtotal / 2) / dtotal ))
|
|
cpu_temp=$(hwmon_temp k10temp) || cpu_temp=$(hwmon_temp coretemp) || cpu_temp=""
|
|
printf 'cpu\tThrusters\t%s\t%s\t%s cores online\n' "$cpu_usage" "$cpu_temp" "$(nproc 2>/dev/null || echo '?')"
|
|
|
|
# --- GPU: Hyperdrive (discrete = the card with the most VRAM) ---------------
|
|
gpu_dev=""; best_vram=-1
|
|
for d in /sys/class/drm/card[0-9]*/device; do
|
|
[[ -r "$d/gpu_busy_percent" ]] || continue
|
|
v=$(cat "$d/mem_info_vram_total" 2>/dev/null || echo 0)
|
|
(( v > best_vram )) && { best_vram=$v; gpu_dev=$d; }
|
|
done
|
|
gpu_usage=0; gpu_temp=""; gpu_detail="offline"
|
|
if [[ -n "$gpu_dev" ]]; then
|
|
gpu_usage=$(cat "$gpu_dev/gpu_busy_percent" 2>/dev/null || echo 0)
|
|
for hd in "$gpu_dev"/hwmon/hwmon*; do
|
|
[[ -d "$hd" ]] && { gpu_temp=$(hwmon_dir_temp "$hd" junction) || gpu_temp=""; break; }
|
|
done
|
|
(( best_vram > 0 )) && gpu_detail=$(awk -v b="$best_vram" 'BEGIN{printf "%.0f GiB core", b/1073741824}')
|
|
fi
|
|
printf 'gpu\tHyperdrive\t%s\t%s\t%s\n' "$gpu_usage" "$gpu_temp" "$gpu_detail"
|
|
|
|
# --- RAM: Life Support Systems ---------------------------------------------
|
|
read ram_used ram_total < <(free -b | awk '/^Mem:/{print $3, $2}')
|
|
ram_usage=0; (( ram_total > 0 )) && ram_usage=$(( (ram_used * 100 + ram_total / 2) / ram_total ))
|
|
ram_temp=$(hwmon_temp spd5118) || ram_temp=$(hwmon_temp jc42) || ram_temp=""
|
|
ram_detail=$(awk -v u="$ram_used" -v t="$ram_total" 'BEGIN{printf "%.1f/%.1f GiB", u/1073741824, t/1073741824}')
|
|
printf 'ram\tLife Support Systems\t%s\t%s\t%s\n' "$ram_usage" "$ram_temp" "$ram_detail"
|
|
|
|
# --- Storage: Cargo Hold (one row per real filesystem, deduped by device) ---
|
|
declare -A seen
|
|
while read -r src used size; do
|
|
[[ "$src" == /dev/* ]] || continue
|
|
[[ -n "${seen[$src]:-}" ]] && continue
|
|
seen[$src]=1
|
|
dev=$(basename "$src") # e.g. sda1 / nvme0n1p2
|
|
disk=$(lsblk -no pkname "$src" 2>/dev/null | head -1) # parent disk, if partitioned
|
|
[[ -z "$disk" ]] && disk="$dev"
|
|
(( size > 0 )) || continue
|
|
usage=$(( (used * 100 + size / 2) / size ))
|
|
temp=""; [[ "$disk" == nvme* ]] && { temp=$(nvme_temp "$disk") || temp=""; }
|
|
[[ -z "$temp" ]] && temp=$(hwmon_temp drivetemp 2>/dev/null) || true
|
|
detail=$(awk -v d="$dev" -v u="$used" -v t="$size" \
|
|
'BEGIN{printf "%-10s %.0f/%.0f GiB", d, u/1073741824, t/1073741824}')
|
|
printf 'disk\tCargo Hold\t%s\t%s\t%s\n' "$usage" "$temp" "$detail"
|
|
done < <(df -B1 --output=source,used,size -x tmpfs -x devtmpfs -x overlay -x squashfs 2>/dev/null | tail -n +2)
|