#!/bin/bash set -Eeuo pipefail STATUS=/boot/MSCSTAT.TXT PACKAGE_LOG=/boot/MSCPKG.TXT PACKAGE_INVENTORY=/boot/MSCPKGS.TSV DEPLOY_LOG=/boot/MSCDEPLOY.TXT CONFIG=/boot/MSCCFG.BIN BUNDLE=/opt/matrix-image-bootstrap/app/MSCBOOT.TGZ META=/boot/MSCMETA.JSN WORK=/run/matrix-image-provision KERNEL_ROOT=/opt/matrix-image-bootstrap/axp313a KERNEL_ARCHIVE=$KERNEL_ROOT/axp313a-kernel-6.1.31-matrix-axp313a1.tar.gz KERNEL_METADATA=$KERNEL_ROOT/METADATA.json KERNEL_WORK=/var/tmp/matrix-axp313a-image-install status() { printf '%s\n' "$1" > "$STATUS" sync "$STATUS" || true } failed() { code=$? trap - ERR rm -rf -- /var/tmp/matrix-axp313a-image-install status "FAILED: stage=${STAGE:-starting}; code=$code; line=${BASH_LINENO[0]:-unknown}. Power off, remove the TF card, and inspect this file on Windows." exit "$code" } trap failed ERR if [ "$(id -u)" -ne 0 ]; then status "FAILED: the one-time provisioner did not run as root." exit 1 fi STAGE=validate status "RUNNING: validating the offline image payload." rm -rf -- "$WORK" install -d -m 0700 "$WORK" python3 - "$META" "$BUNDLE" "$KERNEL_ARCHIVE" "$KERNEL_METADATA" <<'PY' import hashlib import json from pathlib import Path import sys meta = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8")) bundle = Path(sys.argv[2]) kernel_artifact = Path(sys.argv[3]) kernel = json.loads(Path(sys.argv[4]).read_text(encoding="utf-8")) assert meta == { "format_version": 3, "product": "matrix-screen-controller-walnutpi", "software_version": meta["software_version"], "bundle_path": "/opt/matrix-image-bootstrap/app/MSCBOOT.TGZ", "bundle_bytes": meta["bundle_bytes"], "bundle_sha256": meta["bundle_sha256"], "kernel_release": "6.1.31-matrix-axp313a1", "kernel_artifact": "axp313a-kernel-6.1.31-matrix-axp313a1.tar.gz", "kernel_artifact_bytes": meta["kernel_artifact_bytes"], "kernel_artifact_sha256": meta["kernel_artifact_sha256"], "kernel_unpacked_file_bytes": meta["kernel_unpacked_file_bytes"], "boot_required_bytes": meta["boot_required_bytes"], "boot_safety_bytes": 32 * 1024 * 1024, } assert isinstance(meta["boot_required_bytes"], int) and meta["boot_required_bytes"] > 0 assert bundle.stat().st_size == meta["bundle_bytes"] digest = hashlib.sha256() with bundle.open("rb") as handle: for chunk in iter(lambda: handle.read(1024 * 1024), b""): digest.update(chunk) assert digest.hexdigest() == meta["bundle_sha256"] assert kernel["schema_version"] == 1 assert kernel["architecture"] == "aarch64" assert kernel["kernel_release"] == meta["kernel_release"] assert kernel["artifact"] == meta["kernel_artifact"] assert kernel["artifact_bytes"] == meta["kernel_artifact_bytes"] == kernel_artifact.stat().st_size assert kernel["artifact_sha256"] == meta["kernel_artifact_sha256"] assert kernel["unpacked_file_bytes"] == meta["kernel_unpacked_file_bytes"] digest = hashlib.sha256() with kernel_artifact.open("rb") as handle: for chunk in iter(lambda: handle.read(1024 * 1024), b""): digest.update(chunk) assert digest.hexdigest() == meta["kernel_artifact_sha256"] PY tar -xzf "$BUNDLE" -C "$WORK" cd "$WORK/project/核桃派软件源代码" PYTHONPATH=. python3 scripts/kernel_artifact.py --kernel "$KERNEL_ROOT" >/dev/null cd "$WORK/project/离线依赖/其他依赖/aarch64-py311" sha256sum -c SHA256SUMS cd "$WORK/project/离线依赖/其他依赖/debian12-aarch64" sha256sum -c SHA256SUMS STAGE=packages status "RUNNING: installing offline Debian packages." export DEBIAN_FRONTEND=noninteractive dpkg-query -W -f='${db:Status-Abbrev}\t${binary:Package}\t${Version}\n' >"$PACKAGE_INVENTORY" if ! dpkg -i "$WORK"/project/离线依赖/其他依赖/debian12-aarch64/*.deb >"$PACKAGE_LOG" 2>&1; then status "FAILED: stage=packages; offline Debian package installation failed. Inspect MSCPKG.TXT on Windows; it contains package diagnostics but no configured credentials." exit 1 fi rm -f -- "$PACKAGE_LOG" "$PACKAGE_INVENTORY" STAGE=network status "RUNNING: applying the requested network configuration." cd "$WORK/project/核桃派软件源代码" PYTHONPATH=. python3 -m scripts.provision_device network --config "$CONFIG" systemctl restart NetworkManager.service STAGE=deploy status "RUNNING: installing and testing matrix-screen-controller." { if [ -e /opt/matrix-screen-controller ]; then printf '%s\n' 'A previous deployment attempt left /opt/matrix-screen-controller in place.' systemctl --no-pager --full status matrix-screen-controller.service || true journalctl --no-pager -u matrix-screen-controller.service -n 120 || true fi } >"$DEPLOY_LOG" 2>&1 FRPC_RUN_USER=$(PYTHONPATH=. python3 -c 'from pathlib import Path; from scripts.image_config import read_config_path; import sys; print(read_config_path(Path(sys.argv[1]))["account"]["username"])' "$CONFIG") if ! FRPC_RUN_USER="$FRPC_RUN_USER" DEFER_SERVICE_START=1 WHEELHOUSE="$WORK/project/离线依赖/其他依赖/aarch64-py311" FRPC_BUNDLE="$WORK/project/离线依赖/其他依赖/frp/0.71.0/linux-arm64" ./scripts/deploy_walnutpi.sh >>"$DEPLOY_LOG" 2>&1; then status "FAILED: stage=deploy; controller deployment failed. Inspect MSCDEPLOY.TXT on Windows; it contains deployment diagnostics but no configured credentials." exit 1 fi rm -f -- "$DEPLOY_LOG" STAGE=account status "RUNNING: creating the configured account and unique device identity." PYTHONPATH=. python3 -m scripts.provision_device account --config "$CONFIG" FRPC_RUN_USER="$FRPC_RUN_USER" DEFER_SERVICE_START=1 FRPC_BUNDLE="$WORK/project/离线依赖/其他依赖/frp/0.71.0/linux-arm64" /bin/sh ./scripts/install_frpc_system.sh systemctl disable boot_script.service >/dev/null 2>&1 || true PYTHONPATH=. python3 -m scripts.provision_device identity --config "$CONFIG" STAGE=ssh status "RUNNING: enabling password-authenticated SSH for the configured administrator." PYTHONPATH=. python3 -m scripts.provision_device ssh --config "$CONFIG" STAGE=kernel status "RUNNING: installing the verified offline AXP313A kernel." kernel_unpacked_bytes=$(python3 -c 'import json; print(json.load(open("/opt/matrix-image-bootstrap/axp313a/METADATA.json", encoding="utf-8"))["unpacked_file_bytes"])') available_bytes=$(df -Pk /var/tmp | awk 'NR == 2 { printf "%.0f\n", $4 * 1024 }') required_bytes=$((kernel_unpacked_bytes * 2 + 268435456)) if [ "$available_bytes" -lt "$required_bytes" ]; then printf '%s\n' 'insufficient root filesystem space to install the offline kernel safely' >&2 exit 1 fi rm -rf -- "$KERNEL_WORK" install -d -m 0700 "$KERNEL_WORK" tar -xzf "$KERNEL_ARCHIVE" -C "$KERNEL_WORK" cd "$WORK/project/核桃派软件源代码" ./scripts/install_axp313a_kernel.sh --artifact "$KERNEL_WORK" rm -rf -- "$KERNEL_WORK" rm -rf -- /opt/matrix-image-bootstrap STAGE=finish install -d -m 0711 /var/lib/matrix-screen-controller printf '%s\n' "$(cat VERSION)" > /var/lib/matrix-screen-controller/.factory-image-version if command -v shred >/dev/null 2>&1; then shred -n 1 -z "$CONFIG" || true fi rm -f -- "$CONFIG" "$META" /boot/MSCINIT systemctl disable matrix-image-firstboot.service >/dev/null 2>&1 || true rm -f -- /etc/systemd/system/matrix-image-firstboot.service rm -rf -- "$WORK" sync if nmcli -t -f NAME connection show --active 2>/dev/null | grep -Fxq 'matrix-screen' \ && ip route show default | grep -q .; then status "SUCCESS: provisioning completed; the device is rebooting into the installed controller." else status "SUCCESS: provisioning completed while Wi-Fi is not connected; the installed controller will keep trying after reboot." fi systemctl reboot