From 1de36289a5d2e77000b3b5254970c009867de284 Mon Sep 17 00:00:00 2001 From: Adolfo Delorenzo Date: Thu, 14 May 2026 16:02:21 -0600 Subject: [PATCH] fix(arm64): tr -d '[:space:]' is parsed as literal char-set by busybox 1.30.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ubuntu's busybox-static 1.30.1 (which we use for the ARM64 rootfs after piCore64's BusyBox crashes in QEMU virt) doesn't recognize POSIX character classes. `tr -d '[:space:]'` is interpreted as "delete any of the literal characters [, :, s, p, a, c, e, ]" — so every s/p/a/c/e in module names and sysctl keys gets eaten. Symptoms in the boot log: virtio_net -> virtio_nt (e dropped) overlay -> ovrly (e, a dropped) bridge -> bridg (e dropped) nf_conntrack -> nf_onntrk (c, a, c dropped) net.bridge.bridge-nf-call-iptables -> nt.bridg.bridg-nf-ll-itbl Fix: use explicit whitespace chars `tr -d ' \t\r\n'` in both 30-kernel-modules.sh and 40-sysctl.sh. Works under any tr implementation. Also: filter functions.sh out of the init.d stage-copy loop. It's a shared library (sourced by init.sh), not a numbered stage. With it in init.d the main loop runs it as a stage after stage 90, then panics with "Init completed without exec'ing KubeSolo". Co-Authored-By: Claude Opus 4.7 (1M context) --- build/scripts/inject-kubesolo.sh | 7 ++++++- init/lib/30-kernel-modules.sh | 6 +++++- init/lib/40-sysctl.sh | 7 +++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/build/scripts/inject-kubesolo.sh b/build/scripts/inject-kubesolo.sh index 97a7236..960e8eb 100755 --- a/build/scripts/inject-kubesolo.sh +++ b/build/scripts/inject-kubesolo.sh @@ -84,10 +84,15 @@ if [ "$INJECT_ARCH" = "arm64" ] && [ -x /bin/busybox ]; then fi fi -# Init stages +# Init stages — copy NN-name.sh files only. functions.sh is a shared library +# (sourced by init.sh proper), not a numbered stage; if it ends up in init.d +# the main loop will try to run it as a stage and fail. mkdir -p "$ROOTFS/usr/lib/kubesolo-os/init.d" for stage in "$PROJECT_ROOT"/init/lib/*.sh; do [ -f "$stage" ] || continue + case "$(basename "$stage")" in + functions.sh) continue ;; + esac cp "$stage" "$ROOTFS/usr/lib/kubesolo-os/init.d/" chmod +x "$ROOTFS/usr/lib/kubesolo-os/init.d/$(basename "$stage")" done diff --git a/init/lib/30-kernel-modules.sh b/init/lib/30-kernel-modules.sh index 3a0c601..bf4bca7 100755 --- a/init/lib/30-kernel-modules.sh +++ b/init/lib/30-kernel-modules.sh @@ -16,7 +16,11 @@ while IFS= read -r mod; do case "$mod" in '#'*|'') continue ;; esac - mod="$(echo "$mod" | tr -d '[:space:]')" + # NOTE: do NOT use tr -d '[:space:]' — Ubuntu's busybox-static 1.30.1 (used + # in the ARM64 rootfs override) doesn't parse POSIX char classes and treats + # them as a literal set, deleting [, :, s, p, a, c, e, ]. Use explicit + # whitespace chars instead so the same script works under any tr. + mod="$(printf '%s' "$mod" | tr -d ' \t\r\n')" if modprobe "$mod" 2>/dev/null; then LOADED=$((LOADED + 1)) else diff --git a/init/lib/40-sysctl.sh b/init/lib/40-sysctl.sh index 5869090..074820e 100755 --- a/init/lib/40-sysctl.sh +++ b/init/lib/40-sysctl.sh @@ -8,8 +8,11 @@ for conf in /etc/sysctl.d/*.conf; do case "$key" in '#'*|'') continue ;; esac - key="$(echo "$key" | tr -d '[:space:]')" - value="$(echo "$value" | tr -d '[:space:]')" + # NOTE: do NOT use tr -d '[:space:]' — see 30-kernel-modules.sh for the + # rationale. Use explicit whitespace chars so this works under + # Ubuntu's busybox-static tr too. + key="$(printf '%s' "$key" | tr -d ' \t\r\n')" + value="$(printf '%s' "$value" | tr -d ' \t\r\n')" if [ -n "$key" ] && [ -n "$value" ]; then sysctl -w "${key}=${value}" >/dev/null 2>&1 || \ log_warn "Failed to set sysctl: ${key}=${value}"