#!/bin/bash # ============================================================================= # prepare-image.sh — 产品镜像出厂化清理(母卡制作镜像前运行) # ----------------------------------------------------------------------------- # 用法(母卡上,root): # sudo ./prepare-image.sh 出厂化清理 # sudo ./prepare-image.sh --zero 额外清零空闲空间(压缩镜像体积,较慢) # # 作用:把"部署完成、验证通过"的母卡变成干净的出厂状态: # - 清除设备个体身份(machine-id / SSH 密钥 / device_id / hostname) # - 清空 /data 与运行时数据(日志/告警/HLS),保留分区与 fstab # - 保留:已部署的 safesight、已装的依赖、overlayroot 配置能力(出厂即带断电保护) # # 重要:本脚本后【不要】启用 overlayroot(setup-overlayroot.sh enable), # 保持"可写出厂状态",overlayroot 留到每台设备初始化最后一步启用。 # 否则 /etc/machine-id 无法固化,每台重启后设备 ID 漂移。 # ============================================================================= set -euo pipefail RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' info() { echo -e "${CYAN}[INFO]${NC} $*"; } ok() { echo -e "${GREEN}✓${NC} $*"; } warn() { echo -e "${YELLOW}⚠${NC} $*"; } die() { echo -e "${RED}✗${NC} $*" >&2; exit 1; } ZERO=0 for arg in "$@"; do case "$arg" in --zero) ZERO=1 ;; *) warn "未知参数: $arg" ;; esac done [ "$(id -u)" -eq 0 ] || die "请使用 sudo 运行" RUNTIME_ROOT="/var/lib/safesight-edge-server" AGENT_LIB="/var/lib/safesight-edge-agent" DATA_MOUNT="/data" OVERLAY_CONF="/etc/overlayroot.conf" # --------------------------------------------------------------------------- # 安全检查 # --------------------------------------------------------------------------- if grep -qs 'overlay' /proc/mounts; then die "当前处于 overlayroot 保护模式!请先进入维护模式(setup-overlayroot.sh disable + 重启)再运行。" fi if grep -qE '^overlayroot="[^"]+"' "$OVERLAY_CONF" 2>/dev/null; then die "检测到 $OVERLAY_CONF 已启用 overlayroot(保护模式配置)。出厂镜像必须保持可写状态,\n 请先运行 setup-overlayroot.sh disable(设置 overlayroot=\"\")后再执行出厂化。" fi echo -e "${YELLOW}════════════════════════════════════════════════════════════════${NC}" echo -e "${YELLOW} 即将把母卡重置为出厂状态,此操作不可恢复!${NC}" echo -e "${YELLOW}════════════════════════════════════════════════════════════════${NC}" echo "" echo "将清除:" echo " - /etc/machine-id、SSH 主机密钥、hostname、device_id(首次启动自动重建)" echo " - /data 与 /var/lib/safesight-edge-server 下所有日志/告警/HLS 数据" echo "" echo "将保留:" echo " - safesight 程序与配置模板、全部依赖、/data 分区与 fstab(断电保护能力)" echo "" read -r -p "继续? [y/N]: " yn [ "${yn:-n}" = "y" ] || [ "${yn:-n}" = "Y" ] || die "已取消" # --------------------------------------------------------------------------- # 1. 停止服务 # --------------------------------------------------------------------------- info "停止服务 ..." systemctl stop safesight-edge-server safesight-edge-agent 2>/dev/null || true ok "服务已停止" # --------------------------------------------------------------------------- # 2. 清空数据(保留目录结构) # --------------------------------------------------------------------------- info "清空运行数据 ..." for d in hls logs alarms clips; do rm -rf "$RUNTIME_ROOT/$d"/* rm -rf "$DATA_MOUNT/safesight/$d"/* 2>/dev/null || true done rm -rf "$AGENT_LIB"/* /data/safesight/agent/* 2>/dev/null || true [ -f "$AGENT_LIB/device_id" ] && rm -f "$AGENT_LIB/device_id" ok "运行数据已清空(目录保留)" # --------------------------------------------------------------------------- # 3. 设备身份重置(首次启动自动重建) # --------------------------------------------------------------------------- info "重置设备身份 ..." rm -f /etc/machine-id /var/lib/dbus/machine-id rm -f /etc/ssh/ssh_host_*_key* /etc/ssh/ssh_host_*_key*.pub rm -f "$AGENT_LIB/device_id" hostnamectl set-hostname orangepi 2>/dev/null || true ok "machine-id / SSH 密钥 / hostname / device_id 已重置(首次启动自动生成唯一值)" # --------------------------------------------------------------------------- # 4. 日志与缓存清理 # --------------------------------------------------------------------------- info "清理日志与缓存 ..." journalctl --vacuum-size=1M >/dev/null 2>&1 || true rm -rf /var/log/journal/* 2>/dev/null || true find /var/log -type f -name "*.log" -delete 2>/dev/null || true apt-get clean 2>/dev/null || true rm -f /root/.bash_history /home/orangepi/.bash_history 2>/dev/null || true ok "日志与缓存已清理" # --------------------------------------------------------------------------- # 5. 清零空闲空间(可选,压缩镜像体积) # --------------------------------------------------------------------------- if [ "$ZERO" = "1" ]; then info "清零空闲空间(SD 卡写入较慢,请耐心等待)..." for target in /data / ; do fill="$target/zero.fill" echo " $target ..." dd if=/dev/zero of="$fill" bs=4M 2>/dev/null || true rm -f "$fill" done ok "空闲空间已清零" else warn "未清零空闲空间。如需缩小镜像体积,可加 --zero 重新执行。" fi # --------------------------------------------------------------------------- # 6. 完成 # --------------------------------------------------------------------------- echo "" echo -e "${GREEN}════════════════════════════════════════════════════════════════${NC}" echo -e "${GREEN} 出厂化完成!可以关机、摘卡、制作产品镜像${NC}" echo -e "${GREEN}════════════════════════════════════════════════════════════════${NC}" echo "" echo "下一步:" echo " 1) sudo poweroff # 关机(确保文件系统一致)" echo " 2) 摘卡,在主机上制作镜像:" echo " Windows: Win32DiskImager 读取 → img" echo " Linux: sudo dd if=/dev/sdX bs=4M status=progress | gzip > safesight-product.img.gz" echo " 3) 每台烧录后首次启动会自动生成唯一 machine-id / SSH 密钥 / device_id" echo " 4) 每台初始化: sudo ./init-device.sh --hostname ... --ip ...(见脚本说明)" echo "" echo "注意: 此状态【尚未启用 overlayroot】——出厂镜像故意如此。" echo " overlayroot 由 init-device.sh 在每台初始化最后一步统一启用。"