11 Commits

Author SHA1 Message Date
Justin Oros cbdbce7a41 refactor(setup-network): let netplan own the AP switch — update config and apply before wpa_cli 2026-04-23 12:16:40 -07:00
Justin Oros bbf1d8b79a fix(setup-network): use remove_network instead of disable_network and drop interface bounce to prevent AP fallback 2026-04-23 12:11:12 -07:00
Justin Oros 436906582c fix(setup-network): move netplan file selection before Proceed prompt so it isn't missed on SSH drop 2026-04-23 11:57:04 -07:00
Justin Oros a01f4aa11c fix(setup-network): prompt user to choose netplan file when multiple configs exist 2026-04-23 11:54:03 -07:00
Justin Oros d61f7e4512 fix(setup-network): update all netplan files containing access-points, not just the first one 2026-04-23 11:49:01 -07:00
Justin Oros 337d238d7f fix(setup-network): bounce interface and force DHCP renew after AP switch to restore connectivity 2026-04-23 11:43:39 -07:00
Justin Oros ff5cb104f8 fix(setup-network): collect all user input before switching AP to prevent SSH session drop mid-prompt 2026-04-23 11:39:10 -07:00
Justin Oros 5d9e0f579c setup-network.sh: add Change Wireless Network option using iw/wpa_cli/wpa_passphrase for systemd-networkd on Armbian 2026-04-23 11:32:47 -07:00
Justin Oros 2bd8711db3 health-check.sh: show human-readable used/total disk usage instead of percentage 2026-04-22 09:50:44 -07:00
Justin Oros 2928285143 health-check.sh: fix total disk usage label to show root filesystem instead of empty mount point 2026-04-22 09:47:25 -07:00
Justin Oros f9d0717b71 health-check.sh: add total disk usage summary line to disk space section 2026-04-22 09:45:30 -07:00
2 changed files with 147 additions and 0 deletions
+11
View File
@@ -62,6 +62,17 @@ check_disk() {
ok "Disk usage at ${pct}% on $mount" ok "Disk usage at ${pct}% on $mount"
fi fi
done < <(df -h | awk 'NR>1' | grep -v ' /dev' | grep -v ' /sys' | grep -v ' /proc' | grep -v ' /run' | grep -v ' /snap' | grep -v 'overlay2' | grep -v 'docker') done < <(df -h | awk 'NR>1' | grep -v ' /dev' | grep -v ' /sys' | grep -v ' /proc' | grep -v ' /run' | grep -v ' /snap' | grep -v 'overlay2' | grep -v 'docker')
local used_human total_human total_pct
used_human=$(df -h / | awk 'NR==2 {print $3}')
total_human=$(df -h / | awk 'NR==2 {print $2}')
total_pct=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$total_pct" -ge 90 ]; then
fail "Total disk usage ${used_human} of ${total_human} — critically low"
elif [ "$total_pct" -ge 80 ]; then
warn "Total disk usage ${used_human} of ${total_human}"
else
ok "Total disk usage ${used_human} of ${total_human}"
fi
} }
check_common() { check_common() {
+136
View File
@@ -34,6 +34,7 @@ echo " 0) Change hostname"
echo " 1) Configure static IP" echo " 1) Configure static IP"
echo " 2) Prefer IPv4 over IPv6" echo " 2) Prefer IPv4 over IPv6"
echo " 3) Prefer IPv6 over IPv4" echo " 3) Prefer IPv6 over IPv4"
echo " 4) Change Wireless Network"
echo " q) Quit" echo " q) Quit"
echo "" echo ""
read -rp "Choose: " NET_OPT read -rp "Choose: " NET_OPT
@@ -71,6 +72,141 @@ case "$NET_OPT" in
info "IPv4 preference removed. System will use default IPv6-first behavior." info "IPv4 preference removed. System will use default IPv6-first behavior."
exit 0 exit 0
;; ;;
4)
header "Change Wireless Network"
check_deps iw netplan
WIFI_IFACE=$(iw dev 2>/dev/null | awk '/Interface/{print $2}' | head -1)
[ -n "$WIFI_IFACE" ] || die "No wireless interface found."
CURRENT_SSID=$(iw dev "$WIFI_IFACE" link 2>/dev/null | awk '/SSID:/{print $2}')
info "Scanning for networks on ${WIFI_IFACE}..."
ip link set "$WIFI_IFACE" up 2>/dev/null || true
iw dev "$WIFI_IFACE" scan >/dev/null 2>&1 || true
sleep 2
mapfile -t SCAN_LINES < <(iw dev "$WIFI_IFACE" scan 2>/dev/null \
| awk '
/^BSS / { signal=""; ssid="" }
/signal:/ { signal=$2 }
/SSID:/ { ssid=substr($0, index($0,$2)); gsub(/^[[:space:]]+|[[:space:]]+$/, "", ssid) }
ssid!="" && signal!="" { print signal "\t" ssid; signal=""; ssid="" }
' \
| sort -rn \
| awk -F'\t' '!seen[$2]++ && $2!="" {print $2}')
[ ${#SCAN_LINES[@]} -gt 0 ] || die "No wireless networks found. Ensure the interface is up and try again."
echo ""
for i in "${!SCAN_LINES[@]}"; do
SSID="${SCAN_LINES[$i]}"
if [ "$SSID" = "$CURRENT_SSID" ]; then
echo -e " $((i+1))) ${GREEN}${SSID}${NC} ${CYAN}(connected)${NC}"
else
echo -e " $((i+1))) ${SSID}"
fi
done
echo ""
read -rp "Enter network number to join: " WIFI_CHOICE
[[ "$WIFI_CHOICE" =~ ^[0-9]+$ ]] || die "Invalid selection."
WIFI_IDX=$((WIFI_CHOICE - 1))
[ "$WIFI_IDX" -ge 0 ] && [ "$WIFI_IDX" -lt "${#SCAN_LINES[@]}" ] || die "Selection out of range."
NEW_SSID="${SCAN_LINES[$WIFI_IDX]}"
echo ""
read -rsp "Password for '${NEW_SSID}': " NEW_PASS
echo ""
[ -n "$NEW_PASS" ] || die "Password cannot be empty."
NETPLAN_BACKUP_DIR="/root/.config/tinyboard/netplan-backups"
mkdir -p "$NETPLAN_BACKUP_DIR"
mapfile -t NETPLAN_FILES < <(find /etc/netplan -maxdepth 1 -name '*.yaml' 2>/dev/null | sort)
if [ ${#NETPLAN_FILES[@]} -eq 0 ]; then
warn "No netplan config files found — WiFi credentials will not persist across reboots."
NETPLAN_FILE=""
elif [ ${#NETPLAN_FILES[@]} -eq 1 ]; then
NETPLAN_FILE="${NETPLAN_FILES[0]}"
else
echo ""
warn "Multiple netplan config files found:"
for i in "${!NETPLAN_FILES[@]}"; do
echo -e " $((i+1))) ${NETPLAN_FILES[$i]}"
done
echo ""
read -rp "Which file should be updated with the new WiFi credentials? [1]: " NP_CHOICE
NP_CHOICE="${NP_CHOICE:-1}"
[[ "$NP_CHOICE" =~ ^[0-9]+$ ]] || die "Invalid selection."
NP_IDX=$((NP_CHOICE - 1))
[ "$NP_IDX" -ge 0 ] && [ "$NP_IDX" -lt "${#NETPLAN_FILES[@]}" ] || die "Selection out of range."
NETPLAN_FILE="${NETPLAN_FILES[$NP_IDX]}"
fi
echo ""
info "Currently connected to: ${CURRENT_SSID:-none}"
info "Switching to: ${NEW_SSID}"
warn "Your SSH session will drop. Reconnect once the device joins '${NEW_SSID}'."
echo ""
read -rp "Proceed? [Y/n]: " CONFIRM
CONFIRM="${CONFIRM:-y}"
[[ "${CONFIRM,,}" == "y" ]] || { info "Aborted."; exit 0; }
if [ -n "$NETPLAN_FILE" ] && grep -q "access-points" "$NETPLAN_FILE" 2>/dev/null; then
BACKUP_FILE="$NETPLAN_BACKUP_DIR/$(basename "${NETPLAN_FILE}").$(date +%Y%m%d%H%M%S)"
cp "$NETPLAN_FILE" "$BACKUP_FILE"
info "Backed up: $NETPLAN_FILE$BACKUP_FILE"
python3 - "$NETPLAN_FILE" "$NEW_SSID" "$NEW_PASS" <<'PYEOF'
import sys, re
path, ssid, pw = sys.argv[1], sys.argv[2], sys.argv[3]
txt = open(path).read()
txt = re.sub(
r'(access-points:\s*\n\s+)["\']?[^"\':\n]+["\']?:\s*\n(\s+password:)[^\n]*',
lambda m: f'{m.group(1)}"{ssid}":\n{m.group(2)} "{pw}"',
txt
)
open(path, "w").write(txt)
PYEOF
info "Netplan config updated."
elif [ -n "$NETPLAN_FILE" ]; then
warn "$NETPLAN_FILE has no access-points section — skipping."
fi
info "Applying netplan — device will switch to '${NEW_SSID}' now..."
netplan apply
info "Waiting for association..."
ASSOCIATED=false
for i in $(seq 1 15); do
sleep 2
CONN_SSID=$(wpa_cli -i "$WIFI_IFACE" status 2>/dev/null | awk -F= '/^ssid=/{print $2}')
STATUS=$(wpa_cli -i "$WIFI_IFACE" status 2>/dev/null | awk -F= '/^wpa_state=/{print $2}')
if [ "$STATUS" = "COMPLETED" ] && [ "$CONN_SSID" = "$NEW_SSID" ]; then
ASSOCIATED=true
break
fi
warn "Attempt $i/15 — state: ${STATUS:-unknown}, ssid: ${CONN_SSID:-none}"
done
if [ "$ASSOCIATED" = "false" ]; then
die "Failed to associate with '${NEW_SSID}'. Check the password and try again. Backup at: $BACKUP_FILE"
fi
sleep 3
NEW_IP=$(ip -o -4 addr show "$WIFI_IFACE" 2>/dev/null | awk '{print $4}' | head -1)
if [ -n "$NEW_IP" ]; then
info "IP address: ${NEW_IP}"
else
warn "No IP assigned yet — DHCP may still be in progress."
fi
info "Connected to '${NEW_SSID}' successfully."
exit 0
;;
q|Q) q|Q)
exit 0 exit 0
;; ;;