跳转到内容
来自 Arch Linux 中文维基

如果遇到下面的问题,很可能需要恢复 pacman 本地数据库:

  • pacman -Q 什么都不输出,pacman -Syu 错误地报告系统已为最新。
  • 使用 pacman -S 安装软件包时,很多已经安装过的依赖提示未安装。

pacman 储存本地软件包的数据库 /var/lib/pacman/local 很可能已经损坏甚至丢失。这是很严重的问题,请按照如下步骤修复。

首先,确认 pacman 的日志文件还在:

$ ls /var/log/pacman.log

如果日志丢失了,那就不能使用本方法修复,可以尝试使用Xyne的软件包检测脚本重建数据库。要是还行不通,很遗憾,最后的路就是重装系统。

生成软件包恢复清单

警告:如果出于某些原因,您的 pacman 缓存或 makepkg package destination 包含了其他架构的包,请在继续前移除它们。

安装 pacman-contrib 以获取 paclog-pkglist

创建日志过滤脚本并使其可执行

pacrecover
#!/bin/bash -e

# load configuration settings from the makepkg configuration file
. /etc/makepkg.conf

# determine the cache directory from pacman configuration, defaulting to /var/cache/pacman/pkg, remove prefix with sed
PKGCACHE=$( (grep -m 1 '^CacheDir' /etc/pacman.conf || echo 'CacheDir = /var/cache/pacman/pkg') | sed 's/CacheDir = //')

# define directories to search for package files
pkgdirs=("$@" "$PKGDEST" "$PKGCACHE")

# read package name and version from input and construct a search pattern for package files
while read -r -a parampart; do

        # loop through each directory to search for matching package files
        for pkgdir in "${pkgdirs[@]}"; do

                # check each file matching the pattern in the current directory
                for i in "$pkgdir"/"${parampart[0]}"-"${parampart[1]}"-*.pkg.tar.{xz,zst} ; do

                        # if a file exists, print its path and stop checking further
                        [ -f "${i}" ] && { echo "${i}" ; break; };
                done

                # If no file is found, output the package name to stderr
        done || echo "${parampart[0]}" 1>&2 
done

运行脚本(可选择将带有包的目录作为参数):

$ paclog-pkglist /var/log/pacman.log | ./pacrecover >files.list 2>pkglist.orig

这样做会创建两个文件:files.list 存储着依然在设备上的软件包的包文件;pkglist.orig 存储着需要下载的包。接下来的操作可能会导致设备上的旧版本包的部分文件与新版不匹配,需要手动干预。

过滤掉第二个列表中无法用软件仓库安装的包:

$ { cat pkglist.orig; pacman -Slq; } | sort | uniq -d > pkglist
注意:如果失败并返回报错 failed to initialise alpm library,请检查/var/lib/pacman/local/ALPM_DB_VERSION 是否存在。若不存在,请以 root 执行pacman-db-upgrade,然后执行 pacman -Sy,接下来重试之前的命令。

检查是否缺失一些重要的 base 软件包并将它们加入列表:

$ comm -23 <({ echo base ; expac -l '\n' '%E' base; } | sort) pkglist.orig >> pkglist

如果两个列表的内容均就绪,无甚缺漏,就请继续下一步,它们将被用于恢复 pacman 的已安装软件包数据库 /var/lib/pacman/local/

开始恢复

为恢复工作定义一个 bash 函数

 recovery-pacman() {
    pacman "$@"  \
    --log /dev/null   \
    --noscriptlet     \
    --dbonly          \
    --overwrite "*"   \
    --nodeps          \
    --needed
}

--log /dev/null 参数可以避免污染 pacman 日志;--needed 参数可以跳过数据库中已存在的包以节省时间;--nodeps 参数允许安装已缓存的包,即使已安装的包依赖于更新版本。其余选项用于使 pacman 在进行操作时不读写文件系统。

同步数据库:

# pacman -Sy

files.list 安装本地可用的包以开始生成数据库:

# recovery-pacman -U $(< files.list)

pkglist 安装其余包:

# recovery-pacman -S $(< pkglist)

更新本地数据库以将不被其它包依赖的包标记为明确按照并将其它包标记为依赖。您将来在移除软件包时需要格外小心,但是原始数据库已丢失,这已经是我们所能做的最好的。

# pacman -D --asdeps $(pacman -Qq)
# pacman -D --asexplicit $(pacman -Qtq)

可选检查安装的软件包是否损坏:

# pacman -Qk

可选参阅 Pacman/提示和技巧#查找不属于任何软件包的文件

更新所有软件包:

# pacman -Su