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 }