|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Real system resources report (no API, no installed-state) |
| 3 | +# Safe: read-only, uses common tools and /proc |
| 4 | +# Prints a structured report to stdout. |
| 5 | +# |
| 6 | +# Optional: call check_resources_direct_dialog to show in dialog. |
| 7 | + |
| 8 | +set -Euo pipefail |
| 9 | + |
| 10 | +# --- helpers --------------------------------------------------------- |
| 11 | + |
| 12 | +EXCLUDE_IFACES_REGEX="${EXCLUDE_IFACES_REGEX:-^(docker0|docker.*|br-.*|veth.*)$}" |
| 13 | + |
| 14 | +cmd_exists() { command -v "$1" >/dev/null 2>&1; } |
| 15 | + |
| 16 | +fmt_secs() { |
| 17 | + # format seconds to d h m s |
| 18 | + local s="${1:-0}" d h m |
| 19 | + d=$(( s/86400 )); s=$(( s%86400 )) |
| 20 | + h=$(( s/3600 )); s=$(( s%3600 )) |
| 21 | + m=$(( s/60 )); s=$(( s%60 )) |
| 22 | + if (( d > 0 )); then printf "%dd %02dh %02dm %02ds" "$d" "$h" "$m" "$s" |
| 23 | + elif (( h > 0 )); then printf "%dh %02dm %02ds" "$h" "$m" "$s" |
| 24 | + elif (( m > 0 )); then printf "%dm %02ds" "$m" "$s" |
| 25 | + else printf "%ds" "$s"; fi |
| 26 | +} |
| 27 | + |
| 28 | +kv_from_meminfo() { |
| 29 | + # print value in kB (numeric) for key |
| 30 | + local key="$1" |
| 31 | + awk -v K="$key" '$1==K":"{print $2}' /proc/meminfo 2>/dev/null |
| 32 | +} |
| 33 | + |
| 34 | +cpu_model() { |
| 35 | + awk -F: '/^model name[ \t]*:/{gsub(/^[ \t]+/,"",$2); print $2; exit}' /proc/cpuinfo 2>/dev/null |
| 36 | +} |
| 37 | + |
| 38 | +cpu_mhz_avg() { |
| 39 | + awk -F: '/^cpu MHz[ \t]*:/{sum+=$2; n++} END{if(n>0){printf "%.0f\n", sum/n}}' /proc/cpuinfo 2>/dev/null |
| 40 | +} |
| 41 | + |
| 42 | +cpu_cores_count() { |
| 43 | + if cmd_exists nproc; then nproc |
| 44 | + else awk -F: '/^processor[ \t]*:/{c++} END{print c+0}' /proc/cpuinfo 2>/dev/null |
| 45 | + fi |
| 46 | +} |
| 47 | + |
| 48 | +loadavg_line() { |
| 49 | + if [[ -r /proc/loadavg ]]; then |
| 50 | + awk '{print $1" "$2" "$3" (1/5/15 min)"}' /proc/loadavg |
| 51 | + else |
| 52 | + if cmd_exists uptime; then uptime | sed 's/^.*load average: //' |
| 53 | + else echo "n/a" |
| 54 | + fi |
| 55 | + fi |
| 56 | +} |
| 57 | + |
| 58 | +root_df_line() { |
| 59 | + df -h -T / 2>/dev/null | awk 'NR==1 || NR==2' |
| 60 | +} |
| 61 | + |
| 62 | +df_summary() { |
| 63 | + # Exclude pseudo filesystems; show top few |
| 64 | + df -h -T -x tmpfs -x devtmpfs -x overlay 2>/dev/null | awk 'NR==1 || NR<=8' |
| 65 | +} |
| 66 | + |
| 67 | +list_dns() { |
| 68 | + if [[ -f /etc/resolv.conf ]]; then |
| 69 | + awk '/^nameserver[ \t]+/{print $2}' /etc/resolv.conf | sed 's/^/ - /' |
| 70 | + fi |
| 71 | +} |
| 72 | + |
| 73 | +ip_addrs_brief() { |
| 74 | + if cmd_exists ip; then |
| 75 | + ip -br addr show 2>/dev/null | awk -v R="$EXCLUDE_IFACES_REGEX" '$1 !~ R' |
| 76 | + else |
| 77 | + echo "ip command not available." |
| 78 | + fi |
| 79 | +} |
| 80 | + |
| 81 | +ip_links_brief() { |
| 82 | + if cmd_exists ip; then |
| 83 | + ip -br link show 2>/dev/null | awk -v R="$EXCLUDE_IFACES_REGEX" '$1 !~ R' |
| 84 | + else |
| 85 | + echo "ip command not available." |
| 86 | + fi |
| 87 | +} |
| 88 | + |
| 89 | +show_route() { |
| 90 | + if cmd_exists ip; then |
| 91 | + ip route show 2>/dev/null |
| 92 | + fi |
| 93 | +} |
| 94 | + |
| 95 | +os_pretty() { |
| 96 | + if cmd_exists hostnamectl; then |
| 97 | + hostnamectl 2>/dev/null | sed -n '1,8p' |
| 98 | + elif [[ -f /etc/os-release ]]; then |
| 99 | + . /etc/os-release |
| 100 | + echo "Operating System: ${PRETTY_NAME:-unknown}" |
| 101 | + echo "Kernel: $(uname -r)" |
| 102 | + echo "Architecture: $(uname -m)" |
| 103 | + else |
| 104 | + echo "Kernel: $(uname -srmo 2>/dev/null || uname -a)" |
| 105 | + fi |
| 106 | +} |
| 107 | + |
| 108 | +uptime_secs() { |
| 109 | + awk '{print int($1)}' /proc/uptime 2>/dev/null || echo 0 |
| 110 | +} |
| 111 | + |
| 112 | +top_cpu_governor() { |
| 113 | + # best-effort; may not exist in VMs/containers |
| 114 | + local g |
| 115 | + g=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 2>/dev/null || true) |
| 116 | + [[ -n "$g" ]] && echo "$g" || echo "n/a" |
| 117 | +} |
| 118 | + |
| 119 | +# --- main report ----------------------------------------------------- |
| 120 | + |
| 121 | +get_resources() { |
| 122 | + # Time and host |
| 123 | + local now tz |
| 124 | + now="$(date '+%F %T' 2>/dev/null || date)" |
| 125 | + tz="$(date '+%Z (%z)' 2>/dev/null || echo "")" |
| 126 | + |
| 127 | + # System section |
| 128 | + echo "System Information" |
| 129 | + echo "------------------" |
| 130 | + echo "Hostname: $(hostname 2>/dev/null || echo n/a)" |
| 131 | + os_pretty |
| 132 | + echo "Time: $now $tz" |
| 133 | + local up; up="$(uptime_secs)" |
| 134 | + echo "Uptime: $(fmt_secs "${up:-0}")" |
| 135 | + echo |
| 136 | + |
| 137 | + # CPU section |
| 138 | + local cores model mhz gov load |
| 139 | + cores="$(cpu_cores_count)" |
| 140 | + model="$(cpu_model)"; [[ -z "$model" ]] && model="n/a" |
| 141 | + mhz="$(cpu_mhz_avg)"; [[ -z "$mhz" ]] && mhz="n/a" |
| 142 | + gov="$(top_cpu_governor)" |
| 143 | + load="$(loadavg_line)" |
| 144 | + echo "CPU" |
| 145 | + echo "---" |
| 146 | + echo "Model: $model" |
| 147 | + echo "Cores: ${cores:-n/a}" |
| 148 | + echo "Avg Frequency (MHz): ${mhz}" |
| 149 | + echo "Governor: ${gov}" |
| 150 | + echo "Load Average: ${load}" |
| 151 | + echo |
| 152 | + |
| 153 | + # Memory section (from /proc/meminfo) |
| 154 | + local mt mf ma st sf bu ca |
| 155 | + mt="$(kv_from_meminfo MemTotal)" |
| 156 | + ma="$(kv_from_meminfo MemAvailable)" |
| 157 | + st="$(kv_from_meminfo SwapTotal)" |
| 158 | + sf="$(kv_from_meminfo SwapFree)" |
| 159 | + bu="$(kv_from_meminfo Buffers)" |
| 160 | + ca="$(kv_from_meminfo Cached)" |
| 161 | + |
| 162 | + # Convert kB to human MiB/GB approximations |
| 163 | + _kb_to_mib() { awk -v k="${1:-0}" 'BEGIN{printf "%.1f", k/1024}'; } |
| 164 | + _kb_to_gib() { awk -v k="${1:-0}" 'BEGIN{printf "%.2f", k/1048576}'; } |
| 165 | + |
| 166 | + local used avail pct |
| 167 | + if [[ -n "$mt" && -n "$ma" ]]; then |
| 168 | + used=$(( mt - ma )) |
| 169 | + pct=$(awk -v u="$used" -v t="$mt" 'BEGIN{ if(t>0) printf "%.1f", (u*100.0)/t; else print "n/a"}') |
| 170 | + fi |
| 171 | + |
| 172 | + echo "Memory" |
| 173 | + echo "------" |
| 174 | + if [[ -n "$mt" ]]; then |
| 175 | + echo "Total: $(_kb_to_gib "$mt") GiB" |
| 176 | + echo "Available: $(_kb_to_gib "${ma:-0}") GiB" |
| 177 | + echo "Used (approx = Total-Available): $(_kb_to_gib "${used:-0}") GiB (${pct:-n/a}%)" |
| 178 | + echo "Buffers/Cache: $(_kb_to_mib "${bu:-0}") MiB / $(_kb_to_mib "${ca:-0}") MiB" |
| 179 | + else |
| 180 | + echo "Meminfo not available." |
| 181 | + fi |
| 182 | + echo "Swap Total: $(_kb_to_gib "${st:-0}") GiB" |
| 183 | + echo "Swap Free: $(_kb_to_gib "${sf:-0}") GiB" |
| 184 | + echo |
| 185 | + |
| 186 | + # Disk section |
| 187 | + echo "Disk Usage" |
| 188 | + echo "----------" |
| 189 | + echo "(Root filesystem)" |
| 190 | + root_df_line |
| 191 | + echo |
| 192 | + echo "(Top filesystems)" |
| 193 | + df_summary |
| 194 | + echo |
| 195 | + |
| 196 | + # Network section |
| 197 | + echo "Network" |
| 198 | + echo "-------" |
| 199 | + echo "(Interfaces - brief)" |
| 200 | + ip_links_brief |
| 201 | + echo |
| 202 | + echo "(Addresses - brief)" |
| 203 | + ip_addrs_brief |
| 204 | + echo |
| 205 | + echo "(Routes)" |
| 206 | + show_route |
| 207 | + echo |
| 208 | + echo "(DNS from /etc/resolv.conf)" |
| 209 | + list_dns |
| 210 | + echo |
| 211 | + |
| 212 | +} |
| 213 | + |
| 214 | +get_resources |
0 commit comments