Files
MeowOS-For-R3P2/scripts/build/build_fw_apps.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

228 lines
11 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
# ============================================================================
# build_fw_apps.sh — 通用固件打包脚本(配置驱动)
#
# 用法:
# build_fw_apps.sh -c <manifest> -v <version> -o <out.upt> [-b <base dir>]
#
# 参数:
# -c|--config 固件内容清单路径。默认 scripts/build/fw_content.conf。
# 传别的路径即可并存多套调试/场景配置(互不覆盖)。
# -v|--version 版本号,写入目标 /etc/meowos_version(如 0.7.62)。【必传】
# -o|--out 输出 .upt 路径(如 r3proii_m2_67.upt)。【必传】
# 若指向仓库内 fw_apps/ 下(非 out/),自动并入 fw_apps/out/ 归档。
# -b|--base fw_ssh 基线目录。默认 fw_ssh/squashfs-root。
#
# 通用步骤(读清单之外的固定逻辑):
# 1) 解析参数
# 2) 建树:rm -rf fw_apps/build && mkdir -p && cp -a $BASE fw_apps/build/squashfs-root
# (组装区 fw_apps/build/ 每次清理重建;产物 fw_apps/out/ 不受影响)
# 3) 校验基线:usr/bin/hiby_player 必须为 stock(a73f2c49…)
# 4) 解析清单:逐条 md5 校验(若填) + cp -f + chmod 755,目录自动建
# 5) 写版本:echo $VERSION > $DST/etc/meowos_version
# 6) 外围 CLI 瘦身:从 $DST/usr/bin 按白名单移除(已迁 TF 卡 MeowOS/opt/bin)
# 7) 启动图/背包/关机 logo:从 bootlogos/ 拷 logo_new→logo.jpeg、logo1_new→logo1、
# logo2_new→logo2、boot_anim_0.png→etc/boot_animation/0.png、shutdown_logo.jpeg→etc/
# 8) S99ssh → S84ssh:改名(内容不变),校验一致后删除 S99ssh(清单不含 S84)
# 9) repack:hiby_os_crack/scripts/repack.sh -i $DST -k unpacked_v14/xImage -o $OUT
# 10) 体积核对(rootfs ≤ 45,088,768)+ unpack 回验 0 diff
#
# 约定:改固件内容只改 fw_content.conf(每行 <src>|<dst>|<md5>|<desc>),不改本脚本。
# ============================================================================
set -e
# 项目根:由本脚本位置向上推(scripts/build/ → 根),可迁移
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# 默认值
CONFIG="$ROOT/scripts/build/fw_content.conf"
BASE="$ROOT/fw_ssh/squashfs-root"
VERSION=""
OUT=""
OUT_DIR="$ROOT/fw_apps/out" # 产物归档目录(不受构建清理影响)
usage() {
echo "用法: $0 -c <manifest.conf> -v <version> -o <out.upt> [-b <fw_ssh/squashfs-root>]"
echo " -c|--config <manifest> 固件内容清单路径 (默认 scripts/build/fw_content.conf)"
echo " -v|--version <version> 版本号,写入 etc/meowos_version (必传)"
echo " -o|--out <file> 输出 .upt 路径 (必传)"
echo " -b|--base <dir> fw_ssh 基线目录 (默认 fw_ssh/squashfs-root)"
}
# ---- 1) 解析参数 ----
while [ $# -gt 0 ]; do
case "$1" in
-c|--config) CONFIG="$2"; shift 2 ;;
-v|--version) VERSION="$2"; shift 2 ;;
-o|--out) OUT="$2"; shift 2 ;;
-b|--base) BASE="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) echo "!!! 未知参数: $1"; usage; exit 1 ;;
esac
done
[ -n "$VERSION" ] || { echo "!!! 缺少 -v/--version"; usage; exit 1; }
[ -n "$OUT" ] || { echo "!!! 缺少 -o/--out"; usage; exit 1; }
# 一律转绝对路径,避免后续 cd /tmp 后相对路径失效
case "$CONFIG" in /*) ;; *) CONFIG="$ROOT/$CONFIG" ;; esac
case "$BASE" in /*) ;; *) BASE="$ROOT/$BASE" ;; esac
case "$OUT" in /*) ;; *) OUT="$ROOT/$OUT" ;; esac
[ -f "$CONFIG" ] || { echo "!!! 清单不存在: $CONFIG"; exit 1; }
[ -d "$BASE" ] || { echo "!!! 基线不存在: $BASE"; exit 1; }
# 产物统一归档到 $ROOT/fw_apps/out/(避免某次构建清理误删;仅当 -o 指向仓库内非 out/ 路径时并入)
case "$OUT" in
"$OUT_DIR/"*) ;; # 已在 out/ 下,保持
"$ROOT/fw_apps/"*) OUT="$OUT_DIR/$(basename "$OUT")" ;; # 仓库内 fw_apps/ 下 → 并入 out/
esac
mkdir -p "$(dirname "$OUT")"
SRC="$BASE" # 基线(拷贝源)
DST="$ROOT/fw_apps/build/squashfs-root" # 组装目标(工作区,每次构建清理重建;产物不受影响)
LOGO_DIR="$ROOT/bootlogos"
# 外围 CLI(自 rootfs /usr/bin 移除;已迁 TF 卡 MeowOS/opt/bin/)
MIGRATE_TOOLS="curl socat tmux jq rsync nano htop ncdu file xxd"
# 基线 player 校验值(stock v1.4)
STOCK_PLAYER_MD5="a73f2c49a655659ef14db3bf6acecd78"
echo "==> 参数"
echo " ROOT=$ROOT"
echo " CONFIG=$CONFIG"
echo " BASE=$BASE"
echo " VERSION=$VERSION"
echo " OUT=$OUT"
# ---- 2) 建树(复制基线) ----
echo "==> 建树(复制基线)"
rm -rf "$ROOT/fw_apps/build"
mkdir -p "$ROOT/fw_apps/build" "$OUT_DIR"
cp -a "$SRC" "$DST"
# ---- 3) 校验基线 player 为 stock ----
echo "==> 校验基线 player 为 stock"
BASE_MD5=$(md5sum "$DST/usr/bin/hiby_player" | cut -d' ' -f1)
[ "$BASE_MD5" = "$STOCK_PLAYER_MD5" ] || {
echo "!!! hiby_player 不是 stock(a73f2c49): $BASE_MD5"; exit 1; }
# ---- 4) 解析清单,逐条 校验(md5 若填) + cp + chmod 755 ----
echo "==> 解析清单: $CONFIG"
CNT=0
while IFS='|' read -r src dst md5 desc; do
# 去首尾空白
src=$(echo "$src" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
dst=$(echo "$dst" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
# 注释 / 空行 / 无有效字段跳过
[ -z "$src" ] && continue
case "$src" in \#*) continue ;; esac
[ -z "$dst" ] && { echo " !!! 行缺 dst(跳过): $src"; continue; }
md5=$(echo "$md5" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
srcpath="$ROOT/$src"
[ -f "$srcpath" ] || { echo "!!! 源不存在: $srcpath"; exit 1; }
# 强校验 md5(若填)
if [ -n "$md5" ]; then
got=$(md5sum "$srcpath" | cut -d' ' -f1)
[ "$got" = "$md5" ] || {
echo "!!! 源 md5 不匹配: $src (期望 $md5, 实际 $got)"; exit 1; }
fi
# 目标绝对路径 $dst 的宿主目录
dstdir=$(dirname "$DST$dst")
mkdir -p "$dstdir"
cp -f "$srcpath" "$DST$dst"
chmod 755 "$DST$dst"
CNT=$((CNT+1))
[ -n "$desc" ] && echo " ${dst} <- ${src} (${desc})" || echo " ${dst} <- ${src}"
done < "$CONFIG"
echo " 已安装 $CNT 条"
# ---- 5) 写版本号 ----
echo "==> 写版本: $VERSION"
echo "$VERSION" > "$DST/etc/meowos_version"
# ---- 6) 外围 CLI 瘦身(已迁 TF 卡 MeowOS/opt/bin)----
echo "==> rootfs 瘦身:移除外围 CLI(已迁卡)"
for t in $MIGRATE_TOOLS; do
if [ -e "$DST/usr/bin/$t" ]; then rm -f "$DST/usr/bin/$t"; echo " removed /usr/bin/$t"; fi
done
# ---- 7) 启动图/背包/关机 logo(M2.1 用户自定义图覆盖 stock)----
echo "==> 启动图补回(M2.1):用户自定义 logo*.jpeg + boot_animation/0.png"
cp -f "$LOGO_DIR/logo_new.jpeg" "$DST/etc/logo.jpeg"; chmod 755 "$DST/etc/logo.jpeg"
cp -f "$LOGO_DIR/logo1_new.jpeg" "$DST/etc/logo1.jpeg"; chmod 755 "$DST/etc/logo1.jpeg"
cp -f "$LOGO_DIR/logo2_new.jpeg" "$DST/etc/logo2.jpeg"; chmod 755 "$DST/etc/logo2.jpeg"
mkdir -p "$DST/etc/boot_animation"
cp -f "$LOGO_DIR/boot_anim_0.png" "$DST/etc/boot_animation/0.png"; chmod 644 "$DST/etc/boot_animation/0.png"
echo " logo.jpeg/logo1.jpeg/logo2.jpeg + boot_animation/0.png ✓"
echo "==> 关机 logo(M2.1):/etc/shutdown_logo.jpeg"
cp -f "$LOGO_DIR/shutdown_logo.jpeg" "$DST/etc/shutdown_logo.jpeg"; chmod 755 "$DST/etc/shutdown_logo.jpeg"
[ -f "$DST/etc/shutdown_logo.jpeg" ] && echo " shutdown_logo.jpeg ✓"
# ---- 8) S99ssh → S84ssh(改名,内容不变,清单不含 S84;基线缺 S99 则跳过)----
echo "==> S99ssh -> S84ssh(改名,内容不变)"
if [ -f "$SRC/etc/init.d/S99ssh" ]; then
cp -f "$SRC/etc/init.d/S99ssh" "$DST/etc/init.d/S84ssh"; chmod 755 "$DST/etc/init.d/S84ssh"
rm -f "$DST/etc/init.d/S99ssh"
diff -q "$SRC/etc/init.d/S99ssh" "$DST/etc/init.d/S84ssh" >/dev/null 2>&1 \
&& echo " S84ssh == 原 S99ssh ✓" || { echo " !!! S84ssh 与 S99ssh 不一致"; exit 1; }
[ ! -e "$DST/etc/init.d/S99ssh" ] && echo " S99ssh 已移除 ✓" || { echo " !!! S99ssh 仍存在"; exit 1; }
else
echo " (基线无 S99ssh,跳过 S99→S84 改名)"
fi
echo "==> repack"
# 优先用可复现打包器(scripts/build/repack_repro.sh:mksquashfs -repro-time +
# genisoimage -creation-date + mtime 归一化)。可复现口径**到 squashfs/元数据为止**:
# rootfs.squashfs / 分片 / ota_update.in 两次打包逐字节相同;`.upt` 本身仍差约 93 字节
# (genisoimage 写的 Rock Ridge TF backup date,无覆盖开关),故 .upt 验收仍是
# 「体积 + unpack 0 diff + 进包 md5」。
# 未设 REPACK 时才回退历史 repack.sh(产物布局相同,时间戳全随墙钟);
# **显式指定了却不存在 → 直接失败**,免得「以为用了可复现打包器、其实悄悄退回旧路径」。
# 两者都按 bash 显式执行:repack.sh 的 #!/usr/bin/env bash 在 Android 上无 /usr/bin/env,
# 且经 su 跑时 termux-exec 的 LD_PRELOAD 被丢弃 → bad interpreter(M13 实测)。
if [ -n "${REPACK:-}" ]; then
[ -f "$REPACK" ] || { echo "!!! REPACK 显式指定但不存在: $REPACK"; exit 1; }
else
REPACK="$ROOT/scripts/build/repack_repro.sh"
[ -f "$REPACK" ] || REPACK="$ROOT/hiby_os_crack/scripts/repack.sh"
fi
echo " repack = $REPACK"
# 内核镜像(unpacked_v14/xImage)未入库:干净 checkout / git worktree 里没有它,
# 用 XIMAGE 指到主 checkout 的那份(普通 checkout 下默认值即可)。
XIMAGE="${XIMAGE:-$ROOT/unpacked_v14/xImage}"
[ -f "$XIMAGE" ] || { echo "!!! 内核镜像不存在: $XIMAGE(可用 XIMAGE=/path/to/xImage 覆盖)"; exit 1; }
bash "$REPACK" \
-i "$DST" \
-k "$XIMAGE" \
-o "$OUT" < /dev/null
# ---- 10) 体积核对(rootfs 分区, 上限 45,088,768) ----
echo "==> 体积核对(rootfs 分区, 上限 45,088,768)"
mkdir -p "${TMPDIR:-/tmp}/fw_apps_chk" && cd "${TMPDIR:-/tmp}/fw_apps_chk"
rm -rf ota_v0 ota_update.in rootfs.squashfs
7z x -y "$OUT" ota_v0/ota_update.in > /dev/null 2>&1
RFSZ=$(grep -A1 'img_name=rootfs' ota_v0/ota_update.in | grep img_size | cut -d= -f2)
echo "rootfs.squashfs = $RFSZ bytes"
if [ "$RFSZ" -le 45088768 ]; then echo "OK <= 上限"; else echo "!!! 超上限"; exit 1; fi
echo "==> rootfs.img md5"
grep -A3 'img_name=rootfs' ota_v0/ota_update.in | grep img_md5 | cut -d= -f2
echo "==> unpack 回验(0 diff)"
mkdir -p "${TMPDIR:-/tmp}/fw_apps_rt" && cd "${TMPDIR:-/tmp}/fw_apps_rt"
rm -rf ota_v0 ota_config.in squashfs-root rootfs.squashfs rootfs.squashfs.*
7z x -y "$OUT" > /dev/null 2>&1
find . -name "rootfs.squashfs.*" | sort -V | xargs cat > rootfs.squashfs 2>/dev/null
unsquashfs -no-progress -d squashfs-root rootfs.squashfs > /dev/null 2>&1 || true
if diff -rq --no-dereference "$DST" squashfs-root > ${TMPDIR:-/tmp}/fw_apps_rt_diff.log 2>&1; then
echo "0 diff ✓"
else
echo "!!! diff found:"; head -20 ${TMPDIR:-/tmp}/fw_apps_rt_diff.log
exit 1
fi
echo "==> 最终固件 md5"
md5sum "$OUT"
ls -la "$OUT"