#!/bin/sh /etc/rc.common
# OWC: 把宿主的爱快 iptables 工具链落到 guest 里，让 guest 的 iptables 能驱动爱快打过补丁的
# 宿主 netfilter（stock iptables 会 `ERROR: 0 not a valid target` / Aborted）。
# 早启动（START=10），让 OpenWrt 防火墙与代理类应用从第一刻起就拿到可用的 iptables。
#
# 落地方式由**宿主 libc** 决定，宿主把它写在 /usr/ikuai/compat/.hostlibc：
#
#   musl  宿主 → 工具链与 guest 同 ABI，直接原生运行（/usr/ikuai/native）。
#                不 chroot、不需要 CAP_SYS_CHROOT、不再额外拷一份 libc。
#   uClibc 宿主 → 解释器 /lib/ld64-uClibc.so.0 本机没有，必须连 libc 一起 chroot
#                 （/usr/ikuai/chroot），才能让 loader 落在它 PT_INTERP 的硬编码路径上。
#
# 工具链本体在 /usr/ikuai/compat（宿主只读 bind）。这里只做「落到可执行位置」这一步：
# 该挂载是 ro+noexec，不能直接 exec，所以必须复制出来；每次启动重建，幂等。
# 容器在独立的 network namespace 里，永远不会碰宿主的防火墙。
START=10
STOP=90

SRC=/usr/ikuai/compat
NATIVE=/usr/ikuai/native
CHROOT=/usr/ikuai/chroot

# 迁移清理：旧版本把 compat 根建在 /opt/ikuai-root 或 /usr/ikuai/helper/ikuai-compat-root。
# 不清理会在 upper 层白占一份空间。
for old in /opt/ikuai-root /usr/ikuai/helper/ikuai-compat-root; do
	[ -d "$old" ] && rm -rf "$old" 2>/dev/null
done

# 宿主 libc。缺标记时按「compat 树里带的是哪种加载器」推断（老宿主没有这个标记）。
host_libc() {
	local v
	v=$(cat "$SRC/.hostlibc" 2>/dev/null | head -1)
	[ -n "$v" ] && { echo "$v"; return; }
	if ls "$SRC"/lib/ld-musl-*.so.1 >/dev/null 2>&1; then echo musl; else echo uclibc; fi
}

# 原生：只搬「二进制 + xtables 库 + 私有扩展插件」。libc/loader 用 guest 自己的 —— 这正是
# 去掉 chroot 的意义。清掉 chroot 那份，免得两种模式各留一份白占空间。
build_native() {
	rm -rf "$NATIVE"
	mkdir -p "$NATIVE/usr/lib" "$NATIVE/usr/sbin"
	cp -a "$SRC/usr/lib/." "$NATIVE/usr/lib/" 2>/dev/null
	cp -a "$SRC/usr/sbin/." "$NATIVE/usr/sbin/" 2>/dev/null
	chmod 0755 "$NATIVE/usr/sbin/xtables-legacy-multi" 2>/dev/null
	rm -rf "$CHROOT"
}

# chroot：连 libc + loader 一起搬，才能满足二进制里硬编码的 PT_INTERP 路径。
build_chroot() {
	rm -rf "$CHROOT"
	mkdir -p "$CHROOT/lib" "$CHROOT/usr/lib" "$CHROOT/usr/sbin" "$CHROOT/var/run" "$CHROOT/run"
	cp -a "$SRC/lib/." "$CHROOT/lib/" 2>/dev/null
	cp -a "$SRC/usr/lib/." "$CHROOT/usr/lib/" 2>/dev/null
	cp -a "$SRC/usr/sbin/." "$CHROOT/usr/sbin/" 2>/dev/null
	chmod 0755 "$CHROOT/usr/sbin/xtables-legacy-multi" 2>/dev/null
	rm -rf "$NATIVE"
}

# ★ 自愈：旧版本（≤0.4.31）在**运行期**往 /usr/sbin 写过 wrapper 与 applet 软链，那些副本
#   落在 overlay 的**上层**，会遮挡本次烤进 lower 层的新副本 —— 症状是升级后仍旧跑旧逻辑
#   （例如 x64 上仍 chroot 到早已不存在的 /usr/ikuai/chroot，iptables 全线不可用，而容器
#   表面完全正常）。旧版本从未写过 .fresh 这个名字，所以它必定来自当前镜像、不被遮挡；
#   用它覆盖回去即可。每次启动都做，幂等，且覆盖后新旧名字内容一致。
refresh_wrapper() {
	local fresh=/usr/sbin/iptables-compat-wrapper.fresh
	[ -f "$fresh" ] || return 0
	if cp -f "$fresh" /usr/sbin/iptables-compat-wrapper 2>/dev/null; then
		chmod 0755 /usr/sbin/iptables-compat-wrapper 2>/dev/null
		local a
		for a in iptables iptables-save iptables-restore ip6tables ip6tables-save ip6tables-restore; do
			ln -sfn iptables-compat-wrapper "/usr/sbin/$a" 2>/dev/null
		done
	else
		logger -t ikuai-compat-iptables "WARN 无法刷新 /usr/sbin/iptables-compat-wrapper；旧副本可能仍生效"
	fi
}

start() {
	[ -d "$SRC/usr/sbin" ] || {
		logger -t ikuai-compat-iptables "no $SRC; compat layer skipped"
		return 0
	}
	refresh_wrapper
	local libc
	libc=$(host_libc)
	case "$libc" in
		musl) build_native ;;
		*)    build_chroot ;;
	esac
	# netns 挂载点与锁目录：iptables 保存/恢复会用到。
	mkdir -p /var/run/netns /var/lock

	# 包装脚本与 applet 符号链接是**构建期烤进镜像**的（运行期写不了 /usr/sbin）。
	# 缺失就明确报出来 —— 否则症状是「容器一切正常，只是没有防火墙」，最难查。
	if [ ! -x /usr/sbin/iptables-compat-wrapper ]; then
		logger -t ikuai-compat-iptables "FATAL: /usr/sbin/iptables-compat-wrapper missing (rootfs built without install-iptables-wrapper.sh); firewall layer inert"
		return 1
	fi
	logger -t ikuai-compat-iptables "compat layer active ($libc): $(iptables --version 2>/dev/null | head -1)"
}

stop() { :; }
