OpenWrt x86 ext4 系统升级最佳实践

Caution

本文撰写于 OpenWrt 23 release 版本发布之时，文中所述内容在未来可能会发生改变。请务必备份重要数据，仔细阅读可能的错误信息并谨慎操作，作者不对本文内容做任何保证。

WHY? 为什么会有这篇文章存在？

因为 OpenWrt 社区摆烂 or 人手不够没有给 target x86 额外做一套合适的升级工具，因此 x86 设备系统升级工具跟其它 target 一样有且仅有sysupgrade，只能简单粗暴地刷写磁盘镜像。OpenWrt 文档中提供了一个既不优雅也不简单还带有副作用的绥靖方案。

Tip

还有个比较好的解决方案是利用 extroot，使用 SquashFS 镜像将 OverlayFS 的 upper 与 lower 分离放到不同的磁盘上，升级版本时直接使用预编译镜像刷写 lower 所在磁盘，随后修改 extroot 配置重新将 OverylayFS 指向原有 upper 磁盘即可恢复原有状态。但由于目前主线 OpenWrt 社群仍然没有修复这个横跨 5 年的 bug，extroot 的配置不生效故此方案不可行1。

作为技术又菜懂的也不多但是喜欢探索的ProUser受害者，花点时间根据一份升级脚本 2 撰写此篇升级指南，以方便各位 OpenWrt 新手更方便地升级追新。

最佳实践方案

Warning

本文所述方法仅适用于 OpenWrt 主线及拥有良好发行版本和包管理源的 ImmortalWrt 等分支变体，不适用于任何自编译，“大神” 魔改的重发行版本。

Note

本文 target 是 x86_64，升级至 OpenWrt 23.05.0，请自行调整以符合自己所需。

OpenWrt x86 本质上是个特化版的 Linux 发行版，理论上当然也可以如一般 Linux 发行版一样保留配置升级大版本的，只是如前所述没有升级工具，因此需要进行一系列操作来手动实现。

获取版本号（可选）

oldver=$(awk -F\" 'NR==2 {print $2}' /usr/lib/os-release)
newver=23.05.0

升级所有软件包（可选）

opkg update
opkg upgrade netifd #单独升级 netifd 是因为它会重启网络接口中断 SSH 连接
opkg list-upgradable | cut -d ' ' -f 1 | xargs opkg upgrade

替换内核

Important

此处需要确认 boot 分区挂载位置，我的挂载位置是 /boot 且没有二次挂载，文件树看起来是下面这样子，请根据自己实际内核位置修改路径。

Copy
tree /boot

/boot
├── boot
│   ├── grub
│   │   ├── boot.img
│   │   ├── core.img
│   │   ├── grub.cfg
│   │   └── grub.cfg.b
│   ├── vmlinuz
│   └── vmlinuz.23.05.0-rc3
└── efi
└── boot
└── bootx64.efi

备份旧版本内核
mv /boot/boot/vmlinuz /boot/boot/vmlinuz.$oldver

下载新版内核
wget -O /boot/boot/vmlinuz "https://downloads.openwrt.org/releases/23.05.0/targets/x86/64/openwrt-23.05.0-x86-64-generic-kernel.bin"

校验文件 hash 是否一致
sha256sum /boot/boot/vmlinuz

处理软件包

手动下载新发行版的 kernel.ipk
注意这并不是真正的内核，而是 opkg 提供内核版本依赖的软件包
wget https://downloads.openwrt.org/releases/23.05.0/targets/x86/64/packages/kernel_5.15.134-1-47964456485559d992fe6f536131fc64_x86_64.ipk

手动下载新发行版的 keyring.ipk（可选）
wget https://downloads.openwrt.org/releases/packages-23.05/x86_64/base/openwrt-keyring_2022-03-25-62471e69-2_x86_64.ipk

Note

release 版本所使用的 key 与 snapshot/rc 版有所区别，故在其之间切换时需要安装 keyring.ipk，反之则不需要。

安装它们：
opkg install kernel_*
opkg install openwrt-keyring_*

修改 opkg 源

替换软件源发行版版本号
sed -i.backup "s/$oldver/$newver/g" /etc/opkg/distfeeds.conf

更新包列表
opkg update

升级新发行版软件包

使 /lib/functions.sh 失能
（这一步忘记因为啥了，有知道的评论区补充下）
mv /lib/functions.sh /lib/functions.sh.b

升级基本文件
opkg upgrade base-files

升级并强制覆写除 netifd 之外的所有包
opkg list-upgradable | cut -d ' ' -f 1 | grep -v 'netifd' | xargs opkg upgrade --force-overwrite

升级 netifd
opkg upgrade netifd

reboot&done

如果不出意外的话，重新启动之后就是全新版本的 OpenWrt 了。
如果前面有报错而你没有处理的话，此次重启可能就再也起不来了。

注释

Footnotes

据信某些衍生版本已经合并修复代码，但鉴于其可能缺失发行版和包管理源故此处不讨论。 ↩

大概是 OpenWrt 21 时代网上找的，其中部分已经失效，脚本来源已不可考，如果有知道来源的可以评论留个链接：

Copy
#!/bin/sh

oldver=$(awk -F\" 'NR==2 {print $2}' /usr/lib/os-release)
newver=$(echo $1| awk -F/ '{print $5}')
if [ -z "$1" ]; then
echo "Please input new kernel URL"
else
if [ $oldver == $newver ]; then
echo "No need upgrade"
else
#Upgrade
opkg update
opkg upgrade netifd
opkg list-upgradable | cut -d ' ' -f 1 | xargs opkg upgrade
#Kernel
mount /dev/sda /boot
mv /boot/boot/vmlinuz /boot/boot/vmlinuz.$oldver
wget -O /boot/boot/vmlinuz https://downloads.openwrt.org/releases/$newver/targets/x86/64/generic-kernel.bin
cd /tmp
wget $1
opkg install kernel_*
#Edit /etc/opkg/distfeeds.conf
sed -i.bak "s/$oldver/$newver/g" /etc/opkg/distfeeds.conf
opkg update
#Upgrade the base-files package
chmod -x /lib/functions.sh
opkg upgrade base-files
#Reconfigure your DNS setting in /etc/resolv.conf
ln -sf /tmp/resolv.conf.ppp /etc/resolv.conf
#Upgrade all other core packages
opkg list-upgradable | cut -d ' ' -f 1 | xargs opkg upgrade
fi
fi

find_pkg(){
local name=$1
awk '$1 ~ /^src/' /etc/opkg.conf /etc/opkg/*.conf | while read type repo url pad; do
local f=/var/opkg-lists/$repo
{
[ $type == "src/gz" ] && zcat $f || cat $f;
} | {
awk -vname="$name" '$1=="Package:" && $2==name {f=1;r=1} $0=="" {f=0} f {print} END{exit 1-r}'
} | while read key val pad; do
[ "$key" == "Version:" ] && ver=$val
[ "$key" == "Filename:" ] && {
echo found $ver @$repo
echo $url/$val
}
done
done
}

↩