威联通QHora-322免拆无损刷机教程

2026-07-03 16:33:27 1点赞 1收藏 1评论

前言

手头有一台 QHora-322,其串口没有消息输出,因此无法通过线刷方式刷机。一直想找到一份像针对 Qhora-301W 那样的免拆刷机教程,但全网都找不到现成的。不过,找到了开启 SSH 的方法,并成功完成了免拆无损刷机。同时,还解决了刷机后原厂系统配置丢失的问题,实现了原厂 QuRouterOS 和 OpenWrt双系统之间的完全的自由切换。

现将刷机过程归纳总结成本教程,并将关键动作脚本化,分享给需要的朋友。受篇幅所限,本教程只介绍刷机方法和步骤,不介绍相关工具、OpenWrt和QuRouterOS原厂系统的具体使用,相关内容请自行熟悉。

本教程介绍的刷机方法有如下独特优点:

  1. 免拆、无损

    无需拆机,无需TTL刷写版,无需接TTL串口线,通过开启ssh即可刷机,有台电脑就能操作;不改变路由器硬件状态,软件可恢复成原厂状态。

  2. 双系统完全独立,可自由切换,互不影响

    OpenWrt运行时不占用原厂系统存放配置的分区,原厂系统运行时也不破坏OpenWrt配置,双系统可自由切换,切换后无需重配系统、重配网络,切换即可用。

  3. 关键刷机动作和双系统切换脚本化,降低难度和出错概率(注:脚本在AI的协助下编写完成)

重要警示:

  • 刷机有风险,稍有不慎就变砖;风险自担,请谨慎操作;

  • 刷机后,原厂系统升级会覆盖OpenWrt,因此刷机后请勿升级原厂系统;

  • QHora-321的刷机思路类似,但手头没有QHora-321,故未适配QHora-321,刷机脚本请勿直接用于QHora-321刷机。

一、刷机工具与固件准备

1.1、必备软件&网络配件

  • 7Zip解压工具:用于固件分层二次解压;

  • FinalShell:用于 SSH 远程连接、文件上传下载、命令行操作;

  • FinalShell工具也可以用Putty + WinSCP来替代,其中WinSCP登录时协议选SFTP,端口号填22200;

  • 刷机过程中需要电脑通过网线连接路由器,如果电脑没有以太网口,需要准备一个USB转以太网的转换头。

1.2、OpenWrt固件下载&预处理

  1. 前往 OpenWrt 官网,下载 iEi Puzzle-M902(QHora-322同款硬件) 对应的 SDCARD (SQUASHFS) 格式最新稳定版本固件,OpenWrt官网下载地址:https://downloads.openwrt.org/releases/25.12.4/targets/mvebu/cortexa72/openwrt-25.12.4-mvebu-cortexa72-iei_puzzle-m902-squashfs-sdcard.img.gz

  2. 使用 7Zip 对固件压缩包连续解压两次:第一次解压得到分包文件,第二次解压分包文件,第二次解压会报一个“文件末端错误:1.img”,此报错对1.img文件的完整性无影响,不影响刷机,请忽略;

  3. 解压完成后得到两个镜像文件:0.img、1.img,请将0.img 改名为 kernel.img,1.img 改名为 rootfs.img。

1.3、准备刷机脚本

本文后附两个刷机脚本和两个双系统切换脚本内容,请将两个刷机脚本pre_backup.sh、flash_write.sh的内容拷贝下来,用文本编辑器分别以pre_backup.sh、flash_write.sh文件名保存。

双系统切换脚本在要切换系统时再使用,第八、第九节有介绍。

二、备份原厂路由器配置(可选)

建议在刷机开始之前,先备份路由器原厂系统配置,具体方法是通过浏览器登录原厂QuRouterOS,进入 系统 > 系统设置 > 重置/备份/恢复 页面,点击“备份”按钮备份,按提示操作即可。

重要提示:记住这份配置中的admin用户密码,下次用此配置备份恢复的系统,密码也会恢复成此密码。

三、开启原厂 QuRouterOS SSH 权限

原厂QuRouterOS系统默认关闭 SSH 功能,可通过复位键快捷开启。

  1. 路由器正常通电、进入原厂系统正常运行状态,浏览器可登录;

  2. 连续短按 RESET 键 3 次(轻点即可,不要长按);

  3. 设备发出一长声“嘀”提示音,即代表 SSH 成功开启。

说明

  • 该开启方式在 QuRouterOS 2.6.x 版本测试通过,未测试过早期版本;若早期版本无法开启 SSH,建议升级路由器原厂固件至最新版;

  • 长按 RESET 键会直接初始化 QuRouterOS,如果不小心重置了,初始密码为路由器MAC地址,见路由器背面标签。

四、实施刷机

4.1、FinalShell登录路由器ssh

电脑网线插入路由器第二网口,电脑设置自动获取 IP,打开 FinalShell 新建 SSH 连接,参数如下(原厂专属配置):

  • 默认管理 IP:192.168.100.1(不通时以电脑以太网获取到的网关地址为准)

  • SSH 端口:22200

  • 用户名:admin

  • 密码:路由器登录密码

4.2、上传刷机文件

1.    检查并清理 /tmp 空间:

  • 在FinalShell界面ssh shell命令行执行命令df -h /tmp 查看空间;

  • 如果空闲空间不足800M,执行 sudo rm -rf /tmp/* 清除/tmp空间。

2.    上传文件:

在FinalShell界面右下角文件窗口中上传文件kernel.img、rootfs.img、pre_backup.sh、flash_write.sh四个文件上传到路由器/tmp目录下。

4.3、刷机文件预处理

  1. 在FinalShell界面右上角ssh shell窗口执行如下命令,转换windows换行符(finalshell上传的文件不会自动转换);

sed 's/r//g' /tmp/pre_backup.sh > /tmp/pre_backup.tmp && mv /tmp/pre_backup.tmp /tmp/pre_backup.sh

sed 's/r//g' /tmp/flash_write.sh > /tmp/flash_write.tmp && mv /tmp/flash_write.tmp /tmp/flash_write.sh

  1. 执行如下命令,给刷机脚本赋可执行权限:

chmod +x /tmp/pre_backup.sh

chmod +x /tmp/flash_write.sh

威联通QHora-322免拆无损刷机教程

4.4、执行预刷机脚本pre_backup.sh

ssh shell窗口执行:/tmp/pre_backup.sh

pre_backup.sh只干两件事情:

o   确定当前系统运行的活动分区,以及待刷机的备用分区;

o   完整备份原厂系统备用分区,以备以后恢复使用。

说明:威联通路由器备用分区有小概率损坏无法启动,为降低变砖风险,此教程中,在刷机前不做分区切换,保留当前正成功运行的活动分区中的原厂系统,OpenWrt刷入备用分区,故要先确定活动分区和备用分区。

威联通QHora-322免拆无损刷机教程

4.5、下载原厂备用分区备份

FinalShell 右侧文件目录进入路由器 /tmp 文件夹,找到生成的备份 img 文件,右键下载到电脑本地保存。

4.6、执行刷机脚本flash_write.sh

【风险提示】此脚本执行关键刷机动作,执行期间断电会导致路由器变砖,此脚本执行期间严禁断电。

ssh shell窗口执行:/tmp/flash_write.sh

  • flash_write.sh完成如下事项:

    • 将上传的kernel.img、rootfs.img刷写入系统备用分区;

    • 自定义环境变量boot_orig_entry、boot_owrt_entry标识原厂系统和新刷的openwrt系统所在的分区;

    • 固化原厂QuRouterOS和新刷的OpenWrt系统的启动命令,简化后续的双系统切换操作,降低操作难度和出错机率;

    • 切换系统启动环境变量,指向新刷的OpenWrt系统。

威联通QHora-322免拆无损刷机教程

五、OpenWrt 首次登录和设置

  1. 执行sudo reboot,重启后即切换成OpwnWrt系统;若启动时间过长,请断电重启。

  2. 路由器重启完成后, 通过电脑浏览器登录路由器,OpenWrt 默认地址:192.168.1.1;

  3. 192.168.1.1为网络设备常用缺省ip,如果无法访问,可能是与网络上光猫或其他网络设备ip冲突,请尝试手动设置电脑IP为 192.168.1.2,子网掩码 255.255.255.0,并断开路由器和电脑上的其他网络连接(包括Wi-Fi),仅保留电脑通过网线连接路由器的这条唯一连接,然后重试;

  4. 首次登录无密码,用户名root,根据页面提示设置管理员密码(必须设置密码,第六节的OpenWrt ssh登录才能成功);

  5. 按自己需求配置上网方式,配置系统、配置网络。

说明: OpenWrt系统中网口顺序有变,对照表如下:

威联通QHora-322免拆无损刷机教程

六、修复缺失的文件fw_env.config

OpenWrt 缺少 U-Boot 环境变量配置文件,导致fw_printenv和fw_setenv 命令执行失败,也就无法通过修改环境变量,实现双系统自由切换。修复方法:

  1. FinalShell 连接 OpenWrt SSH:端口22,用户名root,密码为你刚设置的管理员密码;

  2. 在ssh shell命令行执行命令, echo "/dev/mtd3 0x0 0x10000 0x10000 1" > /etc/fw_env.config,生成环境变量配置文件;

  3. ssh Shell窗口执行 fw_printenv 测试,能正常输出变量即修复成功。

注:有朋友刷的iStoreOS好像也缺此配置文件,亦可用此方法修复。

威联通QHora-322免拆无损刷机教程

七、备份OpenWrt配置(可选)

在需要切换回原厂系统前请做配置备份。以防原厂系统被误升级破坏了OpenWrt系统。具体方法是通过浏览器登录OpenWrt,进入 System > Backup / Flash Firmware 页面,点击"Generate archive" 按钮备份,按提示操作即可。

重要提示:记住这份配置中的root用户密码,下次用此配置备份恢复的系统,密码也会恢复成此密码。

八、OpenWrt 切换回原厂QuRouterOS

  1. FinalShell 连接 OpenWrt SSH:端口22,用户名root,密码为你设置的管理员密码

  2. 生成一键切换脚本(只需在第一次从OpenWrt切换到QuRouterOS时才生成一次):

    从附件脚本三拷贝生成一键切换脚本的生成命令,粘贴到ssh shell命令行执行,生成切换脚本switch_to_origin.sh

    ssh shell执行命令,chmod +x /root/switch_to_origin.sh,给切换脚本赋可执行权限

  3. 执行switch_to_origin.sh,完成系统切换的环境变量设置。

  4. 校验无误后执行 reboot,重启后即切换回原厂 QuRouterOS 系统。若启动时间过长,请断电重启。

威联通QHora-322免拆无损刷机教程

九、原厂QuRouterOS切换回OpenWrt

  1. 按第三节的方法开启ssh,finalshell登录路由器ssh

  2. 生成一键切换脚本(只需在第一次从QuRouterOS切换到OpenWrt时生成一次):

    从附件脚本四拷贝生成一键切换脚本的生成命令,粘贴到ssh shell命令行执行,生成切换脚本switch_to_openwrt.sh

    ssh shell执行命令,chmod +x /home/admin/switch_to_openwrt.sh,给切换脚本赋可执行权限

  3. 执行switch_to_openwrt.sh,完成系统切换的环境变量设置。

  4. 校验无误后执行sudo reboot,重启后即切换成OpenWrt。若启动时间过长,请断电重启。

威联通QHora-322免拆无损刷机教程

十、恢复成原厂系统(需要恢复原厂时执行)

如果不再需要OpenWrt,QHora-322在切换回原厂系统后,做一次升级,即可恢复成原厂状态,具体方法如下:

  1. 如果当前运行的是OpenWrt,按第八节的办法,切换回QuRouterOS原厂系统

  2. 浏览器登录到QuRouterOS系统

  3. 在“固件”页面,转到“QNAP 下载中心”下载最新固件版本(即使与当前运行版本一致,也可下载和更新)

  4. 在“固件”页面,上传下载的固件,并手动更新。更新完成,等待系统重启

  5. 重启完成后,按第三节的办法,开启ssh

  6. FinalShell登录QuRouterOS的ssh,并在ssh shell命令行执行:

sudo fw_printenv current_entry

sudo fw_printenv boot_orig_entry

  1. 如果这两值不相同,且一个为1,一个为2,则表示OpenWrt分区已被原厂系统覆盖,继续下一步,如果两值相等,则回到第3步重新更新系统。

  2. 执行如下命令,消除刷机残留环境变量:

sudo fw_setenv boot_orig_entry

sudo fw_setenv boot_owrt_entry

sudo fw_setenv boot_OpenWrt

sudo fw_setenv boot_QuRouterOS

至此,已完全消除刷机痕迹,完全恢复成原厂状态。

附件:

脚本一:pre_backup.sh 【分区检测 + 备用分区备份】

#!/bin/sh

# QHora-322 免拆无损刷机 - 前置备份脚本

# 自动分区校验 + 备用分区备份

# 非法分区直接终止,杜绝未知分区变砖

# 读取当前启动项

current_entry=$(sudo fw_printenv current_entry | awk -F= '{print $2}')

# 合法分区校验

if [ "$current_entry" = "1" ];then

owrt_entry=2

orig_entry=1

part_kernel=p2

part_rootfs=p4

elif [ "$current_entry" = "2" ];then

owrt_entry=1

orig_entry=2

part_kernel=p1

part_rootfs=p3

else

echo "======================================"

echo "错误:未知 current_entry = $current_entry"

echo "仅支持 entry=1 / entry=2,刷机终止!"

echo "======================================"

exit 1

fi

echo "======================================"

echo "分区校验通过!"

echo "当前原厂运行活动分区 entry: $current_entry"

echo "待刷写备用分区 entry: $owrt_entry"

echo "内核分区: $part_kernel"

echo "根文件系统分区: $part_rootfs"

echo "======================================"

# 开始备份备用分区

echo "正在备份备用内核分区 $part_kernel ..."

sudo dd if=/dev/mmcblk0${part_kernel} of=/tmp/${part_kernel}-backup.img || { echo "内核分区备份失败!"; exit 1; }

echo "正在备份备用根文件系统分区 $part_rootfs ..."

sudo dd if=/dev/mmcblk0${part_rootfs} of=/tmp/${part_rootfs}-backup.img || { echo "根文件系统分区备份失败!"; exit 1; }

echo "======================================"

echo "分区备份完成!"

echo "请将/tmp目录中以下文件下载到电脑:"

echo "1. ${part_kernel}-backup.img"

echo "2. ${part_rootfs}-backup.img"

echo "======================================"

echo "【重要】备份保存完成后,执行第二阶段刷机脚本 flash_write.sh"

echo "======================================"

 

 

脚本二:flash_write.sh 【写入固件 + 配置双系统环境变量】

#!/bin/sh

# QHora-322 免拆无损刷机 - 正式刷机脚本

# 写入镜像 + 配置双系统变量 + 固化原厂系统和OpenWrt启动命令

# 读取当前启动项,二次校验防误刷

current_entry=$(sudo fw_printenv current_entry | awk -F= '{print $2}')

#分区固定映射规则(硬件固化:entry1=p1+p3 / entry2=p2+p4)

if [ "$current_entry" = "1" ];then

owrt_entry=2

orig_entry=1

part_kernel=p2

part_rootfs=p4

elif [ "$current_entry" = "2" ];then

owrt_entry=1

orig_entry=2

part_kernel=p1

part_rootfs=p3

else

echo "分区校验异常,终止刷机!"

exit 1

fi

# 确认备份文件已下载交互

read -p "确认已将${part_kernel}-backup.img、${part_rootfs}-backup.img备份镜像下载至电脑?输入y继续,其他退出:" ack

if [ "$ack" != "y" ];then

echo "刷机终止,请先下载备份文件!"

exit 1

fi

# 校验镜像文件是否存在

if [ ! -f "/tmp/kernel.img" ] || [ ! -f "/tmp/rootfs.img" ];then

echo "======================================"

echo "错误:未检测到 kernel.img / rootfs.img"

echo "请上传固件至 /tmp 后重试!"

echo "======================================"

exit 1

fi

echo "开始写入 OpenWrt 内核镜像 kernel.img ..."

sudo dd if=/tmp/kernel.img of="/dev/mmcblk0${part_kernel}" || { echo "内核镜像写入失败!终止刷机"; exit 1; }

echo "开始写入 OpenWrt 根文件系统镜像 rootfs.img ..."

sudo dd if=/tmp/rootfs.img of="/dev/mmcblk0${part_rootfs}" || { echo "根文件系统镜像写入失败!终止刷机"; exit 1; }

echo "镜像写入完成,开始配置双系统环境变量..."

# 双系统分区标记变量

sudo fw_setenv boot_orig_entry $orig_entry

sudo fw_setenv boot_owrt_entry $owrt_entry

# 固化原厂QuRouterOS启动命令

if [ "$orig_entry" = "1" ];then

sudo fw_setenv boot_QuRouterOS 'ext4load mmc 0:1 0x6500000 Image; ext4load mmc 0:1 0x6000000 cn9132-db-A.dtb; setenv bootargs $console cpuidle.off=1; booti 0x6500000 - 0x6000000'

elif [ "$orig_entry" = "2" ];then

sudo fw_setenv boot_QuRouterOS 'ext4load mmc 0:2 0x6500000 Image; ext4load mmc 0:2 0x6000000 cn9132-db-A.dtb; setenv bootargs $console cpuidle.off=1; booti 0x6500000 - 0x6000000'

else

echo "======================================"

echo "错误:检测到非法orig_entry值:$orig_entry"

echo "分区校验异常,终止配置!"

echo "======================================"

exit 1

fi

# 固化OpenWrt启动命令,启动命令中root=… fstools_ignore_partname=…是OpenWrt启动中比原厂系统启动中新增的必选项

# 严格校验owrt_entry合法值,非法值直接退出,避免错误分区挂载

if [ "$owrt_entry" = "2" ];then

sudo fw_setenv boot_OpenWrt 'ext4load mmc 0:2 0x6500000 Image; ext4load mmc 0:2 0x6000000 cn9132-puzzle-m902.dtb; setenv bootargs $console root=/dev/mmcblk0p4 fstools_ignore_partname=1 cpuidle.off=1; booti 0x6500000 - 0x6000000'

elif [ "$owrt_entry" = "1" ];then

sudo fw_setenv boot_OpenWrt 'ext4load mmc 0:1 0x6500000 Image; ext4load mmc 0:1 0x6000000 cn9132-puzzle-m902.dtb; setenv bootargs $console root=/dev/mmcblk0p3 fstools_ignore_partname=1 cpuidle.off=1; booti 0x6500000 - 0x6000000'

else

echo "======================================"

echo "错误:检测到非法owrt_entry值:$owrt_entry"

echo "无法匹配合法OpenWrt根分区,终止配置!"

echo "======================================"

exit 1

fi

# ====================== 设置启动关键环境变量 ======================

sudo fw_setenv bootcmd 'run boot_OpenWrt'

sudo fw_setenv current_entry 0

# 批量校验U-Boot环境变量写入结果

echo "校验U-Boot环境变量..."

sudo fw_printenv boot_orig_entry || { echo "环境变量 boot_orig_entry 读取失败!"; }

sudo fw_printenv boot_owrt_entry || { echo "环境变量 boot_owrt_entry 读取失败!"; }

sudo fw_printenv boot_QuRouterOS || { echo "环境变量 boot_QuRouterOS 读取失败!"; }

sudo fw_printenv boot_OpenWrt || { echo "环境变量 boot_OpenWrt 读取失败!"; }

sudo fw_printenv bootcmd || { echo "环境变量 bootcmd 读取失败!"; }

sudo fw_printenv current_entry || { echo "环境变量 current_entry 读取失败!"; }

echo "======================================"

echo "全部配置完成!即将重启进入 OpenWrt 25.12.4"

echo "检查环境变量无误后,请执行sudo reboot,重启系统"

echo "======================================"

脚本三:生成切换脚本switch_to_origin.sh,从OpenWrt到QuRoterOS

cat > /root/switch_to_origin.sh <<'EOF'

#!/bin/sh

set -e

# 兼容所有fw_printenv,完整截取=后全部内容

get_fw_val() {

    local key="$1"

    fw_printenv "$key" | sed 's/^[^=]*=//'

}

# 提取字符串内第一个 mmc 0:X 的数字

get_mmc_part() {

    local cmd="$1"

    echo "$cmd" | grep -oE 'mmc 0:[0-9]+' | head -n1 | cut -d: -f2

}

# 前置校验函数:1.四个变量存在;2.entry与对应启动命令分区号匹配

check_env_exist() {

    local missing=""

    # 检查四个核心变量是否存在

    if ! fw_printenv boot_orig_entry >/dev/null 2>&1; then

        missing="${missing} boot_orig_entry"

    fi

    if ! fw_printenv boot_owrt_entry >/dev/null 2>&1; then

        missing="${missing} boot_owrt_entry"

    fi

    if ! fw_printenv boot_QuRouterOS >/dev/null 2>&1; then

        missing="${missing} boot_QuRouterOS"

    fi

    if ! fw_printenv boot_OpenWrt >/dev/null 2>&1; then

        missing="${missing} boot_OpenWrt"

    fi

    if [ -n "$missing" ]; then

        echo "错误:以下U-Boot变量未定义,请手工修复后重试:$missing"

        exit 1

    fi

    echo "✅ 全部4个必要环境变量校验存在:boot_orig_entry boot_owrt_entry boot_QuRouterOS boot_OpenWrt"

    # 校验1:boot_orig_entry == boot_QuRouterOS 内 mmc 0:X

    ORIG_ENTRY_VAL=$(get_fw_val boot_orig_entry)

    QU_CMD=$(get_fw_val boot_QuRouterOS)

    QU_MMC_PART=$(get_mmc_part "$QU_CMD")

    if [ "$ORIG_ENTRY_VAL" != "$QU_MMC_PART" ]; then

        echo "❌ 前置校验失败:"

        echo "boot_orig_entry=$ORIG_ENTRY_VAL"

        echo "boot_QuRouterOS 内 mmc 0:$QU_MMC_PART"

        echo "两者分区号不一致,请修正U-Boot环境变量后重试"

        exit 1

    fi

    # 校验2:boot_owrt_entry == boot_OpenWrt 内 mmc 0:X

    OW_ENTRY_VAL=$(get_fw_val boot_owrt_entry)

    OW_CMD=$(get_fw_val boot_OpenWrt)

    OW_MMC_PART=$(get_mmc_part "$OW_CMD")

    if [ "$OW_ENTRY_VAL" != "$OW_MMC_PART" ]; then

        echo "❌ 前置校验失败:"

        echo "boot_owrt_entry=$OW_ENTRY_VAL"

        echo "boot_OpenWrt 内 mmc 0:$OW_MMC_PART"

        echo "两者分区号不一致,请修正U-Boot环境变量后重试"

        exit 1

    fi

    echo "✅ entry与对应启动命令mmc分区号全部匹配"

}

# 执行全部前置校验

check_env_exist

# ---------------- 切换原厂逻辑 ----------------

ORIG_ENTRY=$(get_fw_val boot_orig_entry)

echo "原厂分区标识 boot_orig_entry = $ORIG_ENTRY"

fw_setenv current_entry "$ORIG_ENTRY"

echo "已同步 current_entry = $ORIG_ENTRY"

ORIG_BOOT_CMD=$(get_fw_val boot_QuRouterOS)

echo "读取QuRouterOS完整启动命令完成"

fw_setenv bootcmd "$ORIG_BOOT_CMD"

echo "已替换bootcmd为原厂启动指令"

echo -e "n===== 后置校验1:boot_orig_entry / current_entry ====="

fw_printenv boot_orig_entry current_entry

echo -e "n===== 后置校验2:boot_QuRouterOS 与 bootcmd 全文比对 ====="

VAL_QU=$(get_fw_val boot_QuRouterOS)

VAL_BOOTCMD=$(get_fw_val bootcmd)

if [ "$VAL_QU" = "$VAL_BOOTCMD" ]; then

    echo "✅ boot_QuRouterOS 与 bootcmd 内容完全一致"

else

    echo "❌ boot_QuRouterOS 与 bootcmd 内容不匹配!"

    exit 1

fi

echo -e "n===== 后置校验3:mmc分区号与current_entry匹配 ====="

MMC_NUM=$(get_mmc_part "$VAL_BOOTCMD")

CUR_ENTRY=$(get_fw_val current_entry)

echo "bootcmd 内 mmc 0:$MMC_NUM"

echo "current_entry = $CUR_ENTRY"

if [ "$MMC_NUM" = "$CUR_ENTRY" ]; then

    echo "✅ 分区数字匹配,全部校验通过"

else

    echo "❌ mmc分区号与current_entry不一致,配置异常"

    exit 1

fi

echo -e "n操作完成,执行 reboot 重启进入原厂系统"

EOF

脚本四:生成切换脚本switch_to_openwrt.sh,从QuRoterOS到OpenWrt

cat > /home/admin/switch_to_openwrt.sh <<'EOF'

#!/bin/sh

set -e

# 兼容所有fw_printenv,完整截取=后全部内容

get_fw_val() {

    local key="$1"

    sudo fw_printenv "$key" | sed 's/^[^=]*=//'

}

# 提取字符串内第一个 mmc 0:X 的数字

get_mmc_part() {

    local cmd="$1"

    echo "$cmd" | grep -oE 'mmc 0:[0-9]+' | head -n1 | cut -d: -f2

}

# 前置校验函数:1.四个变量存在;2.entry与对应启动命令分区号匹配

check_env_exist() {

    local missing=""

    # 检查四个核心变量(boot_openwrt_entry → boot_owrt_entry)

    if ! sudo fw_printenv boot_orig_entry >/dev/null 2>&1; then

        missing="${missing} boot_orig_entry"

    fi

    if ! sudo fw_printenv boot_owrt_entry >/dev/null 2>&1; then

        missing="${missing} boot_owrt_entry"

    fi

    if ! sudo fw_printenv boot_QuRouterOS >/dev/null 2>&1; then

        missing="${missing} boot_QuRouterOS"

    fi

    if ! sudo fw_printenv boot_OpenWrt >/dev/null 2>&1; then

        missing="${missing} boot_OpenWrt"

    fi

    if [ -n "$missing" ]; then

        echo "错误:以下U-Boot变量未定义,请手工修复后重试:$missing"

        exit 1

    fi

    echo "✅ 全部4个必要环境变量校验存在:boot_orig_entry boot_owrt_entry boot_QuRouterOS boot_OpenWrt"

    # 校验1:boot_orig_entry == boot_QuRouterOS 内 mmc 0:X

    ORIG_ENTRY_VAL=$(get_fw_val boot_orig_entry)

    QU_CMD=$(get_fw_val boot_QuRouterOS)

    QU_MMC_PART=$(get_mmc_part "$QU_CMD")

    if [ "$ORIG_ENTRY_VAL" != "$QU_MMC_PART" ]; then

        echo "❌ 前置校验失败:"

        echo "boot_orig_entry=$ORIG_ENTRY_VAL"

        echo "boot_QuRouterOS 内 mmc 0:$QU_MMC_PART"

        echo "两者分区号不一致,请修正U-Boot环境变量后重试"

        exit 1

    fi

    # 校验2:boot_owrt_entry == boot_OpenWrt 内 mmc 0:X

    OW_ENTRY_VAL=$(get_fw_val boot_owrt_entry)

    OW_CMD=$(get_fw_val boot_OpenWrt)

    OW_MMC_PART=$(get_mmc_part "$OW_CMD")

    if [ "$OW_ENTRY_VAL" != "$OW_MMC_PART" ]; then

        echo "❌ 前置校验失败:"

        echo "boot_owrt_entry=$OW_ENTRY_VAL"

        echo "boot_OpenWrt 内 mmc 0:$OW_MMC_PART"

        echo "两者分区号不一致,请修正U-Boot环境变量后重试"

        exit 1

    fi

    echo "✅ entry与对应启动命令mmc分区号全部匹配"

}

# 执行全部前置校验

check_env_exist

# ---------------- 切换OpenWrt逻辑:先更新bootcmd,后设置current_entry=0 ----------------

OW_BOOT=$(get_fw_val boot_OpenWrt)

sudo fw_setenv bootcmd "$OW_BOOT"

sudo fw_setenv current_entry "0"

echo "===== 后置校验1:boot_owrt_entry / current_entry ====="

sudo fw_printenv boot_owrt_entry current_entry

# 新增校验current_entry必须等于0

CUR_ENTRY_CHECK=$(get_fw_val current_entry)

if [ "$CUR_ENTRY_CHECK" = "0" ]; then

    echo "✅ current_entry = 0,符合设定"

else

    echo "❌ current_entry 不为0,配置异常"

    exit 1

fi

echo -e "n===== 后置校验2:boot_OpenWrt 与 bootcmd 全文比对 ====="

VAL_OW=$(get_fw_val boot_OpenWrt)

VAL_BOOT=$(get_fw_val bootcmd)

if [ "$VAL_OW" = "$VAL_BOOT" ]; then

    echo "✅ 启动命令完整匹配"

else

    echo "❌ 启动命令不匹配"

    exit 1

fi

echo -e "n===== 后置校验3:mmc分区号与boot_owrt_entry匹配 ====="

MMC_NUM=$(get_mmc_part "$VAL_BOOT")

OW_ENTRY=$(get_fw_val boot_owrt_entry)

echo "mmc分区号:$MMC_NUM boot_owrt_entry:$OW_ENTRY"

if [ "$MMC_NUM" = "$OW_ENTRY" ]; then

    echo "✅ 分区编号匹配"

else

    echo "❌ 分区编号不匹配"

    exit 1

fi

echo "操作完成,执行sudo reboot 重启进OpenWrt"

EOF

展开 收起
1评论

  • 精彩
  • 最新
  • 终于有教程了,之前还花了钱刷的...
    大佬的不死uboot有吗

    校验提示文案

    提交
提示信息

取消
确认
评论举报

相关文章推荐

更多精彩文章
更多精彩文章

dafan116

Ta还没有介绍自己

关注 打赏
最新文章 热门文章
1
扫一下,分享更方便,购买更轻松