57bc9a24
fix: two tools still ran muxd and muxa — one binary, mode words
a73x 2026-08-29 02:18
Commit message
tools/collect.sh
| Old | New | ||
|---|---|---|---|
| @@ -4,13 +4,13 @@ | |||
| 4 | # | 4 | # |
| 5 | # tools/collect.sh [--sock PATH]... [--host SSHHOST]... [--hub PORT] [--log-lines N] | 5 | # tools/collect.sh [--sock PATH]... [--host SSHHOST]... [--hub PORT] [--log-lines N] |
| 6 | # | 6 | # |
| 7 | # Collects: binary versions, the local daemon log, `muxd stats` per | 7 | # Collects: the binary's version, the local daemon log, `mux d stats` per |
| 8 | # --sock, the hub's /tiles if --hub names a port, and per --host (over | 8 | # --sock, the hub's /tiles if --hub names a port, and per --host (over |
| 9 | # ssh): version, stats, log tail, key FINGERPRINT. Key material itself | 9 | # ssh): version, stats, log tail, key FINGERPRINT. Key material itself |
| 10 | # is never read — fingerprints are what a key-drift diagnosis needs, | 10 | # is never read — fingerprints are what a key-drift diagnosis needs, |
| 11 | # and were what the M17 field trial had to assemble by hand. | 11 | # and were what the M17 field trial had to assemble by hand. |
| 12 | # | 12 | # |
| 13 | # Screen contents are NOT collected: `muxd dump` shows whatever the | 13 | # Screen contents are NOT collected: `mux d dump` shows whatever the |
| 14 | # session shows, and a diagnostic bundle should be safe to paste. | 14 | # session shows, and a diagnostic bundle should be safe to paste. |
| 15 | set -u | 15 | set -u |
| 16 | 16 | ||
| @@ -34,10 +34,13 @@ section() { printf '\n===== %s =====\n' "$1"; } | |||
| 34 | # instant is the only clock the bundle has. | 34 | # instant is the only clock the bundle has. |
| 35 | printf 'mux diagnostic bundle: %s on %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$(uname -n)" | 35 | printf 'mux diagnostic bundle: %s on %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$(uname -n)" |
| 36 | 36 | ||
| 37 | section "versions (local)" | 37 | section "version (local)" |
| 38 | for b in muxd mux muxweb; do | 38 | # One binary since the modes became words; muxd, muxa and muxweb are gone, |
| 39 | p=$(command -v "$b" 2>/dev/null) || { echo "$b: not on PATH"; continue; } | 39 | # and a box that still has them has an install this bundle cannot explain. |
| 40 | printf '%s: %s (%s)\n' "$b" "$("$p" --version 2>&1)" "$p" | 40 | p=$(command -v mux 2>/dev/null) && printf 'mux: %s (%s)\n' "$("$p" --version 2>&1)" "$p" \ |
| 41 | || echo "mux: not on PATH" | ||
| 42 | for old in muxd muxa muxweb; do | ||
| 43 | o=$(command -v "$old" 2>/dev/null) && printf 'STALE %s: %s (%s)\n' "$old" "$("$o" --version 2>&1)" "$o" | ||
| 41 | done | 44 | done |
| 42 | 45 | ||
| 43 | section "local key fingerprint" | 46 | section "local key fingerprint" |
| @@ -58,12 +61,14 @@ else | |||
| 58 | fi | 61 | fi |
| 59 | 62 | ||
| 60 | section "local daemons (observed, not claimed)" | 63 | section "local daemons (observed, not claimed)" |
| 61 | pgrep -a muxd 2>/dev/null || echo "no muxd processes" | 64 | # Matched on the ARGS, not the name: every mode is the same binary called |
| 62 | pgrep -a muxweb 2>/dev/null || echo "no muxweb processes" | 65 | # `mux`, so only the mode word after it tells a daemon from a client. |
| 66 | pgrep -af 'mux d run' 2>/dev/null || echo "no mux daemons" | ||
| 67 | pgrep -af 'mux web' 2>/dev/null || echo "no mux hubs" | ||
| 63 | 68 | ||
| 64 | for s in $SOCKS; do | 69 | for s in $SOCKS; do |
| 65 | section "stats: $s" | 70 | section "stats: $s" |
| 66 | muxd stats --sock "$s" 2>&1 | 71 | mux d stats --sock "$s" 2>&1 |
| 67 | done | 72 | done |
| 68 | 73 | ||
| 69 | if [ -n "$HUB" ]; then | 74 | if [ -n "$HUB" ]; then |
| @@ -81,15 +86,15 @@ for h in $HOSTS; do | |||
| 81 | # One ssh round trip per box, everything in one remote shell. BatchMode | 86 | # One ssh round trip per box, everything in one remote shell. BatchMode |
| 82 | # so an interactive prompt fails fast instead of hanging the bundle. | 87 | # so an interactive prompt fails fast instead of hanging the bundle. |
| 83 | ssh -o BatchMode=yes -o ConnectTimeout=10 "$h" ' | 88 | ssh -o BatchMode=yes -o ConnectTimeout=10 "$h" ' |
| 84 | printf "version: %s\n" "$(muxd --version 2>&1)" | 89 | printf "version: %s\n" "$(mux --version 2>&1)" |
| 85 | k=~/.config/mux/key | 90 | k=~/.config/mux/key |
| 86 | if [ -f "$k" ]; then | 91 | if [ -f "$k" ]; then |
| 87 | printf "key: %s %s\n" "$(sha256sum "$k" | cut -c1-16)" "$k" | 92 | printf "key: %s %s\n" "$(sha256sum "$k" | cut -c1-16)" "$k" |
| 88 | else | 93 | else |
| 89 | echo "key: none" | 94 | echo "key: none" |
| 90 | fi | 95 | fi |
| 91 | pgrep -a muxd 2>/dev/null || echo "no muxd processes" | 96 | pgrep -af 'mux d run' 2>/dev/null || echo "no mux daemons" |
| 92 | echo "stats: $(muxd stats 2>&1)" | 97 | echo "stats: $(mux d stats 2>&1)" |
| 93 | l=${XDG_STATE_HOME:-$HOME/.local/state}/mux/muxd.log | 98 | l=${XDG_STATE_HOME:-$HOME/.local/state}/mux/muxd.log |
| 94 | if [ -f "$l" ]; then | 99 | if [ -f "$l" ]; then |
| 95 | printf "log %s (%s bytes), last '"$LINES"' lines:\n" "$l" "$(wc -c < "$l")" | 100 | printf "log %s (%s bytes), last '"$LINES"' lines:\n" "$l" "$(wc -c < "$l")" |
tools/valgrind-quic.sh
| Old | New | ||
|---|---|---|---|
| @@ -8,17 +8,17 @@ | |||
| 8 | # DebugAllocator verdict (6a) never sees. Run it by hand after touching | 8 | # DebugAllocator verdict (6a) never sees. Run it by hand after touching |
| 9 | # the QUIC stack or bumping deps/quic. | 9 | # the QUIC stack or bumping deps/quic. |
| 10 | # | 10 | # |
| 11 | # Usage: tools/valgrind-quic.sh [path/to/muxd [path/to/muxa]] | 11 | # Usage: tools/valgrind-quic.sh [path/to/mux] |
| 12 | # (defaults to zig-out/bin — build first with `zig build -Dcpu=x86_64_v3`; | 12 | # (defaults to zig-out/bin — build first with `zig build -Dcpu=x86_64_v3`; |
| 13 | # valgrind 3.25 decodes no AVX-512, and a native build on a machine that | 13 | # valgrind 3.25 decodes no AVX-512, and a native build on a machine that |
| 14 | # has it SIGILLs at startup. The QUIC deps' zigcc-native wrapper already | 14 | # has it SIGILLs at startup. The QUIC deps' zigcc-native wrapper already |
| 15 | # pins x86_64_v3 for the same reason. Debug build is the point: Zig debug | 15 | # pins x86_64_v3 for the same reason. Debug build is the point: Zig debug |
| 16 | # builds carry valgrind client requests natively.) | 16 | # builds carry valgrind client requests natively.) |
| 17 | set -eu | 17 | set -eu |
| 18 | MUXD="${1:-zig-out/bin/muxd}" | 18 | # One binary, two modes: `d` is the daemon and `a` the agent client. |
| 19 | MUXA="${2:-zig-out/bin/muxa}" | 19 | MUX="${1:-zig-out/bin/mux}" |
| 20 | command -v valgrind >/dev/null || { echo "valgrind is not installed"; exit 1; } | 20 | command -v valgrind >/dev/null || { echo "valgrind is not installed"; exit 1; } |
| 21 | [ -x "$MUXD" ] && [ -x "$MUXA" ] || { echo "binaries missing — run zig build"; exit 1; } | 21 | [ -x "$MUX" ] || { echo "binary missing — run zig build"; exit 1; } |
| 22 | TMP="${TMPDIR:-/tmp}/mux-valgrind-$$" | 22 | TMP="${TMPDIR:-/tmp}/mux-valgrind-$$" |
| 23 | mkdir -p "$TMP" | 23 | mkdir -p "$TMP" |
| 24 | VGPID="" | 24 | VGPID="" |
| @@ -27,16 +27,16 @@ trap 'exit 130' INT | |||
| 27 | trap 'exit 143' TERM | 27 | trap 'exit 143' TERM |
| 28 | # Hermetic key: keygen into a private XDG home, --key it explicitly. | 28 | # Hermetic key: keygen into a private XDG home, --key it explicitly. |
| 29 | XDG_CONFIG_HOME="$TMP/cfg"; export XDG_CONFIG_HOME | 29 | XDG_CONFIG_HOME="$TMP/cfg"; export XDG_CONFIG_HOME |
| 30 | "$MUXD" keygen > /dev/null | 30 | "$MUX" d keygen > /dev/null |
| 31 | KEY="$TMP/cfg/mux/key" | 31 | KEY="$TMP/cfg/mux/key" |
| 32 | SOCK="$TMP/vg.sock" | 32 | SOCK="$TMP/vg.sock" |
| 33 | # muxd's own stdout+stderr, kept apart from valgrind's --log-file so the two | 33 | # The daemon's own stdout+stderr, kept apart from valgrind's --log-file so the two |
| 34 | # accounts stay readable — and so the bind refusal below can be read back. | 34 | # accounts stay readable — and so the bind refusal below can be read back. |
| 35 | DLOG="$TMP/muxd.log" | 35 | DLOG="$TMP/mux-d.log" |
| 36 | # The port is derived from the pid, which makes it a GUESS in two ways: this | 36 | # The port is derived from the pid, which makes it a GUESS in two ways: this |
| 37 | # band is inside the ephemeral range on a box whose ip_local_port_range has | 37 | # band is inside the ephemeral range on a box whose ip_local_port_range has |
| 38 | # been lowered, so an outgoing connection can already hold the number, and | 38 | # been lowered, so an outgoing connection can already hold the number, and |
| 39 | # two runs whose pids are congruent mod 900 derive the same one. muxd sets no | 39 | # two runs whose pids are congruent mod 900 derive the same one. The daemon sets no |
| 40 | # SO_REUSEADDR and refuses to share a UDP port, so both show up identically — | 40 | # SO_REUSEADDR and refuses to share a UDP port, so both show up identically — |
| 41 | # the daemon says `a daemon is already listening on udp ...` and exits — and | 41 | # the daemon says `a daemon is already listening on udp ...` and exits — and |
| 42 | # the answer to both is the next candidate. The port this script goes on to | 42 | # the answer to both is the next candidate. The port this script goes on to |
| @@ -48,7 +48,7 @@ tries=0 | |||
| 48 | while :; do | 48 | while :; do |
| 49 | : > "$DLOG" | 49 | : > "$DLOG" |
| 50 | valgrind --leak-check=full --error-exitcode=99 --log-file="$TMP/vg.log" \ | 50 | valgrind --leak-check=full --error-exitcode=99 --log-file="$TMP/vg.log" \ |
| 51 | "$MUXD" run --sock "$SOCK" --shell /bin/sh \ | 51 | "$MUX" d run --sock "$SOCK" --shell /bin/sh \ |
| 52 | --quic "127.0.0.1:$PORT" --key "$KEY" > "$DLOG" 2>&1 & | 52 | --quic "127.0.0.1:$PORT" --key "$KEY" > "$DLOG" 2>&1 & |
| 53 | VGPID=$! | 53 | VGPID=$! |
| 54 | # valgrind start is SLOW; give the bind a full minute. Bail early if the | 54 | # valgrind start is SLOW; give the bind a full minute. Bail early if the |
| @@ -76,13 +76,13 @@ while :; do | |||
| 76 | PORT=$((PORT + PORT_STEP)) | 76 | PORT=$((PORT + PORT_STEP)) |
| 77 | echo "udp port taken; retrying on $PORT" | 77 | echo "udp port taken; retrying on $PORT" |
| 78 | done | 78 | done |
| 79 | echo "muxd is up under valgrind on udp $PORT" | 79 | echo "the daemon is up under valgrind on udp $PORT" |
| 80 | # One real command over QUIC — handshake, frames, teardown — with a | 80 | # One real command over QUIC — handshake, frames, teardown — with a |
| 81 | # timeout sized for valgrind's clock, then a clean stop so every exit | 81 | # timeout sized for valgrind's clock, then a clean stop so every exit |
| 82 | # path (and the allocator teardown) runs. | 82 | # path (and the allocator teardown) runs. |
| 83 | "$MUXA" run --quic "127.0.0.1:$PORT" --key "$KEY" --timeout 60000 "echo vg-probe" \ | 83 | "$MUX" a run --quic "127.0.0.1:$PORT" --key "$KEY" --timeout 60000 "echo vg-probe" \ |
| 84 | || echo "muxa run failed under valgrind (timing?) — the leak summary below still stands" | 84 | || echo "mux a run failed under valgrind (timing?) — the leak summary below still stands" |
| 85 | "$MUXD" stop --sock "$SOCK" || kill "$VGPID" 2>/dev/null || true | 85 | "$MUX" d stop --sock "$SOCK" || kill "$VGPID" 2>/dev/null || true |
| 86 | wait "$VGPID" && VGRC=0 || VGRC=$? | 86 | wait "$VGPID" && VGRC=0 || VGRC=$? |
| 87 | VGPID="" | 87 | VGPID="" |
| 88 | echo "valgrind exit: $VGRC (99 = valgrind-detected errors)" | 88 | echo "valgrind exit: $VGRC (99 = valgrind-detected errors)" |