1. 🧱 问题背景
某天,Coldrain 像往常一样打开自己的电脑,然后像往常一样按下了
Shift+Alt+T
,并像往常一样在终端输入paru -Syu
来进行滚包。然而,他在进行滚包操作之前没有登陆校园网,于是引发了报错。Coldrain 意识到没有登陆校园网之后,火速登陆了校园网,重新进行滚包操作,结果引发了同样的报错…
背景如上所示 ⬆️,我在没有登陆校园网的情况下进行了滚包操作,然后理所当然地引发了如下报错:
error: GPGME error: No data error: GPGME error: No data error: GPGME error: No data error: failed to synchronize all databases (unexpected error) Terminal
问题在于:我在报错之后登陆了校园网,重新输入 paru -Syu
进行滚包操作,结果触发了相同的报错。
2. 🔍 问题复现与分析
Coldrain 百思不得其解,于是向 Deepseek 大人求助,于是得知了问题产生的流程…
Step1. 校园网未登录
大部分校园网都需要登陆才可以正常使用。
在未登录校园网的情况下:
- 任何 HTTP/HTTPS 流量都会被劫持,返回
302
错误并重新定向到校园网认证界面。也就是说,此时你向任意一个 url 发送 GET 等请求,都会被校园网拦下来,并且将你拉到登陆界面。(DNS 污染)
Step2. Pacman 下载到错误文件
如上所说,在未登录校园网情况下,任何请求都会被重新定向到校园网认证界面。
Pacman
在滚包时,首先会先尝试下载仓库数据库(core.db 等)。
于是,在未登录校园网的情况下,pacman 下载到的文件,是校园网认证界面的 HTML 文件 😧
Step3. Pacman GPG 验证签名出错
在下载到校园网认证界面的 HTML 文件时,Pacman
并不知道自己下载到了错误的文件,于是 Pacman
像往常一样尝试用 GPG 验证该文件的签名…
由于 HTML 文件并没有有效的签名,所以 Pacman
意识到了下载到错误的文件,于是将自己发现的问题告诉用户:
error: GPGME error: No data Terminal
于是用户在这一提示下意识到自己没有登陆校园网,并登陆校园网重新进行滚包,结果触发 了相同的报错!?
那么,问题出在哪里呢?为什么此时还是无法正常滚包呢?
Step4. Pacman 触发缓存特性
刚才我们讲过,Pacman
尝试下载了仓库数据库,结果下载到了校园网的 HTML 文件,而这个 HTML 文件成为了本地缓存文件(如 core.db 等)。
(敲黑板)
然而,
Pacman
自身具有一个缓存策略:
Pacman
在正常情况下,会默认优先使用本地缓存文件来进行滚包,而非强制重新下载。同时,
Pacman
为了节省带宽,会假设本地缓存的文件是有效的,仅在以下情况重新下载:
- 本地文件已过期(根据服务器返回的
Last-Modified
时间)。- 用户显式要求强制刷新(如
pacman -Syyu
)。所以,用户第一次下载的 core.db 实际是一个 HTML 文件,但
Pacman
的缓存机制 无法自动识别其内容是否合法,仅依赖时间戳或强制刷新指令。❓什么是时间戳误导
如果校园网的认证页面服务器返回的 Last-Modified 时间较新,Pacman 会认为本地缓存的 HTML 文件是“最新”的,从而跳过重新下载。
这种情况常见于某些网络拦截策略,导致 Pacman 被误导。
于是,当我们在未清除本地缓存的情况下登陆校园网并重新尝试滚包时,pacman 并没有去下载新的仓库数据库,而是直接用本地缓存的校园网认证 HTML 文件来进行滚包,结果可想而知是再次触发相同的报错。
这里 Pacman
使用本地缓存文件而报错的流程大概如下所示:
1. pacman -Syu 2. 检查本地缓存 → 发现存在 core.db 3. 向服务器发送请求:“core.db 是否有更新?” 4. 服务器返回:“无需更新”(时间戳相同或拦截响应) 5. Pacman 直接使用本地 core.db(实际是 HTML 文件) 6. GPG 验证失败 → 报错 Terminal
Step5. 问题关键
由此可知,解决问题的关键在于强制清除缓存文件。
3. 💊 解决方案
这里直接放命令了:
# 删除所有仓库数据库缓存(解决核心问题) sudo rm -rf /var/lib/pacman/sync/*.db sudo rm -rf /var/lib/pacman/sync/*.sig # 强制重新下载数据库(-Syy 表示强制刷新) pacman -Syyu # 或者用下面这个: paru -Syyu Terminal
于是后面的滚包操作就可以正常进行了!😁
竟然无条件信任本地缓存,哈基 Pacman,你这家伙…
4. 🤔 扩展思考
4.1 Pacman 的设计哲学
- 保守性:
Pacman
倾向于减少网络请求和磁盘写入,依赖用户明确指令(如-Syy
)执行高风险操作。 - 安全性:GPG 验证是硬性要求,即使文件看似“存在”,也必须通过签名检查。
- 透明性:错误信息直接反映根本原因(如
GPGME error
),而非隐藏底层问题
4.2 为什么 Pacman 不会自动覆盖错误文件
Pacman
的设计逻辑遵循以下原则:
- 信任本地缓存:假设用户已通过 GPG 验证的文件是安全的,避免重复下载。
- 依赖时间戳和服务器响应:仅当服务器明确指示文件已更新时,才会替换本地缓存。
- 不主动清理用户数据:避免因误判导致数据丢失(例如用户手动修改了数据库文件)。
4.3 类比理解
想象你从图书馆借了一本书(core.db
),但拿回家发现书页被替换成了广告传单(HTML 认证页面)。第二天你再去图书馆:
- 如果直接还书:图书管理员(Pacman)会检查书的封面和借阅记录(时间戳),认为这是同一本书,不会主动替换内容。
- 必须明确告知:“这本书被篡改了,请给我一本新的”(即删除旧文件并强制刷新)。
4.4 注意点
下次遇到类似问题时,记住 Pacman 的缓存目录(/var/lib/pacman/sync/ 和 /var/cache/pacman/pkg/)是首要检查对象。