前回紹介したように,昨年末に64ビット版(x86_64)のPlamo64-1.0を公開した後,年明けからは32ビット版(x86)のパッケージを追従させる作業にかかっています。
前回の最後では,ここ数ヶ月のうちにx86用のパッケージを揃えてしまいたいと書きましたが,実際に取りかかってみると,バージョンが古くなっていてx86用のみならずx86_64用もバージョンアップした方がいいソフトウェアが多数出てきました。
ざっと見た感じでは,Plamo64-1.0を公開してから今までに,x86用のパッケージは300弱が更新されているのに対し,x86_64用のパッケージもその半数の150弱が更新されているようです。Plamo64-1.0の総パッケージ数は1100ほどなので,このペースで行くとx86用のパッケージが揃うのは今年の後半くらいになりそうで,たぶん,そのころにはx86_64用も半分くらいのパッケージを更新している計算になります。
パッケージの更新作業の際には,アーキテクチャごとのバージョンをチェックする作業が頻発するので,FTPサーバにあるパッケージのバージョンを一覧表示するページを作ってみました。
このページでは,FTPサーバのPlamo-5.0/{x86,x86_64}/ 以下のパッケージを調べて,カテゴリごとに両アーキテクチャでのパッケージの有無とバージョン,アーキテクチャ間でバージョンが異なる場合は古そうな方に色を付けて表示するようにしてみました。
バージョンの新旧比較はPHPの比較関数を使って小さい方に色を付けているだけなので,新しいバージョンの側に色が付いている例もいくつかあります。
最近はこのページを使ってどのソフトウェアから更新していくかを考えていますが,このページでわかるパッケージの有無やバージョンといった情報だけでは判断できない問題もあります。
パッケージの依存性問題
その問題とはパッケージの依存関係で,たとえば,Aというソフトウェアが提供するライブラリをBというソフトウェアが使っていて,Bの提供する機能をCが使っているような場合,手を付けやすそうだからと思ってCを先にバージョンアップしてみても,将来Aのバージョンを上げた際にBのバージョンも上げる必要が生じ,芋づる式にCもまた更新しなければならなくなったりすることがあります。
この問題は共有ライブラリに関して発生しがちです。特に共有ライブラリのバージョン番号が変わる際には,その共有ライブラリを参照しているバイナリファイルを全てビルドし直す必要があるので気を使います。
影響が大きすぎる場合には,後方互換性のための経過措置として古いバージョンのライブラリをパッケージに含めておくこともあります。これら共有ライブラリのバージョン問題については本連載の14回目に紹介しているので,興味ある人はご覧ください。
rpmなどの洗練されたパッケージ管理システムでは,そのパッケージに含まれるバイナリファイルを動かすために必要なライブラリをバージョン番号と共にパッケージに記録しておくことができますが,Plamo Linuxで採用しているシンプルなtgz,txz形式のパッケージでは,パッケージには依存性情報を記録できないため,バイナリファイルの依存関係は別途チェックしてやる必要があります。
バイナリファイルが必要とするライブラリはlddコマンドで調べることができるので,手元はこんな形のシェルスクリプトを使って,指定した共有ライブラリを利用しているバイナリファイルを調べていました。
リスト1 ライブラリの利用状況を調べるスクリプト
#!/bin/sh
dir=$1
lib=$2
for i in `find $dir `; do
elf_chk=`file $i | grep ELF`
if [ "$elf_chk.x" != ".x" ]; then
lib_chk=`(ldd $i 2>/dev/null) | grep $lib `
if [ "$lib_chk.x" != ".x" ]; then
echo "$i: $lib_chk"
fi
fi
done
このシェルスクリプトをchklibs.shとして実行パーミッションを付けておくと,
$ ./chklibs.sh /usr/bin libcrypto
のように引数を与えれば,libcryptoライブラリを参照している,/usr/bin/以下のバイナリファイルを表示します。
$ ./libchk.sh /usr/bin libcrypto /usr/bin/ssh: libcrypto.so.1.0.0 => /usr/lib64/libcrypto.so.1.0.0 (0x00007f9f8ac34000) /usr/bin/ssh-add: libcrypto.so.1.0.0 => /usr/lib64/libcrypto.so.1.0.0 (0x00007fd604bef000) /usr/bin/ssh-agent: libcrypto.so.1.0.0 => /usr/lib64/libcrypto.so.1.0.0 (0x00007f7944552000) /usr/bin/ssh-keygen: libcrypto.so.1.0.0 => /usr/lib64/libcrypto.so.1.0.0 (0x00007ffaf104d000) /usr/bin/ssh-keyscan: libcrypto.so.1.0.0 => /usr/lib64/libcrypto.so.1.0.0 (0x00007f300c58b000) /usr/bin/openssl: libcrypto.so.1.0.0 => /usr/lib64/libcrypto.so.1.0.0 (0x00007f940a486000) /usr/bin/dig: libcrypto.so.1.0.0 => /usr/lib64/libcrypto.so.1.0.0 (0x00007feaa79ad000) /usr/bin/host: libcrypto.so.1.0.0 => /usr/lib64/libcrypto.so.1.0.0 (0x00007f334f124000) ....
従来,広く使われている共有ライブラリを更新する際などに,このスクリプトを使って更新の影響がどの程度まで及ぶかを調べていました。しかし,このスクリプトは処理にかなり時間がかかります。そこで,もう少し効率よくできないかと考えてみました。
依存関係データベースの試み
前述のchklibs.shスクリプトでは,指定したディレクトリ以下を再帰的に調べていってlddコマンドを実行し,ライブラリ参照の有無をチェックしています。
この作業には,指定したディレクトリ以下の全てのバイナリファイルをチェックする必要があるため,かなり時間がかかります。そんな時間のかかる処理を,調べたいライブラリごとに繰り返すのは無駄と言えそうです。
そこで,インストール済みのバイナリファイル全てについて,それぞれが必要とするライブラリの情報をあらかじめデータベースに登録しておき,検索時にはそれぞれのバイナリファイルを調べるのではなく,データベースから必要な情報を抽出できないかと考えました。
lddの出力は,下記のように一つのバイナリファイルに対して,そのバイナリファイルが参照している全ての共有ライブラリを表示します。
$ ldd /usr/bin/sed
linux-vdso.so.1 => (0x00007fff3a35b000)
libacl.so.1 => /usr/lib64/libacl.so.1 (0x00007f526a0c6000)
libc.so.6 => /lib64/libc.so.6 (0x00007f5269d5c000)
libattr.so.1 => /usr/lib64/libattr.so.1 (0x00007f5269b58000)
/lib64/ld-linux-x86-64.so.2 (0x00007f526a2cd000)
たとえばこの結果を「バイナリファイルと必要な共有ライブラリの組」として,/usr/bin/sed & (linux-vdso.so.1, libacl.so.1, libattr.so.1, ld-linux-x86-64-so.2) のような形に整理してやれば,バイナリファイルをキーに,必要なライブラリのリストをバリューとするような連想配列を作ることができます。PerlやPythonといったスクリプト言語ならこの手の連想配列の操作は得意でしょう。
しかし,今回調べたいのは「あるバイナリファイルが使っているライブラリ」よりも,「あるライブラリを参照しているバイナリファイル」という方向なので,連想配列のバリューのリストを全て調べて該当するキーを抽出するのはちょっと大変そうです。
加えて,上記/usr/bin/sed の例では参照しているライブラリは5つ程度ですが,KDEのソフトウェアのようにGUIを多用しているバイナリファイルでは,参照しているライブラリ数が100近くに達することも稀ではありません。また,調べるべきバイナリファイルの総数もシステム全体では数千の規模になるので,扱うべきデータ全体は数十万件のオーダになりそうです。
そのような規模のデータを効率よく扱うには,フラットなテキストファイルに記録するのではなく,専用のデータベースソフトを使った方がよさそうです。また,上述したように,ライブラリからバイナリファイルを調べる,という検索方向を考えると,連想配列的な形で記録するBerkeley DBやgdbmよりも,表形式で記録するリレーショナルデータベース(RDB)の方がよさそうです。
Linuxで使えるRDBソフトウェアではPostgreSQLやMySQLが有名ですが,今回は勉強を兼ねてSQLiteを試してみることにしました。

