dnf install bilibili 失败:旧包 %postun 移除了一个从未配置过的 update-alternatives 条目

【时间】2026 年 9 月 26 号,dnf install bilibili-1.19.0 在 %postun 阶段挂掉

error: %postun scriptlet failed, exit status 2

系统表面看起来一切正常,但 dnf 报事务失败。先查 rpmdb:

$ rpm -q bilibili
bilibili-1.19.0-1.x86_64

只有 1.19.0,旧版 1.17.5 已经移除。/usr/bin/bilibili 符号链接正常:

/usr/bin/bilibili → /etc/alternatives/bilibili → /opt/bilibili/bilibili

直接运行 bilibili,成功启动。系统没坏,是上游脚本的 bug。

坑

旧包的 %postun 执行:

update-alternatives --remove bilibili /usr/bin/bilibili

但新包的 %post 注册的备选路径是 /opt/bilibili/bilibili。update-alternatives --remove 找不到条目,exit 2,dnf 报事务失败。

这是典型的“旧包卸载脚本和新包安装脚本不一致”问题——上游在某个版本把安装路径从 /usr/bin 改到了 /opt/bilibili,但没同步更新 %postun 里的路径。

修复

写了一个容错的 after-remove.sh,用 update-alternatives --query 先查条目存在不,再决定要不要 remove:

#!/bin/bash
# after-remove.sh
BIN="/opt/bilibili/bilibili"
LEGACY="/usr/bin/bilibili"
for path in "$BIN" "$LEGACY"; do
    if update-alternatives --query bilibili 2>/dev/null | grep -q "Link: $path"; then
        update-alternatives --remove bilibili "$path" 2>/dev/null || true
    fi
done
exit 0

在 conf/build.json 的 rpm/deb 段用 afterRemove 引用这个脚本。提交到 msojocs/bilibili-linux,开了 PR。

经验

  1. update-alternatives --remove 找不到条目时 exit 2,不是幂等的。写 %postun 或 after-remove 脚本时必须先 --query 确认条目存在。
  2. dnf 事务失败不等于系统坏了。先查 rpmdb 和符号链接,确认实际状态再决定是否要补救。
  3. 上游包改了安装路径但没更新卸载脚本,是 RPM 打包里最常见的坑之一。

🎵 Listening companion