#!/bin/sh
#
# trame-wifi-debug - Collect wifi diagnostics into a tarball.
#
# Standalone, busybox/POSIX-safe. Run as root on the hardware that
# fails to connect, then send the produced /tmp/trame-wifi-debug-*.tar.gz
# back for analysis. The PSK / wifi key is redacted from every captured
# file so the tarball is safe to share.
#
#   sudo trame-wifi-debug          # read-only snapshot (safe, fast)
#   sudo trame-wifi-debug --live   # + a 12s wpa_supplicant -dd trace
#                                  #   that briefly drops the wifi but
#                                  #   pinpoints handshake/key failures
#
# Every probe is run under a timeout, so the script always finishes and
# always produces a tarball.
#
# Copyright (C) SliTaz GNU/Linux - BSD License
# Author: See AUTHORS files
#

: ${NETWORK_CONF_FILE:=/etc/network.conf}
: ${WPA_CONF_FILE:=/etc/wpa/wpa.conf}

# --live adds an intrusive trace: it stops wpa_supplicant, forces a
# reassociation and captures wpa_supplicant -dd. Default run is a
# read-only snapshot that never touches the live connection.
LIVE=no
case "$1" in --live|-l) LIVE=yes ;; esac

# Portable command timeout so no probe can ever hang the whole script.
# busybox shipped "timeout -t N" before switching to coreutils-style
# "timeout N"; detect which one works, fall back to running bare.
if timeout 1 true 2>/dev/null; then     TO="timeout 20"
elif timeout -t 1 true 2>/dev/null; then TO="timeout -t 20"
else                                     TO=""
fi

STAMP=$(date +%Y%m%d-%H%M%S 2>/dev/null || echo now)
OUT="/tmp/trame-wifi-debug-$STAMP"
TARBALL="$OUT.tar.gz"

mkdir -p "$OUT" || { echo "cannot create $OUT" >&2; exit 1; }

# section <title> -- everything piped in lands in one numbered report
# section, also echoed live so the operator sees progress.
REPORT="$OUT/report.txt"
section() {
	printf '\n===== %s =====\n' "$1" >> "$REPORT"
	echo "  + $1"
}

# run <label> <cmd...> -- record a command and its output (stderr too),
# noting plainly when the tool is absent rather than failing.
run() {
	label="$1"; shift
	printf '\n--- $ %s\n' "$label" >> "$REPORT"
	if command -v "${1}" >/dev/null 2>&1; then
		$TO "$@" >> "$REPORT" 2>&1
		rc=$?
		[ $rc -eq 0 ] || printf '[exit %s%s]\n' "$rc" \
			"$([ $rc -eq 124 ] && echo ' - timed out')" >> "$REPORT"
	else
		printf '[not installed: %s]\n' "$1" >> "$REPORT"
	fi
}

# Strip secrets from a conf before copying: psk="...", WIFI_KEY=...,
# wep keys, passwords. Keeps structure so the bug stays visible.
redact() {
	sed -e 's/\(psk=\)"[^"]*"/\1"<REDACTED>"/g' \
	    -e 's/\(WIFI_KEY=\)"[^"]*"/\1"<REDACTED>"/g' \
	    -e 's/\(WIFI_KEY=\)[^" ][^" ]*/\1<REDACTED>/g' \
	    -e 's/\(WIFI_WPA_PSK=\)"[^"]*"/\1"<REDACTED>"/g' \
	    -e 's/\(password[= ]*\).*/\1<REDACTED>/Ig'
}

printf 'trame-wifi-debug  %s\n' "$STAMP" > "$REPORT"
[ "$(id -u 2>/dev/null)" = 0 ] || \
	printf '\nWARNING: not run as root - scan/log/process info may be incomplete.\n' >> "$REPORT"

section "trame version"
run "trame --version" trame --version

section "kernel / system"
run "uname -a" uname -a
[ -r /etc/slitaz-release ] && run "slitaz-release" cat /etc/slitaz-release

section "wifi hardware (pci/usb)"
run "lspci wifi" sh -c 'lspci -k 2>/dev/null | grep -iA3 "net\|wireless\|wifi\|802.11"'
run "lsusb" lsusb

section "loaded modules"
run "lsmod" lsmod
# modinfo on the driver(s) bound to a wireless iface
for d in /sys/class/net/*/wireless; do
	[ -d "$d" ] || continue
	i=${d%/wireless}; i=${i##*/}
	drv=$(readlink "/sys/class/net/$i/device/driver" 2>/dev/null)
	drv=${drv##*/}
	[ -n "$drv" ] && run "modinfo $drv" modinfo "$drv"
done

section "firmware"
run "ls /lib/firmware" ls -R /lib/firmware
run "dmesg firmware/wifi" sh -c 'dmesg 2>/dev/null | grep -iE "firmware|iwl|ath|rtl|brcm|wlan|wifi|802.11|cfg80211|mac80211" | tail -n 80'

section "interfaces"
run "ip link" ip link
run "ip addr" ip addr
run "ifconfig -a" ifconfig -a
run "iwconfig" iwconfig
run "iw dev" iw dev
run "rfkill list" rfkill list

section "scan"
for d in /sys/class/net/*/wireless; do
	[ -d "$d" ] || continue
	i=${d%/wireless}; i=${i##*/}
	run "ifconfig $i up" ifconfig "$i" up
	run "iwlist $i scan" iwlist "$i" scan
	run "iw $i scan" iw dev "$i" scan
done

section "wpa_supplicant (read-only)"
run "wpa_supplicant -v" wpa_supplicant -v
run "ps wpa/dhcp" sh -c 'ps w 2>/dev/null | grep -iE "wpa_supplicant|udhcpc|dhcp" | grep -v grep'
# Query the real wireless iface with -i, NOT the first ctrl socket (which
# is often the p2p-dev-* virtual iface that just times out under nl80211).
# All read-only: status/list/signal never touch the connection.
for d in /sys/class/net/*/wireless; do
	[ -d "$d" ] || continue
	i=${d%/wireless}; i=${i##*/}
	run "wpa_cli -i $i status" wpa_cli -i "$i" status
	run "wpa_cli -i $i list_networks" wpa_cli -i "$i" list_networks
	run "wpa_cli -i $i signal_poll" wpa_cli -i "$i" signal_poll
done

# Intrusive decisive capture (only with --live): fully stop the boot
# wpa_supplicant (it holds the interface and would block a 2nd one),
# reset the iface, then run wpa_supplicant -dd in the foreground under a
# hard SIGKILL timeout so it CAN NOT hang. The trace + the dmesg right
# after state the cause plainly: scan? associate? "4-Way Handshake
# failed" / "WRONG KEY" / deauth reason. Then network.sh is restarted.
if [ "$LIVE" = yes ]; then
	section "wpa_supplicant -dd live trace (~15s)"
	WIFACE=$(for d in /sys/class/net/*/wireless; do [ -d "$d" ] && { x=${d%/wireless}; echo "${x##*/}"; break; }; done)
	WDRV=$(grep -s '^WIFI_WPA_DRIVER=' "$NETWORK_CONF_FILE" | cut -d'"' -f2)
	[ -z "$WDRV" ] && WDRV=nl80211
	# Hard kill form: prefer "timeout -s KILL N", else plain "$TO".
	if timeout -s KILL 1 true 2>/dev/null; then HK="timeout -s KILL 18"
	else HK="$TO"; fi
	if [ -n "$WIFACE" ] && command -v wpa_supplicant >/dev/null 2>&1; then
		printf 'iface=%s driver=%s\n' "$WIFACE" "$WDRV" >> "$REPORT"
		# Free the device: stop every wpa_supplicant + dhcp client, hard.
		killall -q wpa_supplicant udhcpc 2>/dev/null; sleep 1
		killall -q -9 wpa_supplicant 2>/dev/null; sleep 1
		ifconfig "$WIFACE" down 2>/dev/null; ifconfig "$WIFACE" up 2>/dev/null
		# Foreground, self-terminating: SIGKILL after 18s no matter what.
		$HK wpa_supplicant -dd -i "$WIFACE" -D"$WDRV" -c "$WPA_CONF_FILE" \
			>/tmp/_wpa_dd.$$ 2>&1
		# Full trace (redacted; -dd already prints the PSK as [REMOVED]).
		redact < "/tmp/_wpa_dd.$$" | grep -ivE "hexdump_ascii|hexdump\(" \
			> "$OUT/wpa-dd.txt"
		# Decisive lines inlined into the report for a quick read.
		grep -iE "CTRL-EVENT|state[ =:]|EAPOL|4-Way|handshake|WRONG|PSK may|pre-shared|deauth|disconnect|reason|authenticat|associat|Trying to associate|Associated with|Key negotiation|timed? ?out|No suitable|nl80211: Could not|Failed" \
			"$OUT/wpa-dd.txt" | tail -n 80 >> "$REPORT"
		rm -f "/tmp/_wpa_dd.$$"
		# Kernel side: the mac80211 auth/assoc/deauth reasons live here.
		printf '\n--- dmesg (wifi, after trace) ---\n' >> "$REPORT"
		dmesg 2>/dev/null | grep -iE "wlan|iwl|deauth|authenticat|associat|802.11|cfg80211|mac80211" \
			| tail -n 40 >> "$REPORT"
		# Restore boot networking (best-effort, hard-timed).
		[ -x /etc/init.d/network.sh ] && $HK /etc/init.d/network.sh restart >/dev/null 2>&1
	else
		printf '[no wireless iface or wpa_supplicant missing]\n' >> "$REPORT"
	fi
fi

section "dhcp / routing"
run "ip route" ip route
run "cat /etc/resolv.conf" cat /etc/resolv.conf

section "trame wifi (its own view)"
run "trame wifi status --json" trame wifi status --json
run "trame wifi list --json" trame wifi list --json
run "trame wifi scan --json" trame wifi scan --json

# --- config files (redacted copies) ---
section "config files (secrets redacted)"
if [ -r "$NETWORK_CONF_FILE" ]; then
	redact < "$NETWORK_CONF_FILE" > "$OUT/network.conf"
	printf 'saved network.conf (redacted)\n' >> "$REPORT"
else
	printf '%s not readable\n' "$NETWORK_CONF_FILE" >> "$REPORT"
fi
if [ -r "$WPA_CONF_FILE" ]; then
	redact < "$WPA_CONF_FILE" > "$OUT/wpa.conf"
	printf 'saved wpa.conf (redacted)\n' >> "$REPORT"
else
	printf '%s not readable\n' "$WPA_CONF_FILE" >> "$REPORT"
fi

# --- logs ---
section "logs"
for f in /var/log/messages /var/log/syslog /var/log/daemon.log \
         /var/log/wpa_supplicant.log /var/log/dmesg; do
	[ -r "$f" ] && tail -n 200 "$f" 2>/dev/null > "$OUT/$(basename "$f").tail" \
		&& printf 'saved %s (last 200 lines)\n' "$f" >> "$REPORT"
done
run "dmesg (full)" sh -c 'dmesg > "'"$OUT"'/dmesg.txt" 2>&1; echo saved dmesg.txt'

# --- pack ---
( cd /tmp && tar czf "$TARBALL" "$(basename "$OUT")" 2>/dev/null )
rm -rf "$OUT"

echo
if [ -f "$TARBALL" ]; then
	echo "Done. Send this file back:"
	echo "  $TARBALL"
	ls -lh "$TARBALL" 2>/dev/null
else
	echo "Failed to create tarball; raw data left in $OUT" >&2
	exit 1
fi
