Fix mkimage -B probe defeated by pipefail
The probe piped the candidate binary into grep to look for -B support. mkimage with no arguments prints usage and exits non-zero, and this script runs under `set -euo pipefail`, so the pipeline reported failure even when grep matched. Every candidate was rejected and the script failed closed with "no mkimage on PATH supports -B" while a capable mkimage 2025.01 sat first on PATH, making it impossible to build a boot.img at all. Neutralise the probed command's exit status before the pipe. Sentinel comments now bracket the probe so the new regression test extracts and exercises the shipping code rather than a copy of it. Closes #17 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T2D2KtdgwbhbF6Mo64eUrn
This commit is contained in:
+29
-7
@@ -159,14 +159,36 @@ ITS
|
|||||||
# already 512-aligns, so omitting the flag there is correct rather than a
|
# already 512-aligns, so omitting the flag there is correct rather than a
|
||||||
# fallback. project/build.sh prepends the SDK tool dir to PATH, so that
|
# fallback. project/build.sh prepends the SDK tool dir to PATH, so that
|
||||||
# binary IS what a build inside the SDK environment resolves.
|
# binary IS what a build inside the SDK environment resolves.
|
||||||
if mkimage 2>&1 | grep -q -- '-B '; then
|
# A -B-capable mkimage is REQUIRED, not preferred. The SDK vendors 2017.09,
|
||||||
_align_flag="-B 0x200"
|
# which has no -B, and project/build.sh:64 puts it first on PATH -- so the
|
||||||
else
|
# wrong one is what a build inside the SDK environment picks up. Measured:
|
||||||
_align_flag=""
|
# that binary produces metadata of 1064 bytes here, not a multiple of 512,
|
||||||
echo "== mkimage has no -B (vendor 2017.09); it 512-aligns natively"
|
# so FIT_ALIGN rounds it up and every payload is read late. It does NOT
|
||||||
|
# 512-align this .its natively. Rather than silently emit an image that
|
||||||
|
# fails on a panel, pick the first mkimage on PATH that supports -B and say
|
||||||
|
# plainly when there is none.
|
||||||
|
# >>> mkimage-probe (extracted verbatim by tests/mk-bootimg/run-probe-tests.sh)
|
||||||
|
MKIMAGE=""
|
||||||
|
_IFS_SAVE="$IFS"; IFS=:
|
||||||
|
for _d in $PATH; do
|
||||||
|
_c="$_d/mkimage"
|
||||||
|
[ -x "$_c" ] || continue
|
||||||
|
# mkimage with no args prints its usage and exits non-zero; under the
|
||||||
|
# pipefail set at the top of this file that failure would sink the whole
|
||||||
|
# pipeline, so the probe would reject every mkimage including good ones.
|
||||||
|
if { "$_c" 2>&1 || true; } | grep -q -- '-B '; then MKIMAGE="$_c"; break; fi
|
||||||
|
done
|
||||||
|
IFS="$_IFS_SAVE"
|
||||||
|
# <<< mkimage-probe
|
||||||
|
if [ -z "$MKIMAGE" ]; then
|
||||||
|
echo "FATAL: no mkimage on PATH supports -B (sub-image alignment)." >&2
|
||||||
|
echo " The SDK vendors mkimage 2017.09, which does not, and its output" >&2
|
||||||
|
echo " is not 512-aligned here. Install u-boot-tools (2025.01 works)" >&2
|
||||||
|
echo " and make sure it precedes the SDK tools on PATH." >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "== FIT (external data, -E -p 0x800 ${_align_flag:-no -B})"
|
echo "== FIT (external data, -E -p 0x800 -B 0x200) using $MKIMAGE"
|
||||||
( cd "$WORKDIR" && mkimage -f boot.its -E -p 0x800 ${_align_flag} boot.img >/dev/null )
|
( cd "$WORKDIR" && "$MKIMAGE" -f boot.its -E -p 0x800 -B 0x200 boot.img >/dev/null )
|
||||||
|
|
||||||
# Assert what U-Boot actually requires, on every build: the failure is silent --
|
# Assert what U-Boot actually requires, on every build: the failure is silent --
|
||||||
# a misread offset does not fail the build, it fails on a panel, and sometimes
|
# a misread offset does not fail the build, it fails on a panel, and sometimes
|
||||||
|
|||||||
Executable
+70
@@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Regression tests for the mkimage capability probe in build/mk-bootimg.sh.
|
||||||
|
#
|
||||||
|
# Guards issue #17: the probe ran the candidate binary and piped it into grep.
|
||||||
|
# mkimage with no arguments prints usage and exits non-zero, and mk-bootimg.sh
|
||||||
|
# runs under `set -euo pipefail`, so the pipeline reported failure even when
|
||||||
|
# grep matched. Every mkimage was rejected and the script failed closed with
|
||||||
|
# "no mkimage on PATH supports -B" while a capable mkimage sat first on PATH.
|
||||||
|
#
|
||||||
|
# The probe is extracted verbatim from mk-bootimg.sh between its sentinel
|
||||||
|
# comments, so these tests exercise the shipping code rather than a copy.
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
SCRIPT="$HERE/../../build/mk-bootimg.sh"
|
||||||
|
PROBE="$(mktemp)"; TMP="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$PROBE" "$TMP"' EXIT
|
||||||
|
|
||||||
|
sed -n '/^# >>> mkimage-probe/,/^# <<< mkimage-probe/p' "$SCRIPT" > "$PROBE"
|
||||||
|
grep -q 'MKIMAGE=' "$PROBE" || { echo "FAIL: probe not extracted (sentinels missing)"; exit 1; }
|
||||||
|
|
||||||
|
# The probe needs grep on PATH, but the real /usr/bin must stay off it or the
|
||||||
|
# host's own mkimage would answer these tests. Give it a directory holding
|
||||||
|
# nothing but grep.
|
||||||
|
mkdir -p "$TMP/util"
|
||||||
|
ln -s "$(command -v grep)" "$TMP/util/grep"
|
||||||
|
|
||||||
|
# A faithful stand-in for real mkimage: usage on stderr, non-zero exit.
|
||||||
|
mk_fake() { # mk_fake <dir> <supports-B:0|1>
|
||||||
|
mkdir -p "$1"
|
||||||
|
{ echo '#!/bin/sh'
|
||||||
|
echo 'echo "Usage: mkimage [-T type] -l image" >&2'
|
||||||
|
[ "$2" = 1 ] && echo 'echo " -B => align size in hex for FIT structure and header" >&2'
|
||||||
|
echo 'exit 1'
|
||||||
|
} > "$1/mkimage"
|
||||||
|
chmod +x "$1/mkimage"
|
||||||
|
}
|
||||||
|
|
||||||
|
fails=0
|
||||||
|
check() { # check <name> <expected-basename-or-empty> <dir...>
|
||||||
|
local name="$1" want="$2"; shift 2
|
||||||
|
local path=""; for d in "$@"; do path="$path${path:+:}$d"; done
|
||||||
|
path="$path${path:+:}$TMP/util"
|
||||||
|
local got
|
||||||
|
# /bin/bash by absolute path: a PATH holding only the fixture dirs cannot
|
||||||
|
# locate the interpreter itself.
|
||||||
|
got="$(TEST_PATH="$path" PROBE="$PROBE" /bin/bash -c \
|
||||||
|
'set -euo pipefail; PATH="$TEST_PATH"; . "$PROBE"; echo "${MKIMAGE:-}"' 2>/dev/null)"
|
||||||
|
got="${got##*/}"
|
||||||
|
if [ "$got" = "$want" ]; then
|
||||||
|
echo "PASS: $name"
|
||||||
|
else
|
||||||
|
echo "FAIL: $name (wanted '${want:-<none>}', got '${got:-<none>}')"
|
||||||
|
fails=$((fails + 1))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mk_fake "$TMP/good" 1
|
||||||
|
mk_fake "$TMP/old" 0
|
||||||
|
|
||||||
|
# The regression itself: a capable mkimage that exits non-zero must be accepted.
|
||||||
|
check "capable mkimage accepted despite non-zero exit" mkimage "$TMP/good"
|
||||||
|
# The guarantee the FATAL message depends on: no false positives.
|
||||||
|
check "mkimage without -B rejected" "" "$TMP/old"
|
||||||
|
# PATH order decides, and an incapable earlier entry must not stop the scan.
|
||||||
|
check "scan continues past an incapable mkimage" mkimage "$TMP/old" "$TMP/good"
|
||||||
|
check "no mkimage anywhere selects nothing" "" "$TMP/none"
|
||||||
|
|
||||||
|
[ "$fails" -eq 0 ] && echo "All mk-bootimg probe tests passed." || echo "$fails test(s) failed."
|
||||||
|
exit "$fails"
|
||||||
Reference in New Issue
Block a user