Archlinux 修復紀錄

Universal Studio Singapore

之前我在推特上有說過我不小心把我放 blog 的主機搞壞,當時就是用 pacman 更新過後,出現一些錯誤,我快速的重跑pacman -Syu然後就開始一直出現錯誤了,當時想說是因為我太久沒更新,然後有相依性錯誤造成系統幾乎爛掉,一度要放棄,不過因為網站相關的 instance 都還跑著,所以我就想說暫時放著,等有空把資料弄出來再重建系統,然後十一月中去了一趟新加坡,這趟行程要邊顧小孩其實很累,然後就在回來當天晚上就收到 Linode 的緊急維護,已經把我的 Linode 主機重開了,網站當然也死了,真的是晴天霹靂,不過實在太累了我也只能先放著不管。

過了幾天終於比較有力氣來看看看問題,我當時的狀況是,無法使用 pacman,然後更進一步發現是 curl 就死掉,curl 死掉會造成很多東西一起掛掉,像是 git、wget 也都掛了,結果我能使用的工具和手段就變的很少,總之先來看看錯誤訊息吧:

/usr/lib/libcurl.so.4: undefined symbol: BrotliDecoderCreateInstance

由此可知基本上問題就是動態連結 Brotli 的 library 時出錯,我還記得我當初裝機器時,Archlinux 還沒有正式 Brotli 的套件,所以我還自己編譯了一版給 nginx 用,而我的 nginx 也是自己編譯的,沒想到不知不覺 Archlinux 已經有正式的 Brotli 套件,而且 curl 還相依於它。

接著我就開始各種嘗試,想辦法重新裝 Brotli 套件,curl 雖然不能動,但是我還可以用 scp 傳檔案上去,不過就算傳上去 pacman 也還是完全無法跑起來,即使我只是想要他安裝本地的檔案,而不是要連網路,然後我也去看了/use/local/裡面 brotli 套件的 header 檔案,查看內容,發現真的沒有BrotliDecoderCreateInstance,不過這個 symbol 在 Brotli 的 repo 內是有的,而且已經存在了有四年之久,所以顯然,我系統內安裝的版本很有問題,雖然確定問題在哪,但是還是一直沒有解決方法,重裝套件需要 pacman,但是 pacman 需要修好 brotli 才能動,陷入死結當中,更糟的是,我在網路上搜尋就是找不到有一樣問題的人。

然後我就開始研究 pacman 掛掉要怎麼辦,找了許久終於找到有一個 pacman-static 的工具,是預先編譯好,並且是靜態連結的 pacman 執行檔,抓下來後發現真的可以用,真的是感動的痛哭流涕,然後我立馬執行pacman -Syu,一切執行順利,感動QQ,然後我執行了curl想確認有沒有修好,結果我再次看到了那個一樣的,熟悉的錯誤訊息...

這時我百思不得其解,我用 pacman 看安裝的套件版本確實是新的,我去解開套件來看也是新的,但是我去系統的/usr/local/下看裡面的檔案卻是舊的,重新裝了很多次也都是一樣狀況,就這樣鬼打牆很久之後,我突然察覺,/usr/local/下的東西,其實是我們手動編譯安裝的,也是路徑中優先權較高的,然後我在前面有提過,我很久以前有手動編譯安裝 Brotli 套件,終於,一切真相大白,我手動裝的時間點是五年前,所以該版本沒有BrotliDecoderCreateInstance,然後 Archlinux 用的是四年前版本,所以系統中其他需要 Brotli 的東西都會因此而掛掉,解決方法就是把手動裝的全部砍光光就好了。

不過砍掉我手動編譯的 Brotli,也同時造成我的 nginx 再起不能,因為在設定檔內它是需要我手動編譯安裝的那那個套件,解決方法是很簡單,就把需要的 module 路徑改到 pacman 安裝的套件那邊,然後我的 nginx 就可以起來了,不過我的 blog 還是死的,非 blog 的部分倒是活著,我一開始想說是 php-fpm 的問題,看錯誤訊息發現有 permission 問題,就去改 socket file permisson 成 666,然後網站還是起不來,我研究了很久,想要看看 PHP 的錯誤訊息,但是一直看不到東西,也去看 nginx error log,journalctl 也是看沒錯誤,還以為 php-fpm 是死的,還用了

<? echo phpinfo(); ?>

然後開瀏覽器看到原始碼直接回回來,搞了一陣子想起要改用<?php,改下去結果又發現一切正常,最後才發現,問題是因為我在用 pacman 更新整個系統時,把 PHP 7 升級到 8,然後我的程式碼裡面有個地方寫死大版號不對的話會回錯誤訊息,但是我沒有把錯誤訊息寫到 log 中,結果就造成我一直找不到問題點。

PHP 的問題解決後,我的 blog 就回到線上了,不過其實,這時候我的 mariadb 還是死的,透過 journalctl 看 log

sudo journalctl -xeu mariadb.service

有一行寫著:

Plugin 'InnoDB' registration as a STORAGE ENGINE failed.

一開始想說是安裝失敗,後來往上找發現還有另外一行:

InnoDB: Upgrade after a crash is not supported. The redo log was created with MariaDB 10.4.8

意思就是如果你的 DB crash 後,沒有正常關閉的狀態下,去更新 mariadb,就會有這個錯誤,不過一開始我不以為意,因為我認為我只有 upgrade,但是不知道是何時 crash 過,後來回想,應該是 brotli 爛掉時,mariadb 就跟著起不來了,總之,這個問題的解決方法,就是退回舊的 10.4.8 然後重新啟動 DB,所以就研究了一下 Archlinux 怎樣安裝舊版的套件,基本上 pacman 是不能指定版本的,有兩個方法可以裝舊版,一個是透過系統內的 pacman cache,不過我之前在修理的時候已經清掉了,所以就只能從 Arch Linux Package Archive 那邊下載特定版本的 package tar 檔案,下來用pacman -U安裝,然後因為有相依性問題,所以要把幾個需要的套件都抓下來,一起安裝:

pacman -U mariadb-10.4.8-2-x86_64.pkg.tar.xz \
  mariadb-clients-10.4.8-2-x86_64.pkg.tar.xz \
  mariadb-libs-10.4.8-2-x86_64.pkg.tar.xz

反正如果啟動失敗,也會有訊息提示你要看 log,結果把 mariadb 三個都裝下去後還真的有問題,說找不到 openssl 1.1 的檔案,所以也去抓下來手動安裝:

pacman -S openssl-1.1

至此,總算是修好了,接下來就是有時間要把我的 blog 系統容器化吧,有太多不是很好安裝的東西了。

PS. 這篇發的出去表示真的修好了。