mos

mos

OpenWrt x86 ext4 系统升级最佳实践

OpenWrt_Logo

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#

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

  2. 大概是 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
    }
    
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。