diff --git a/emmc_backup_from_sd.sh b/emmc_backup_from_sd.sh index 00adef8..ccacc5f 100644 --- a/emmc_backup_from_sd.sh +++ b/emmc_backup_from_sd.sh @@ -19,10 +19,15 @@ EMMC_DEV="/dev/mmcblk0" USB_DIR="/mnt/XIN_USB/rock5c" OUTPUT_FILE="${USB_DIR}/rock5c_emmc_$(date +%Y%m%d_%H%M%S).img" -info_msg "从SD卡备份eMMC..." +info_msg "从SD卡备份eMMC (智能压缩版)..." info_msg "eMMC设备: ${EMMC_DEV}" info_msg "输出到: ${OUTPUT_FILE}" +# 获取原始eMMC大小 +ORIGINAL_SIZE=$(blockdev --getsize64 ${EMMC_DEV}) +ORIGINAL_SIZE_GB=$((ORIGINAL_SIZE / 1073741824)) +info_msg "原始eMMC大小: ${ORIGINAL_SIZE_GB}GB" + # 检查设备 [[ -b "${EMMC_DEV}" ]] || error_msg "eMMC设备不存在: ${EMMC_DEV}" [[ -d "${USB_DIR}" ]] || error_msg "USB目录不存在: ${USB_DIR}" @@ -43,70 +48,123 @@ info_msg "检查eMMC数据使用量..." TEMP_MOUNT="/tmp/check_emmc" mkdir -p "${TEMP_MOUNT}" +# 检查分区是否存在 +[[ -b "${EMMC_DEV}p1" ]] || error_msg "未找到boot分区 ${EMMC_DEV}p1" +[[ -b "${EMMC_DEV}p2" ]] || error_msg "未找到root分区 ${EMMC_DEV}p2" + # 临时挂载检查使用量 -mount ${EMMC_DEV}p2 "${TEMP_MOUNT}" -o ro -EMMC_USED=$(df --block-size=1M "${TEMP_MOUNT}" | tail -1 | awk '{print $3}') +mount ${EMMC_DEV}p1 "${TEMP_MOUNT}" -o ro +EMMC_BOOT_USED=$(df --block-size=1M "${TEMP_MOUNT}" | tail -1 | awk '{print $3}') umount "${TEMP_MOUNT}" -mount ${EMMC_DEV}p1 "${TEMP_MOUNT}" -o ro -EMMC_BOOT_USED=$(df --block-size=1M "${TEMP_MOUNT}" | tail -1 | awk '{print $3}') +mount ${EMMC_DEV}p2 "${TEMP_MOUNT}" -o ro +EMMC_ROOT_USED=$(df --block-size=1M "${TEMP_MOUNT}" | tail -1 | awk '{print $3}') umount "${TEMP_MOUNT}" rm -rf "${TEMP_MOUNT}" -info_msg "eMMC使用情况: Root ${EMMC_USED}MB + Boot ${EMMC_BOOT_USED}MB" +TOTAL_USED=$((EMMC_BOOT_USED + EMMC_ROOT_USED)) +info_msg "eMMC使用情况: Boot ${EMMC_BOOT_USED}MB + Root ${EMMC_ROOT_USED}MB = 总计 ${TOTAL_USED}MB" +MIN_TARGET_SIZE=$((TOTAL_USED + 1024)) # 需要1GB额外空间 +info_msg "最小目标eMMC: ${MIN_TARGET_SIZE}MB (约$((MIN_TARGET_SIZE / 1024))GB)" # 步骤2: 智能收缩eMMC分区 info_msg "步骤2: 智能收缩eMMC分区..." +# 记录原始分区信息 +parted -s ${EMMC_DEV} unit s print > "${USB_DIR}/original_partition.txt" +P1_START=$(parted -s ${EMMC_DEV} unit s print | grep "^ 1" | awk '{print $2}' | sed 's/s$//') +P1_END=$(parted -s ${EMMC_DEV} unit s print | grep "^ 1" | awk '{print $3}' | sed 's/s$//') +P2_START=$(parted -s ${EMMC_DEV} unit s print | grep "^ 2" | awk '{print $2}' | sed 's/s$//') +ORIGINAL_P2_END=$(parted -s ${EMMC_DEV} unit s print | grep "^ 2" | awk '{print $3}' | sed 's/s$//') + +info_msg "分区布局: P1=${P1_START}s-${P1_END}s, P2=${P2_START}s-${ORIGINAL_P2_END}s" + # 文件系统检查 e2fsck -f -y ${EMMC_DEV}p2 # 先尝试收缩到最小值 info_msg "计算文件系统最小大小..." -resize2fs -M ${EMMC_DEV}p2 +resize2fs -M ${EMMC_DEV}p2 2>&1 | tee /tmp/resize.log # 获取收缩后的实际大小 FS_SIZE_BLOCKS=$(dumpe2fs -h ${EMMC_DEV}p2 2>/dev/null | grep "^Block count:" | awk '{print $3}') -FS_SIZE_MB=$(( (FS_SIZE_BLOCKS * 4) / 1024 + 200 )) # 块大小4KB + 200MB缓冲 +BLOCK_SIZE=$(dumpe2fs -h ${EMMC_DEV}p2 2>/dev/null | grep "^Block size:" | awk '{print $3}') + +# 添加默认值防止空值 +[[ -z "$FS_SIZE_BLOCKS" ]] && FS_SIZE_BLOCKS=1048576 # 默认4GB worth of blocks +[[ -z "$BLOCK_SIZE" ]] && BLOCK_SIZE=4096 # 默认4K + +FS_SIZE_MB=$(( (FS_SIZE_BLOCKS * BLOCK_SIZE) / 1048576 )) info_msg "文件系统最小大小: ${FS_SIZE_MB}MB" -# 扩展一点给缓冲空间 -SHRINK_TARGET=$((FS_SIZE_MB + 300)) +# 添加缓冲空间确保系统能正常运行 +SHRINK_TARGET=$((FS_SIZE_MB + 512)) # 512MB缓冲 resize2fs ${EMMC_DEV}p2 ${SHRINK_TARGET}M -# 收缩分区 -P2_START=$(parted -s ${EMMC_DEV} unit B print | grep "^ 2" | awk '{print $2}' | sed 's/B$//') -NEW_P2_END=$((P2_START + SHRINK_TARGET * 1048576)) - -# 记录原始分区信息 -parted -s ${EMMC_DEV} unit B print > "${USB_DIR}/emmc_original_layout.txt" -ORIGINAL_P2_END=$(parted -s ${EMMC_DEV} unit B print | grep "^ 2" | awk '{print $3}' | sed 's/B$//') +# 计算新的分区结束位置(扇区) +NEW_P2_END_SECTORS=$((P2_START + (SHRINK_TARGET * 1048576 / 512))) # 重新创建收缩的分区 parted -s ${EMMC_DEV} rm 2 -parted -s ${EMMC_DEV} mkpart primary ext4 ${P2_START}B ${NEW_P2_END}B +parted -s ${EMMC_DEV} unit s mkpart primary ext4 ${P2_START}s ${NEW_P2_END_SECTORS}s -info_msg "✅ eMMC分区已收缩" +partprobe ${EMMC_DEV} +sleep 2 -# 步骤3: 备份收缩后的eMMC -info_msg "步骤3: 备份收缩后的eMMC..." -BACKUP_SIZE_MB=$(( (NEW_P2_END / 1048576) + 100 )) -dd if=${EMMC_DEV} of="${OUTPUT_FILE}" bs=1M count=${BACKUP_SIZE_MB} status=progress +info_msg "✅ eMMC分区已收缩到 ${SHRINK_TARGET}MB" + +# 步骤3: 创建备份信息文件 +info_msg "步骤3: 创建备份信息..." + +cat > "${OUTPUT_FILE}.info" </dev/null || true info_msg "✅ eMMC备份完成" -# 步骤4: 恢复eMMC原始大小 -info_msg "步骤4: 恢复eMMC原始分区大小..." +# 步骤5: 恢复eMMC原始大小 +info_msg "步骤5: 恢复eMMC原始分区大小..." parted -s ${EMMC_DEV} rm 2 -parted -s ${EMMC_DEV} mkpart primary ext4 ${P2_START}B ${ORIGINAL_P2_END}B +parted -s ${EMMC_DEV} unit s mkpart primary ext4 ${P2_START}s ${ORIGINAL_P2_END}s + +partprobe ${EMMC_DEV} +sleep 2 + resize2fs ${EMMC_DEV}p2 -info_msg "✅ eMMC已恢复原始大小" +info_msg "✅ eMMC已恢复原始大小 ${ORIGINAL_SIZE_GB}GB" # 验证备份镜像 -info_msg "步骤5: 验证备份镜像..." +info_msg "步骤6: 验证备份镜像..." LOOP_DEV=$(losetup -P -f --show "${OUTPUT_FILE}") sleep 3 @@ -126,18 +184,77 @@ losetup -d "${LOOP_DEV}" FINAL_SIZE=$(du -h "${OUTPUT_FILE}" | cut -f1) FINAL_SIZE_ACTUAL=$(du --apparent-size -h "${OUTPUT_FILE}" | cut -f1) +# 创建智能恢复脚本 +RESTORE_SCRIPT="${USB_DIR}/restore_adaptive.sh" +cat > "${RESTORE_SCRIPT}" <<'RESTORE_EOF' +#!/bin/bash +# 自适应恢复脚本 - 支持不同大小的eMMC + +set -e +IMAGE_FILE="$1" +TARGET_DEV="/dev/mmcblk0" + +[[ -f "${IMAGE_FILE}" ]] || { echo "用法: $0 <镜像文件>"; exit 1; } +[[ -f "${IMAGE_FILE}.info" ]] || { echo "缺少信息文件"; exit 1; } + +source "${IMAGE_FILE}.info" + +echo "恢复镜像到eMMC" +echo "目标设备: ${TARGET_DEV}" + +TARGET_SIZE=$(blockdev --getsize64 ${TARGET_DEV}) +TARGET_SIZE_MB=$((TARGET_SIZE / 1048576)) + +echo "目标eMMC: $((TARGET_SIZE / 1073741824))GB" + +if [[ ${TARGET_SIZE_MB} -lt ${MIN_TARGET_SIZE_MB} ]]; then + echo "错误: 目标eMMC太小,需要至少 ${MIN_TARGET_SIZE_MB}MB" + exit 1 +fi + +echo "警告: 将清空 ${TARGET_DEV}!" +read -p "继续? (yes): " confirm +[[ "$confirm" == "yes" ]] || exit 1 + +echo "写入镜像..." +dd if="${IMAGE_FILE}" of=${TARGET_DEV} bs=4M status=progress +sync + +partprobe ${TARGET_DEV} +sleep 3 + +# 扩展分区到最大 +MAX_P2_END=$((TARGET_SIZE / 512 - 34)) +parted -s ${TARGET_DEV} rm 2 +parted -s ${TARGET_DEV} unit s mkpart primary ext4 ${P2_START}s ${MAX_P2_END}s +partprobe ${TARGET_DEV} +sleep 2 + +e2fsck -f -y ${TARGET_DEV}p2 +resize2fs ${TARGET_DEV}p2 + +echo "✅ 恢复完成! 分区已扩展到最大空间" +RESTORE_EOF + +chmod +x "${RESTORE_SCRIPT}" + info_msg "=========================================" -info_msg "🎉 eMMC备份成功完成!" +info_msg "🎉 智能eMMC备份成功完成!" info_msg "=========================================" info_msg "📁 备份文件: ${OUTPUT_FILE}" -info_msg "📏 实际大小: ${FINAL_SIZE}" -info_msg "📐 逻辑大小: ${FINAL_SIZE_ACTUAL}" -info_msg "💾 eMMC已恢复原状" +info_msg "📏 备份大小: ${FINAL_SIZE}" +info_msg "📄 信息文件: ${OUTPUT_FILE}.info" +info_msg "🔧 恢复脚本: ${RESTORE_SCRIPT}" info_msg "" -info_msg "🚀 部署到新设备:" -info_msg " dd if=$(basename ${OUTPUT_FILE}) of=/dev/mmcblk0 bs=4M status=progress" +info_msg "源eMMC: ${ORIGINAL_SIZE_GB}GB" +info_msg "数据使用: ${TOTAL_USED}MB" +info_msg "最小目标: ${MIN_TARGET_SIZE}MB (约$((MIN_TARGET_SIZE / 1024))GB)" info_msg "" -info_msg "✅ 包含完整分区表和bootloader" -info_msg "✅ 保持所有原始配置不变" -info_msg "✅ 可在任意Rock5c上启动" +info_msg "🚀 恢复方法:" +info_msg " 1. 从SD卡启动目标设备" +info_msg " 2. 运行: bash ${RESTORE_SCRIPT} ${OUTPUT_FILE}" +info_msg "" +info_msg "✅ 支持恢复到任意大小eMMC (≥${MIN_TARGET_SIZE}MB)" +info_msg "✅ 自动扩展分区到最大可用空间" +info_msg "✅ 保持双分区结构不变" info_msg "=========================================" \ No newline at end of file