Debian パッケージはインストールされるファイルのアーカイブというだけではありません。メタ情報はパッケージの一部で、他の Debian パッケージとの関係性 (依存関係、衝突、提案) を記述しています。また、メタ情報にはスクリプトも含まれています。スクリプトはパッケージライフサイクルのある時点 (インストール、削除、アップグレード) にコマンドを実行するためのものです。これらのデータはパッケージ管理ツールによって使われますが、パッケージ化されたソフトウェアの一部ではありません。しかし、これらのデータはパッケージの「メタ情報」(他の情報のデータ) と呼ばれて、パッケージに含まれています。
このファイルは (RFC 2822 の定義する) 電子メールヘッダとよく似た構造を使っています。たとえば、apt の control
ファイルは以下のような内容を持っています。
$
apt-cache show apt
Package: apt
Version: 1.0.9.6
Installed-Size: 3788
Maintainer: APT Development Team <deity@lists.debian.org>
Architecture: amd64
Replaces: manpages-it (<< 2.80-4~), manpages-pl (<< 20060617-3~), openjdk-6-jdk (<< 6b24-1.11-0ubuntu1~), sun-java5-jdk (>> 0), sun-java6-jdk (>> 0)
Depends: libapt-pkg4.12 (>= 1.0.9.6), libc6 (>= 2.15), libgcc1 (>= 1:4.1.1), libstdc++6 (>= 4.9), debian-archive-keyring, gnupg
Suggests: aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), apt-doc, python-apt
Conflicts: python-apt (<< 0.7.93.2~)
Breaks: manpages-it (<< 2.80-4~), manpages-pl (<< 20060617-3~), openjdk-6-jdk (<< 6b24-1.11-0ubuntu1~), sun-java5-jdk (>> 0), sun-java6-jdk (>> 0)
Description-ja: コマンドラインパッケージマネージャ
本パッケージは、パッケージを検索、管理したりパッケージの情報を照会できるコ
マンドラインツールを提供します。libapt-pkg ライブラリの全機能に低レベルアク
セスできます。
.
次のツールが含まれます。
* apt-get: 信頼されたソースからパッケージやパッケージの情報を取得したり、
パッケージとその依存関係をまとめてインストール、アップグレード、および削
除できます
* apt-cache: インストールしたパッケージやインストール可能なパッケージに関
して利用できる情報を検索できます
* apt-cdrom: リムーバブルメディアをパッケージの取得ソースとして利用できます
* apt-config: 構成設定へのインターフェース
* apt-key: 信頼できる鍵を管理するインターフェース
Description-md5: 9fb97a88cb7383934ef963352b53b4a7
Tag: admin::package-management, devel::lang:ruby, hardware::storage,
hardware::storage:cd, implemented-in::c++, implemented-in::perl,
implemented-in::ruby, interface::commandline, network::client,
protocol::ftp, protocol::http, protocol::ipv6, role::program,
role::shared-lib, scope::application, scope::utility, sound::player,
suite::debian, use::downloading, use::organizing, use::searching,
works-with::audio, works-with::software:package, works-with::text
Section: admin
Priority: important
Filename: pool/main/a/apt/apt_1.0.9.6_amd64.deb
Size: 1107560
MD5sum: a325ccb14e69fef2c50da54e035a4df4
SHA1: 635d09fcb600ec12810e3136d51e696bcfa636a6
SHA256: 371a559ce741394b59dbc6460470a9399be5245356a9183bbeea0f89ecaabb03
5.2.1.1. 依存関係、Depends
フィールド
依存関係はパッケージヘッダの Depends
フィールドで定義されています。依存関係はパッケージを正しく動かすために必要な条件を定義しています — apt
などのツールは、この情報を使って、インストールしたいパッケージの依存関係を満たすために必要なバージョンのライブラリをインストールします。それぞれの依存パッケージについて、要求を満たすパッケージのバージョン範囲を指定することが可能です。言い換えれば、バージョン「2.15」以上の libc6 パッケージが必要という条件を表現する (「libc6 (>= 2.15)
」と表記する) ことが可能です。バージョン比較演算子は次の通りです。
満足すべき条件リストの中で使われるコンマは条件同士の区切りです。このコンマは論理「and」に解釈されます。条件リストの中で、垂直棒 (「|」) は論理「or」に解釈されます (これは「包含的論理和」で、「排他的論理和」ではありません)。or は「and」より大きな優先順位を持っており、必要に応じて何度でも使えます。このため、「(A or B) and C」は
A | B, C
のように表記できます。これに対して、「A or (B and C)」は「(A or B) and (A or C)」のように表記してください。なぜなら、
Depends
フィールドでは括弧を使って論理演算子「or」と「and」の優先度の順位を変えることができないからです。このため、これは
A | B, A | C
のように表記できます。
依存関係システムはプログラムの動作を保証する良いメカニズムですが、「メタパッケージ」を使う手もあります。メタパッケージは依存関係を表記するだけの空のパッケージです。メタパッケージはメンテナが事前に選んだ一連のプログラムグループのインストールを楽にします。すなわち apt install meta-package
はメタパッケージが依存するすべてのプログラムを自動的にインストールします。gnome、kde-full、linux-image-amd64 パッケージはメタパッケージの例です。
5.2.1.2. 衝突、Conflicts
フィールド
Conflicts
フィールドでは、同時にインストールできないパッケージを指定します。このフィールドが使われるケースで最も多いのは、両方のパッケージが同名のファイルを含む場合、同種のサービスを同じ TCP ポートで提供する場合、互いの動作を妨げる場合です。
dpkg
は、あるパッケージがインストール済みのパッケージと衝突を引き起こす場合、新しいパッケージがインストール済みのパッケージを「置換」する場合 (このような場合、dpkg
が古いパッケージを新パッケージで置換します) を除き、そのパッケージのインストールを拒否するでしょう。apt
は常に、あなたの指示に従います。たとえば、もしあなたが新しいパッケージをインストールしたいのなら、問題を引き起こすインストール済みパッケージを自動的にアンインストールします。
5.2.1.3. 不適合性、Breaks
フィールド
Breaks
フィールドは Conflicts
フィールドとよく似た効果を持っていますが、特別な意味があります。このフィールドはあるパッケージをインストールすることで他のパッケージ (または他のパッケージの特定バージョン) を「破壊する」という意味があります。一般的に、このような 2 つのパッケージの不適合性は一時的なもので、Breaks
フィールドでは不適合性がある特定のバージョンだけを指定します。
dpkg
はインストール済みのパッケージを破壊するようなパッケージのインストールを拒否します、apt
は破壊されるパッケージを新しいバージョンに更新することで (新しいバージョンではこの問題が修正され、両パッケージが適合すると期待されます)、この問題の解決を試みます。
この手の状況は更新によって後方互換性がなくなる場合に起こりうるかもしれません。具体的に言えば、新しいバージョンが古いバージョンと同時に動かない場合、特別な設定をしないと別のプログラムがうまく動かない場合です。Breaks
フィールドはユーザがこのような問題に遭遇することがないようにしています。
5.2.1.4. 提供されるアイテム、Provides
フィールド
このフィールドによって、とても興味深い「仮想パッケージ」の構想が生まれました。このフィールドは多くの役割を持っていますが、特に重要な 2 つを説明します。最初の役割は、仮想パッケージを使って一般的なサービスとパッケージを関連付ける (サービスを「提供する」のはパッケージです) ことを可能にする役割です。2 番目の役割は、このパッケージを他のパッケージを完全に置き換えること、このパッケージの依存関係を他のパッケージが満足するであろう依存関係を使って満足させることを可能にする役割です。このため、同じパッケージ名を使わずに、代替パッケージを作成することが可能です。
最初の場合について、例を挙げて詳細に議論しましょう。すなわち、すべてのメールサーバ、たとえば postfix や sendmail などは mail-transport-agent 仮想パッケージ「提供」するとされています。このため、動作にメールサービスを必要なパッケージ (たとえば smartlist や sympa などのメーリングリストマネージャ) は、おそらくメールサービスを提供するであろうパッケージ (たとえば、postfix | sendmail | exim4 | …
の ように) をたくさん依存関係に宣言するのではなく、たった 1 つ mail-transport-agent を宣言するだけで十分です。さらに、1 台のマシンに 2 つのメールサーバをインストールすることは無駄なため、メールサーバの機能を提供するパッケージは mail-transport-agent 仮想パッケージとの衝突を宣言します。あるパッケージとそれ自身との衝突はシステムによって無視されます。この手法により、2 つのメールサーバを同時にインストールできなくなります。
パッケージの内容が巨大なパッケージに統合された場合に、Provides
フィールドはさらに興味深い役割を果たします。たとえば、libdigest-md5-perl Perl モジュールは Perl 5.6 では任意選択モジュールでしたが、Perl 5.8 (と Jessie に含まれる 5.20 などのその後のバージョン) では標準モジュールに組み込まれました。このため、perl パッケージはバージョン 5.8 から Provides: libdigest-md5-perl
を宣言しています。そうすれば、ユーザが Perl 5.8 (とそれより新しいバージョン) を持っている場合、このパッケージの依存関係が満足されるからです。libdigest-md5-perl パッケージ自体は、いずれ削除されます。なぜなら、古い Perl バージョンが削除されたらこのパッケージはもはや存在意義がないからです。
この機能はとても便利です、なぜなら、開発方向性の変化を予測することは絶対に不可能ですし、名称を変更できたり、他の時代遅れのソフトウェアを自動に置き換えできるようにすることが必要だからです。
かつて仮想パッケージにはいくつかの制限がありました。最も重要な制限はバージョン番号がなかったことでした。先に挙げた例に戻ると、Perl 5.10 が存在する場合、Depends: libdigest-md5-perl (>= 1.6)
という依存関係は満足されています (正しく言えば、十中八九は満足されています) が、パッケージシステムはこの依存関係が満足されていることに気が付きませんでした。パッケージシステムは依存関係が満足されていることに気がつきませんでしたが、指定されたバージョンが一致しないと仮定して、最もリスクの低いオプションを選んでいました。
この制限は dpkg 1.17.11 で撤廃され、Jessie ではもはや関係のない話です。パッケージは自分自身から提供される仮想パッケージにバージョン番号を付けることが可能です。これを行うには Provides: libdigest-md5-perl (= 1.8)
などのようにします。
5.2.1.5. ファイルの置き換え、Replaces
フィールド
Replaces
フィールドは、そのパッケージが他のパッケージにも含まれるファイルを含んでおり、合法的にそのファイルを置き換える権利を持っていることを示すためのものです。この仕様がなかったとしても、dpkg
はそのようなファイルを置き換えることはできません。これは他のパッケージのファイルは上書きできないことを意味しています (技術的に言えば、--force-overwrite
オプションを付けることで強制的に上書き可能ですが、これは一般に認められていません)。このことにより潜在的な問題を識別できるようになりますし、メンテナはこのフィールドを追加する前に問題の原因を追及できるようになります。
このフィールドは、パッケージ名が変更された時や、パッケージが別のパッケージに統合された時に使われます。これはまた、メンテナが同じソースパッケージから作成されたバイナリパッケージ間で異なるファイルを配布したい場合に使われます。つまり、置き換えられたファイルはもはや、古いパッケージではなく新しいパッケージに所属します。
インストール済みパッケージのすべてのファイルが置き換えられたら、このパッケージは削除されたとみなされます。最後に、このフィールドは衝突がある場合に dpkg
が置き換えられたパッケージを削除する際に使われます。
それぞれの Debian パッケージには、control
ファイルだけでなく control.tar.gz
アーカイブが含まれており、このアーカイブには、dpkg
がパッケージ処理の各段階で呼び出す多数のスクリプトが含まれているかもしれません。Debian ポリシーでは、呼び出されるスクリプトとスクリプトが受け取る引数を明記することで、スクリプトの使われ方が詳しく説明されています。スクリプトが呼び出される順番はわかりにくいかもしれません。なぜなら、スクリプトのうち 1 つでも失敗したら、dpkg
は進行中のインストールを中止するか (可能ならば) 削除することでシステムを一貫性のある状態に戻そうとするからです。
一般的に言って、preinst
スクリプトはパッケージのインストール前に実行され、postinst
はインストール後に実行されます。同様に、prerm
はパッケージの削除前に実行され、postrm
は削除後に実行されます。パッケージの更新とは、パッケージの古いバージョンを削除して新しいバージョンをインストールすることと等価です。ここですべての可能なシナリオを詳細に説明することは不可能なので、最も一般的なケースを 2 種類だけ挙げます。具体的に言えば、インストール/更新と削除について説明します。
5.2.2.1. パッケージのインストールとアップグレード
ここではパッケージのインストール中 (または更新中) に何が起きるかを説明しています。
更新の際に、dpkg
は old-prerm upgrade new-version
を呼び出します。
更新する場合、dpkg
は new-preinst upgrade old-version
を実行します。これに対して、初めてインストールする場合、new-preinst install
を実行します。過去にもしパッケージがインストールされてさらに削除されていた場合 (完全消去されていない場合、古い設定ファイルがまだ残っている場合)、最後の引数に古いバージョンを追加します。
そして新しいパッケージのファイルが解凍されます。あるファイルが既に存在した場合、そのファイルは置換されますが、一時的にバックアップコピーが作られます。
更新の場合、dpkg
は old-postrm upgrade new-version
を実行します。
dpkg
はすべての内部データを (ファイルリスト、設定スクリプトなど) 更新し、置換されたファイルのバックアップを削除します。これ以降はもう後戻りできません。つまり、前の状態に戻るために必要な情報がすべて失われたため、dpkg
は状態を復元できません。
最後に、dpkg
は new-postinst configure last-version-configured
を実行して、パッケージを設定します。
ここではパッケージの削除中に何が起きるかを説明しています。
dpkg
は prerm remove
を呼び出します。
dpkg
は設定ファイルと設定スクリプトを除くすべてのパッケージのファイルを削除します。
dpkg
は postrm remove
を実行します。すべての設定スクリプトは postrm
を除いて削除されます。ユーザが「purge」オプションを指定しない限り、作業はここで終了します。
パッケージを完全消去する (dpkg --purge
または dpkg -P
を実行した) 場合、設定ファイルおよびそのコピー (*.dpkg-tmp
、*.dpkg-old
、*.dpkg-new
) と一時ファイルも削除されます。さらに dpkg
は postrm purge
を実行します。
上で詳細を述べた 4 つのスクリプトの実行を補助するのが config
スクリプトです。パッケージが提供するこのスクリプトは debconf
を用いて設定に必要な情報をユーザに入力させるためのものです。ユーザからの情報は debconf
データベースに保存され、後から利用されます。このスクリプトは通常 apt
によって各パッケージインストールの前に実行され、処理が始まるとすべての質問をまとめてユーザに尋ねます。インストール前後に実行されるスクリプトは、ユーザの希望を反映させるために、これらの情報を利用します。
前の節で既に説明したメンテナスクリプトと管理情報に加えて、Debian パッケージの
control.tar.gz
アーカイブに興味深いファイルが含まれている場合があります。1 つ目は
md5sums
で、このファイルにはパッケージに含まれる全ファイルの MD5 チェックサムが列挙されています。これのおかげで、
dpkg --verify
(詳しくは
第 14.3.3.1 節「dpkg --verify
を使ったパッケージ監視」を参照) はインストール以降ファイルが変更されたか否かを判断できるようになります。このファイルが存在しなければ、
dpkg
がインストール時に動的にこのファイルを生成します (そして他の管理情報ファイルと同様に dpkg データベースに内容を保存します)。
conffiles
では、設定ファイルとして取り扱われるべきパッケージファイルが指定されています。管理者は設定ファイルを変更でき、dpkg
はパッケージの更新中に設定ファイルの変更を保存しようとします。
実際のところこの状況では、dpkg
はできるだけ賢明に振る舞います。すなわち、パッケージに含まれる標準的な設定ファイルが 2 つのバージョン間で変更されていなければ、何もしません。しかしながら、標準的な設定ファイルが 2 つのバージョン間で変更されていたら、ファイルを更新しようとします。ここで 2 つの場合が考えられます。つまり、管理者が設定ファイルに変更を加えていなければ、dpkg
は自動的にパッケージに含まれる新しいバージョンをインストールします。一方で、管理者が設定ファイルに変更を加えていれば、dpkg
は管理者にどちらのバージョン (変更された古いバージョン、またはパッケージに含まれる新しいバージョン) を使うかを尋ねます。どちらのバージョンを使うかの判断を手助けするために、dpkg
は「diff
」を使って 2 つのバージョンの違いを表示します。ユーザが古いバージョンを選んだ場合、新しいバージョンは同じ場所にファイル名の末尾に .dpkg-dist
を追加して保存されます。ユーザが新しいバージョンを選んだ場合、古いバージョンはファイル名の末尾に .dpkg-old
を追加して保存されます。他の利用できる操作は、一時的に dpkg
の処理を中断してファイルを編集する、または改めてバージョン間の違いを表示する (先と同様に diff
コマンドを実行する) です。