AlmaLinux / CentOS 9 — 修復誤刪 RPM 套件導致 DNF 與 RPM 無法運作的完整復原紀錄
主機環境:AlmaLinux 9.6 (Sage Margay)
日期:2025-10-04
一、問題背景
在一次誤操作中,系統核心的 RPM 套件管理元件(rpm / rpm-libs / rpm-build-libs) 被移除或破壞,導致:
dnf
執行報錯:ImportError: cannot import name 'ts' from 'rpm._rpm'
rpm
無法使用、甚至不存在/usr/bin/rpm
dnf
顯示:error: no dbpath has been set error: cannot open Packages database in /%{_dbpath}
- 系統套件管理完全中斷,無法安裝、更新或重建資料庫。
(base) [root@khmail ~]# dnf
error: Unable to open /usr/lib/rpm/rpmrc for reading: 沒有此一檔案或目錄.
Traceback (most recent call last):
File "/usr/bin/dnf", line 61, in
from dnf.cli import main
File "/usr/lib/python3.9/site-packages/dnf/init.py", line 30, in
import dnf.base
File "/usr/lib/python3.9/site-packages/dnf/base.py", line 32, in
from dnf.comps import CompsQuery
File "/usr/lib/python3.9/site-packages/dnf/comps.py", line 27, in
from dnf.exceptions import CompsError
File "/usr/lib/python3.9/site-packages/dnf/exceptions.py", line 22, in
import dnf.util
File "/usr/lib/python3.9/site-packages/dnf/util.py", line 30, in
import dnf.callback
File "/usr/lib/python3.9/site-packages/dnf/callback.py", line 22, in
import dnf.yum.rpmtrans
File "/usr/lib/python3.9/site-packages/dnf/yum/rpmtrans.py", line 26, in
import rpm
File "/usr/lib64/python3.9/site-packages/rpm/init.py", line 39, in
from rpm.transaction import *
File "/usr/lib64/python3.9/site-packages/rpm/transaction.py", line 3, in
from rpm._rpm import ts as TransactionSetCore
ImportError: cannot import name 'ts' from 'rpm._rpm' (/usr/lib64/python3.9/site-packages/rpm/_rpm.cpython-39-x86_64-linux-gnu.so)
二、初步檢查與環境狀態
- 檢查 RPM 主程式是否存在:
which rpm
→ 無結果。 - 檢查 RPM Python 模組:
python3 -c "import rpm"
→ 報ImportError: cannot import name 'ts'
,顯示底層.so
模組損毀。 - 確認
/usr/lib64/lib*rpm*.so*
等關鍵檔案缺失。
三、採取的修復步驟
1️⃣ 手動下載 RPM 套件
從 AlmaLinux 官方鏡像站下載:
http://repo.almalinux.org/almalinux/9/BaseOS/x86_64/os/Packages/
必要套件:
rpm-4.16.1.3-37.el9.x86_64.rpm
rpm-libs-4.16.1.3-37.el9.x86_64.rpm
rpm-build-libs-4.16.1.3-37.el9.x86_64.rpm
- (輔助)
lua-libs-5.4.4-4.el9.x86_64.rpm
,zstd-1.5.1-2.el9.x86_64.rpm
,ima-evm-utils
2️⃣ 使用 Python 手動解壓 RPM 檔案
由於可能會某些套件移除系統缺乏 rpm2cpio
、bsdtar
等工具,
使用 Python 直接分析 .rpm
檔案內的 zstd payload:
import os, re, subprocess
rpm_path = "/tmp/rpm-libs-4.16.1.3-37.el9.x86_64.rpm"
out_dir = "/tmp/rpm_extract"
os.makedirs(out_dir, exist_ok=True)
data = open(rpm_path, "rb").read()
m = re.search(b'\x28\xB5\x2F\xFD', data)
payload = data[m.start():]
open(out_dir + "/payload.cpio.zst", "wb").write(payload)
os.system(f"cd {out_dir} && unzstd payload.cpio.zst && cpio -idmv < payload.cpio")
完成後,獲得解壓內容:
./usr/lib64/librpm.so.9
./usr/lib64/librpmio.so.9
./usr/bin/rpm
建議可以先下載cpio 以利解壓縮 cpio-2.13-16.el9.x86_64.rpm
python3 - <<'PYCODE'
import os, subprocess
rpm_file = "/tmp/cpio-2.13-16.el9.x86_64.rpm"
out_dir = "/tmp/rpm_build_libs_extract"
os.makedirs(out_dir, exist_ok=True)
print(f"📦 正在解析 {rpm_file} ...")
with open(rpm_file, "rb") as f:
data = f.read()
# 直接掃描 zstd magic bytes (28 B5 2F FD)
magic = b"\x28\xB5\x2F\xFD"
offset = data.find(magic)
if offset == -1:
print("❌ 找不到 ZSTD 壓縮段,RPM 檔可能損壞或不是 zstd 格式")
raise SystemExit(1)
payload = data[offset:]
out_zst = f"{out_dir}/payload.cpio.zst"
with open(out_zst, "wb") as f:
f.write(payload)
print(f"✅ 找到 zstd 段落,位於 offset={offset}, 輸出 {out_zst}")
# 解壓縮
os.system(f"cd {out_dir} && unzstd payload.cpio.zst && cpio -idmv < payload.cpio")
print("✅ 已完成 rpm-build-libs 解壓至 /tmp/rpm_build_libs_extract")
PYCODE
3️⃣ 覆蓋修復關鍵檔案
將提取的檔案覆蓋回系統:
cp -av rpm-4.16.1.3-37.el9.x86_64/usr/bin/rpm /usr/bin/
cp -av rpm-libs-4.16.1.3-37.el9.x86_64/usr/lib64/librpm*.so* /usr/lib64/
cp -av rpm-build-libs-4.16.1.3-37.el9.x86_64/usr/lib64/librpmbuild*.so* /usr/lib64/
ldconfig
檢查:
rpm --version
# ➜ RPM version 4.16.1.3
4️⃣ 修正 /usr/lib/rpm/rpmrc
內容格式錯誤
原檔案中 dbpath:/var/lib/rpm
應為空白分隔:
cat >/usr/lib/rpm/rpmrc <<'EOF'
macrofiles: /usr/lib/rpm/macros:/usr/lib/rpm/%{_target}/macros:/etc/rpm/macros.*:/etc/rpm/macros:/etc/rpm/%{_target}/macros:~/.rpmmacros
optflags: x86_64 -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection
buildarchtranslate: noarch: noarch
buildarchtranslate: x86_64: x86_64
dbpath /var/lib/rpm
EOF
5️⃣ 重建 RPM 資料庫
cd /var/lib/rpm
rm -f __db*
rpmdb --rebuilddb
驗證:
rpm -qa | head
✅ 可成功列出套件。
6️⃣ 驗證 DNF 回復
/usr/bin/dnf --version
# ➜ 4.14.0
dnf list kernel
# ➜ 正常顯示可用版本
四、問題根源與教訓
問題點 | 說明 |
---|---|
誤刪 RPM 相關核心庫rpm 核心元件 (/usr/bin/rpm、librpm.so、librpmbuild.so) | 導致系統無法管理套件,dnf 、rpm 同時損毀 |
rpmrc 沒有檔案(或/usr/lib/rpm/macros 沒有檔案) [root@khmail fixrpm_full]# rpm -qa | head error: bad option ‘dbpath’ at (null):5 error: no dbpath has been set error: cannot open Packages database in /%{_dbpath} (base) [root@khmail fixrpm_full]# | 造成無法找到 dbpath: 可以利用上述下戴相關linux rpm- 包,來解壓縮後找到 |
缺乏 rpm2cpio / bsdtar | 需改用 Python 分析 RPM header 直接提取 payload |
rpmdb 損毀 | 透過 rpmdb --rebuilddb 成功重建 |
五、恢復後建議
- 立即備份 RPM 相關核心:
mkdir -p /root/rpm_backup cp -a /usr/bin/rpm /usr/lib64/librpm*.so* /usr/lib/rpm/rpmrc /root/rpm_backup/
- 啟用 DNF 自動修復插件:
dnf install dnf-plugins-core -y
- 建立自動快照或快照卷(如使用 LVM / Btrfs)。
- 若未來系統升級、請避免同時移除
rpm
與dnf
。
六、最終狀態確認
rpm --version
# RPM version 4.16.1.3
/usr/bin/dnf --version
# 4.14.0
rpm -qa | head
# (成功列出系統套件清單)
🎯 系統已完全修復。在linux上我們常利用管理
發佈留言