a73x

57bc9a24

fix: two tools still ran muxd and muxa — one binary, mode words

a73x   2026-08-29 02:18

Commit message
fix: two tools still ran muxd and muxa — one binary, mode words

`zig-out/bin` holds only `mux`, so valgrind-quic.sh's defaults could
never be executable and collect.sh's `pgrep -a muxd` could never match.
The sh -n gate parses both files and passes them green either way.

collect.sh matches on the ARGS now: every mode is the same binary named
`mux`, so only the word after it separates a daemon from a client. It
still names muxd/muxa/muxweb in one place — flagging them as STALE when
a box's PATH has them, which is the install this bundle cannot explain.

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)"