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 且没有二次挂载,文件树看起来是下面这样子,请根据自己实际内核位置修改路径。
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 时代网上找的,其中部分已经失效,脚本来源已不可考,如果有知道来源的可以评论留个链接:
↩#!/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 }