@@ -21,16 +21,87 @@ if [ ! -f "$SOURCE_BINARY" ]; then
2121fi
2222
2323mkdir -p " $INSTALL_DIR " " $METADATA_DIR "
24- cp " $SOURCE_BINARY " " $TARGET_BINARY "
25- chmod +x " $TARGET_BINARY "
2624
27- case " $( uname -s) " in
28- Darwin)
29- xattr -dr com.apple.quarantine " $TARGET_BINARY " 2> /dev/null || true
30- codesign --force --sign - " $TARGET_BINARY " 2> /dev/null || true
31- codesign -v --verbose=4 " $TARGET_BINARY " 2> /dev/null || true
32- ;;
33- esac
25+ # Portable musl install: when this archive carries the musl runtime (bin/lib/)
26+ # AND the system lacks the musl loader (old-glibc distros like CentOS/RHEL 7),
27+ # install the real binary under libexec, point its ELF interpreter at a per-user
28+ # loader via an in-place edit (no file growth -> bun's appended payload stays
29+ # intact), and put a small wrapper on PATH. On Alpine the loader already exists,
30+ # so we fall through to the plain copy below.
31+ MUSL_LOADER_SRC=" ${SCRIPT_DIR} /lib/ld-musl-x86_64.so.1"
32+ if [ -f " $MUSL_LOADER_SRC " ] && [ ! -e " /lib/ld-musl-x86_64.so.1" ]; then
33+ LIBEXEC=" $( dirname " $INSTALL_DIR " ) /libexec/cz-cli"
34+ mkdir -p " $LIBEXEC "
35+ cp -f " $SOURCE_BINARY " " $LIBEXEC /cz-cli.real"
36+ chmod +x " $LIBEXEC /cz-cli.real"
37+ rm -rf " $LIBEXEC /lib" ; cp -rf " ${SCRIPT_DIR} /lib" " $LIBEXEC /lib"
38+
39+ OLD=" /lib/ld-musl-x86_64.so.1" # original ELF interpreter, 24 chars
40+ INTERP=" "
41+ for p in " $HOME /.ld.so" " $HOME /.cz-ld.so" " /tmp/ld-musl-x86_64.so.1" ; do
42+ [ " ${# p} " -le 24 ] || continue
43+ d=$( dirname " $p " ) ; [ -d " $d " ] && [ -w " $d " ] || continue
44+ INTERP=" $p " ; break
45+ done
46+ [ -n " $INTERP " ] || { print_error " no writable loader path <=24 chars (\$ HOME too long?)" ; exit 1; }
47+ echo " ELF interpreter -> $INTERP (${# INTERP} chars)"
48+
49+ # In-place patch .interp. PT_INTERP lives at a build-fixed offset (568) in the
50+ # ELF header region; we do NOT scan the whole ~140MB binary. Verify the slot by
51+ # reading it back; only on mismatch scan the first 64 KiB (headers live at the
52+ # start). Every write is guarded by a read-back so a wrong offset aborts rather
53+ # than corrupts.
54+ BIN=" $LIBEXEC /cz-cli.real"
55+ read_slot () { dd if=" $BIN " bs=1 skip=" $1 " count=24 2> /dev/null; }
56+ OFF=" "
57+ if [ " $( read_slot 568) " = " $OLD " ]; then
58+ OFF=568
59+ else
60+ HEAD=$( mktemp)
61+ dd if=" $BIN " bs=4096 count=16 of=" $HEAD " 2> /dev/null # first 64 KiB only
62+ M=$( grep -aboF -- " $OLD " " $HEAD " 2> /dev/null || true) ; OFF=${M%%:* }
63+ rm -f " $HEAD "
64+ fi
65+ case " $OFF " in
66+ ' ' |* [!0-9]* ) print_error " musl interpreter string not found in binary" ; exit 1 ;;
67+ esac
68+ [ " $( read_slot " $OFF " ) " = " $OLD " ] || { print_error " unexpected bytes at interp offset $OFF " ; exit 1; }
69+ dd if=/dev/zero of=" $BIN " bs=1 seek=" $OFF " count=24 conv=notrunc 2> /dev/null
70+ printf ' %s' " $INTERP " | dd of=" $BIN " bs=1 seek=" $OFF " conv=notrunc 2> /dev/null
71+ [ " $( read_slot " $OFF " | tr -d ' \0' ) " = " $INTERP " ] || { print_error " interp patch verification failed" ; exit 1; }
72+
73+ # Wrapper on PATH: ensure the loader is present, set the lib path, exec the real
74+ # binary. This becomes $TARGET_BINARY so cz-agent and callers work unchanged.
75+ cat > " $TARGET_BINARY " << EOF
76+ #!/bin/sh
77+ LIBEXEC="$LIBEXEC "
78+ INTERP="$INTERP "
79+ [ -f "\$ INTERP" ] || cp -f "\$ LIBEXEC/lib/ld-musl-x86_64.so.1" "\$ INTERP"
80+ export LD_LIBRARY_PATH="\$ LIBEXEC/lib\$ {LD_LIBRARY_PATH:+:\$ LD_LIBRARY_PATH}"
81+ exec "\$ LIBEXEC/cz-cli.real" "\$ @"
82+ EOF
83+ chmod +x " $TARGET_BINARY "
84+
85+ # Seed the loader now so the first run is clean, then smoke-test. A failure here
86+ # is almost always a missing-AVX2 CPU (SIGILL) — surface it at install time.
87+ [ -f " $INTERP " ] || cp -f " $LIBEXEC /lib/ld-musl-x86_64.so.1" " $INTERP "
88+ if ! " $TARGET_BINARY " --version > /dev/null 2>&1 ; then
89+ print_error " installed binary failed to run (musl portable)."
90+ print_error " If this CPU lacks AVX2 (grep -c avx2 /proc/cpuinfo == 0) a baseline build is required."
91+ exit 1
92+ fi
93+ else
94+ cp " $SOURCE_BINARY " " $TARGET_BINARY "
95+ chmod +x " $TARGET_BINARY "
96+
97+ case " $( uname -s) " in
98+ Darwin)
99+ xattr -dr com.apple.quarantine " $TARGET_BINARY " 2> /dev/null || true
100+ codesign --force --sign - " $TARGET_BINARY " 2> /dev/null || true
101+ codesign -v --verbose=4 " $TARGET_BINARY " 2> /dev/null || true
102+ ;;
103+ esac
104+ fi
34105
35106# cz-agent: convenience wrapper for `cz-cli agent` (same dir, already on PATH;
36107# works in any shell and in scripts, unlike a shell alias).
0 commit comments