Files
MeowOS-For-R3P2/scripts/build/repack_repro.sh
T
tower 28fbc6094a fix(build): M56 r1 评审三条 P2 + 一条观察(脚本权限/可复现口径注释/watchdog 参数去内联+入门禁/REPACK 显式失败)
- P2-1 repack_repro.sh 提交为 100755(scripts/build/ 下唯一非 755 的 .sh,而头注释就让人直接执行)
- P2-2 注释与事实对齐:写明 squashfs/分片/ota_update.in 可复现,但 .upt 仍有 93 字节
  Rock Ridge TF backup date 差异(genisoimage 无覆盖开关),验收口径仍是 体积+unpack 0 diff+进包 md5
- P2-3 watchdog 参数不再内联复制:build_watchdog.sh 认 ZIGCC(照 build_netmgrd.sh 口径),
  rebuild_binaries.sh 改成调它;meow_watchdog 加入 test_time32_abi.sh 的 BUILD_TARGETS(11 个)。
  改后重编仍逐字节 25f769509a43d0f66287efd456c64281 / 100116,与内联那版一致
- 观察1:REPACK 显式指定但不存在 -> exit 1(此前会静默回退到不可复现的旧 repack.sh)
2026-11-12 08:44:27 +08:00

189 lines
8.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ============================================================================
# repack_repro.sh — .upt 打包(mksquashfs + 分片 md5 链 + ISO),时间戳尽量可复现
#
# 与 hiby_os_crack/scripts/repack.sh 的产物布局逐字节等价(ota_update.in / ota_v0.ok /
# ota_config.in / rootfs.squashfs.NNNN.<prev-md5> / ota_md5_rootfs.squashfs.<md5>),
# 只把墙钟时间从「squashfs + 元数据」里拿掉。**可复现到什么程度(实测口径,别夸大)**:
# ✅ bytes-reproducible:rootfs.squashfs、ota_md5_rootfs.squashfs.*、ota_update.in、
# 分片文件名与内容、xImage 侧 —— 同一输入连续两次打包全部相同。
# ❌ not bytes-reproducible:`.upt`(ISO)本身。genisoimage 会给 Rock Ridge `TF`
# 记录写 **backup date**(TF flag=0x1a,第三个 7 字节字段),该字段取墙钟且**没有
# 覆盖开关**(`-creation-date` 只定卷的创建/修改时间)。M56 实测两次打包 `cmp -l`
# 恰好 93 字节不同,全在该字段(分钟字节),载荷 0 差异。
# 因此 `.upt` 的验收口径仍是:**体积 + unpack 0 diff + 进包 md5**。
#
# 时间戳处理:
# 1) squashfs:`-repro-time <epoch>`(= -mkfs-time + -inode-time;mksquashfs 4.7 起)。
# 只加 -all-time 不够 —— 超级块的 mkfs_time 仍是墙钟(M60 实测)。本脚本按
# `mksquashfs -help-all` 能力探测,依次尝试:
# -repro-time <t> (4.7+)
# -mkfs-time <t> -inode-time <t> (4.6)
# -mkfs-time <t> -all-time <t> (老版本)
# 都没有 → 告警并按旧口径(体积 + unpack 0 diff + 进包 md5)出货。
# 2) ISO:卷创建时间用 `-creation-date <秒数>` 固定,并把暂存目录里所有文件/目录的
# mtime touch 到同一 epoch(ISO 目录记录取文件 mtime)。backup date 无解,见上。
#
# 用法:
# repack_repro.sh -i <squashfs-root> -k <xImage> -o <out.upt>
# SOURCE_DATE_EPOCH=1735689600 覆盖固定时间(默认见 REPRO_EPOCH)。
# ============================================================================
set -euo pipefail
REPRO_EPOCH="${SOURCE_DATE_EPOCH:-1735689600}" # 2025-01-01T00:00:00Z
TEMP_DIR="${TMPDIR:-/tmp}/meow-repack-repro"
# 本机(Termux)没有 /usr/bin/mksquashfs:fw 工具集放在 ~/.cache/fwtools/shims
# (glibc 版 mksquashfs/unsquashfs/genisoimage 经 grun 运行)。
if ! command -v mksquashfs >/dev/null 2>&1 && [ -d "$HOME/.cache/fwtools/shims" ]; then
PATH="$HOME/.cache/fwtools/shims:$PATH"
fi
show_help() {
sed -n '2,30p' "$0" | sed 's/^# \{0,1\}//'
}
input_root=""
input_ximage=""
output_file=""
while getopts ":i:k:o:h" opt; do
case "$opt" in
i) input_root="$OPTARG" ;;
k) input_ximage="$OPTARG" ;;
o) output_file="$OPTARG" ;;
h) show_help; exit 0 ;;
:) echo "Error: -$OPTARG 需要参数" >&2; exit 1 ;;
\?) echo "Error: 未知参数 -$OPTARG" >&2; exit 1 ;;
esac
done
[ -n "$input_root" ] || { echo "Error: -i 必填" >&2; exit 1; }
[ -n "$input_ximage" ] || { echo "Error: -k 必填" >&2; exit 1; }
[ -n "$output_file" ] || { echo "Error: -o 必填" >&2; exit 1; }
[ -d "$input_root" ] || { echo "Error: '$input_root' 不存在" >&2; exit 1; }
[ -f "$input_ximage" ] || { echo "Error: '$input_ximage' 不存在" >&2; exit 1; }
command -v mksquashfs >/dev/null 2>&1 || { echo "Error: 缺 mksquashfs" >&2; exit 1; }
command -v genisoimage >/dev/null 2>&1 || echo "WARN: 无 genisoimage,将尝试 mkisofs" >&2
input_root=$(realpath "$input_root")
input_ximage=$(realpath "$input_ximage")
output_file=$(realpath -m "$output_file")
[ -e "$output_file" ] && rm -f "$output_file"
ISO_TOOL=genisoimage
command -v genisoimage >/dev/null 2>&1 || ISO_TOOL=mkisofs
# ---- squashfs 时间戳参数:按能力探测 ----------------------------------------
sq_help="$(mksquashfs -help-all 2>/dev/null || mksquashfs -help 2>/dev/null || true)"
sq_time=()
# 直接用 case 匹配字符串,**不要**写成 `printf ... | grep -q`:脚本是 set -o pipefail,
# grep -q 命中后立刻退出 → printf 收 SIGPIPE(141) → 整条管道判失败 → 参数被静默丢掉
# (M56 踩过一次:ISO 卷时间因此回落成墙钟,两次打包不一致)。
case "$sq_help" in
*-repro-time*) sq_time=(-repro-time "$REPRO_EPOCH") ;;
*-mkfs-time*)
case "$sq_help" in
*-inode-time*) sq_time=(-mkfs-time "$REPRO_EPOCH" -inode-time "$REPRO_EPOCH") ;;
*-all-time*) sq_time=(-mkfs-time "$REPRO_EPOCH" -all-time "$REPRO_EPOCH") ;;
esac ;;
esac
if [ "${#sq_time[@]}" -eq 0 ]; then
echo "WARN: 本机 mksquashfs 不支持 -mkfs-time/-repro-time —— squashfs 内不含可复现时间戳," >&2
echo " 只能按旧口径(体积 + unpack 0 diff + 进包 md5)验收。" >&2
fi
# genisoimage 1.1.11 的 -creation-date 只吃得下「秒数」形式:传 YYYYMMDDhhmmsscc
# (本工具 man 里推荐的 16 位串)会直接 *** buffer overflow detected *** 崩掉。
# 传秒数时 PVD 的 Creation/Modif. Time 都被写成同一时刻(xorriso -pvd_info 可核),
# 正是可复现需要的样子。
iso_date="$REPRO_EPOCH"
iso_time=()
iso_help="$("$ISO_TOOL" -help 2>&1 || true)"
case "$iso_help" in
*-creation-date*) iso_time=(-creation-date "$iso_date") ;;
esac
rm -rf "$TEMP_DIR"
mkdir -p "$TEMP_DIR/ota_v0"
pushd "$TEMP_DIR/ota_v0" >/dev/null
echo "### GENERATING NEW SQUASHFS FILES ###"
echo " mksquashfs 时间参数: ${sq_time[*]:-(无)} epoch=$REPRO_EPOCH"
mksquashfs "$input_root" rootfs.squashfs -comp lzo -all-root "${sq_time[@]}"
rootfs_size=$(stat -c%s rootfs.squashfs)
rootfs_md5=$(md5sum rootfs.squashfs | awk '{print $1}')
split rootfs.squashfs -d -a 4 -b 512k rootfs.squashfs.
rm rootfs.squashfs
md5=$rootfs_md5
ota_md5_rootfs="ota_md5_rootfs.squashfs.${rootfs_md5}"
> "$ota_md5_rootfs"
for part in $(ls rootfs.squashfs.[0-9]* | sort); do
md5next=$(md5sum "$part" | awk '{print $1}')
echo "$md5next" >> "$ota_md5_rootfs"
mv "$part" "$part.$md5"
md5="$md5next"
done
echo "### GENERATING NEW xImage FILES ###"
cp "$input_ximage" xImage
ximage_size=$(stat -c%s xImage)
ximage_md5=$(md5sum xImage | awk '{print $1}')
split xImage -d -a 4 -b 512k xImage.
rm xImage
md5=$ximage_md5
ota_md5_ximage="ota_md5_xImage.${ximage_md5}"
> "$ota_md5_ximage"
for part in $(ls xImage.[0-9]* | sort); do
md5next=$(md5sum "$part" | awk '{print $1}')
echo "$md5next" >> "$ota_md5_ximage"
mv "$part" "$part.$md5"
md5="$md5next"
done
echo "### GENERATING METADATA FILES ###"
cat > ota_update.in <<-EOM
ota_version=0
img_type=kernel
img_name=xImage
img_size=${ximage_size}
img_md5=${ximage_md5}
img_type=rootfs
img_name=rootfs.squashfs
img_size=${rootfs_size}
img_md5=${rootfs_md5}
EOM
echo > ota_v0.ok
echo "current_version=0" > ../ota_config.in
echo "### GENERATING FIRMWARE FILE ###"
# ISO 的目录记录取文件 mtime → 全树归一化到 REPRO_EPOCH(含目录自身;-h 跟随符号链接元数据)。
find "$TEMP_DIR" -exec touch -h -d "@$REPRO_EPOCH" {} +
# 先写暂存路径,成功后再 mv 到交付路径:genisoimage 中途 abort(本机 1.1.11 有已知崩溃)
# 时,交付路径上不会留下「看起来像成品」的残缺 ISO(M56 踩过:28,672 B 半成品)。
iso_tmp="${TEMP_DIR}.iso" # 暂存在打包树之外(否则 ISO 会把自己读进去)
"$ISO_TOOL" -o "$iso_tmp" -J -r "${iso_time[@]}" "$TEMP_DIR"
[ -s "$iso_tmp" ] || { echo "!!! ISO 为空: $iso_tmp" >&2; exit 1; }
mv -f "$iso_tmp" "$output_file"
iso_size=$(stat -c%s "$output_file")
# 反「静默半成品」:ISO 至少要装得下 rootfs 本体(+xImage + 元数据),小了就是没写完。
[ "$iso_size" -ge "$rootfs_size" ] || {
echo "!!! ISO 体积 $iso_size B < rootfs $rootfs_size B —— 打包不完整" >&2
rm -f "$output_file"; exit 1; }
popd >/dev/null
rm -rf "$TEMP_DIR"
echo
echo "Repacking complete!"
echo " rootfs.squashfs = ${rootfs_size} B md5=${rootfs_md5}"
echo " xImage = ${ximage_size} B md5=${ximage_md5}"
echo " firmware: $output_file"