Product SiteDocumentation Site

5.2. パッケージのメタ情報

Debian パッケージはインストールされるファイルのアーカイブというだけではありません。Debian パッケージには他の Debian パッケージとの関係性 (依存関係、衝突、提案) を表す情報が含まれています。さらに Debian パッケージにはスクリプトも含まれています。このスクリプトはパッケージライフサイクルのある時点 (インストール、削除、アップグレード) にコマンドを実行するためのものです。これらのデータはパッケージ管理ツールによって使われますが、パッケージングされたソフトウェアの一部ではありません。しかし、これらのデータはパッケージの「メタ情報」(ソフトウェア以外の情報のデータ) と呼ばれて、パッケージに含まれています。

5.2.1. 説明、control ファイル

control ファイルは (RFC 2822 の定義する) 電子メールヘッダとよく似た構造を使っています。たとえば、aptcontrol ファイルは以下のような内容を持っています。
$ apt-cache show apt
Package: apt
Version: 1.4.8
Installed-Size: 3539
Maintainer: APT Development Team <deity@lists.debian.org>
Architecture: amd64
Replaces: apt-utils (<< 1.3~exp2~)
Depends: adduser, gpgv | gpgv2 | gpgv1, debian-archive-keyring, init-system-helpers (>= 1.18~), libapt-pkg5.0 (>= 1.3~rc2), libc6 (>= 2.15), libgcc1 (>= 1:3.0), libstdc++6 (>= 5.2)
Recommends: gnupg | gnupg2 | gnupg1
Suggests: apt-doc, aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), powermgmt-base, python-apt
Breaks: apt-utils (<< 1.3~exp2~)
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,
 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.4.8_amd64.deb
Size: 1231676
MD5sum: 4963240f23156b2dda3affc9c0d416a3
SHA256: bc319a3abaf98d76e7e13ac97ab0ee7c238a48e2d4ab85524be8b10cfd23d50d

5.2.1.1. 依存関係、Depends フィールド

依存関係はパッケージヘッダの Depends フィールドで定義されています。依存関係はパッケージを正しく動かすために必要な条件を定義しています。すなわち apt などのツールはこの情報を使ってインストールしたいパッケージの依存関係を満たすために必要なバージョンのライブラリをインストールします。それぞれの依存パッケージについて、要求を満たすパッケージのバージョン範囲を指定することが可能です。言い換えれば、バージョン「2.15」以上の libc6 パッケージが必要という条件を表現する (「libc6 (>= 2.15)」と表記する) ことが可能です。バージョン比較演算子は次の通りです。
  • << はより低いことを意味します。
  • <= は以下を意味します。
  • = は等しいことを意味します (「2.6.1」は「2.6.1-1」と等しくありません)。
  • >= は以上を意味します。
  • >> はより高いことを意味します。
満足すべき条件リストの中で使われるコンマは条件同士の区切りです。このコンマは論理「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 はメタパッケージが依存するすべてのプログラムを自動的にインストールします。gnomekde-fulllinux-image-amd64 パッケージはメタパッケージの例です。

5.2.1.2. 衝突、Conflicts フィールド

Conflicts フィールドでは、同時にインストールできないパッケージを指定します。このフィールドが使われるケースで最も多いのは、両方のパッケージが同名のファイルを含む場合、同種のサービスを同じ TCP ポートで提供する場合、互いの動作を妨げる場合です。
dpkg は、あるパッケージがインストール済みのパッケージと衝突を引き起こす場合、新しいパッケージがインストール済みのパッケージを「置換」するものでない限り、そのパッケージのインストールを拒否するでしょう (「置換」するものの場合、dpkg はインストール済みパッケージを新パッケージで置換します)。これに対して apt は常にあなたの指示に従います。つまり、もし apt に新しいパッケージをインストールするよう指示したのなら、apt は新しいパッケージをインストールする際に障害となるインストール済みパッケージを自動的にアンインストールします。

5.2.1.3. 不適合性、Breaks フィールド

Breaks フィールドは Conflicts フィールドとよく似た効果を持っていますが、特別な意味があります。すなわち、Breaks フィールドを持つパッケージは Breaks フィールドに指定された他のパッケージ (または他のパッケージの特定バージョン) を「破壊する」という意味があります。一般的に、このような 2 つのパッケージの不適合性は一時的なもので、Breaks フィールドでは不適合性がある特定のバージョンだけを指定します。
dpkg はインストール済みのパッケージを破壊するようなパッケージのインストールを拒否します。apt は破壊されるパッケージを新しいバージョンに更新することで (新しいバージョンではこの問題が修正され、両パッケージが適合すると期待されます) この問題の解決を試みます。
この手の状況は更新によって後方互換性がなくなる場合に起こりうるかもしれません。具体的に言えば、新しいバージョンが古いバージョンと同時に動かない場合、特別な設定をしないと別のプログラムがうまく動かない場合です。Breaks フィールドはユーザがこのような問題に遭遇することがないようにしています。

5.2.1.4. 提供されるアイテム、Provides フィールド

Provides フィールドはとても興味深い「仮想パッケージ」の構想を生み出しました。Provides フィールドは多くの役割を持っていますが、特に重要な 2 つを説明します。最初の役割は、Provides フィールドを持つパッケージは Provides フィールドに指定された一般的なサービスを意味する仮想パッケージに関連付けられている (サービスを「提供する」のは Provides フィールドを持つパッケージ自身です)、という意味を持たせる役割です。2 番目の役割は、Provides フィールドを持つパッケージは Provides フィールドに指定されたパッケージの機能を完全に置き換えており、Provides フィールドに指定されたパッケージの代替として Provides フィールドに指定されたパッケージに依存する他のパッケージの依存関係を満足できる、という意味を持たせる役割です。そのため、あるパッケージの機能を代替する別パッケージを必ずしも同じパッケージ名を使わずに作ることが可能です。
5.2.1.4.1. 「サービス」の提供
最初の場合について、例を挙げて詳細に議論しましょう。すなわち、すべてのメールサーバ、たとえば postfixsendmail などは mail-transport-agent 仮想パッケージ「提供」しています。このため、動作にメールサービスを必要とするパッケージ (たとえば smartlistsympa などのメーリングリストマネージャ) は、おそらくメールサービスを提供するであろうパッケージをたくさん依存関係に宣言する (たとえば、postfix | sendmail | exim4 | …のように宣言する) のではなく、たった 1 つ mail-transport-agent を宣言するだけで十分です。さらに、1 台のマシンに 2 つのメールサーバをインストールすることは無駄なため、メールサーバの機能を提供するパッケージは mail-transport-agent 仮想パッケージとの衝突を宣言します。例外的にあるパッケージとそれ自身との衝突はシステムによって無視されます。この手法により、2 つのメールサーバを同時にインストールできなくなります。
5.2.1.4.2. 他のパッケージとの互換性
パッケージの内容が巨大なパッケージに統合された場合に、Provides フィールドはさらに興味深い役割を果たします。たとえば、libdigest-md5-perl Perl モジュールは Perl 5.6 では任意選択モジュールでしたが、Perl 5.8 (および Stretch に含まれる 5.24 などのその後のバージョン) では標準モジュールに組み込まれました。このため、perl パッケージはバージョン 5.8 から Provides: libdigest-md5-perl を宣言しています。そうすれば、ユーザが Perl 5.8 (とそれより新しいバージョン) を持っている場合、libdigest-md5-perl に依存するパッケージの依存関係を満足させることができるからです。そして最終的に実体を持つ libdigest-md5-perl パッケージは削除されました。なぜなら、古い Perl バージョンが削除されたことで実体を持つ libdigest-md5-perl パッケージはもはや存在意義がなくなったからです。
依存関係を壊さないための Provides フィールドの使い方

図 5.1 依存関係を壊さないための Provides フィールドの使い方

この機能はとても役立ちます。なぜなら、開発方向性の変化を予測することは絶対に不可能ですし、パッケージ名を変更したり他の時代遅れのソフトウェアを自動に置き換えたりすることを可能な状態にしておくことが必要だからです。
5.2.1.4.3. 過去に設けられていた制限
かつて仮想パッケージにはいくつかの制限がありました。最も重要な制限はバージョン番号がなかったことでした。先に挙げた例に戻ると、Perl 5.10 が存在する場合、Depends: libdigest-md5-perl (>= 1.6) という依存関係は満足されています (正しく言えば、十中八九は満足されています)。しかしながら、パッケージシステムはこの依存関係が満足されていることに気が付きませんでした。そして、パッケージシステムは指定されたバージョンが一致しないと仮定して最もリスクの低いオプションを選んでいました。
この制限は dpkg 1.17.11 で撤廃され、Stretch ではもはや関係のない話です。パッケージは自分自身が提供する仮想パッケージにバージョン番号を付けることが可能です。これを行うには Provides: libdigest-md5-perl (= 1.8) などのようにします。

5.2.1.5. ファイルの置き換え、Replaces フィールド

Replaces フィールドは、Replaces フィールドを持つパッケージが Replaces フィールドに指定された他のパッケージからも提供されるファイルを含んでおり、合法的に Replaces フィールドに指定されたパッケージから提供されたファイルを置き換える権利を持っていることを示すためのものです。Replaces フィールドがなければ、dpkg は別パッケージから提供されたファイルをインストール中のパッケージに含まれるファイルで置き換えることはできません。すなわちこれは他のパッケージのファイルは上書きできないことを意味しています (技術的に言えば、--force-overwrite オプションを付けることで強制的に上書き可能ですが、これは一般に認められていません)。このような dpkg の挙動により潜在的な問題を識別できるようになりますし、メンテナはこのフィールドを追加する前に問題の原因を追及できるようになります。
Replaces フィールドはパッケージ名が変更された時やパッケージが別のパッケージに統合された時に使われます。この状況はメンテナが同じソースパッケージから複数のバイナリパッケージを作成し、各バイナリパッケージから異なるファイルを配布するように方針を決めた場合に発生します。つまり、古いパッケージに含まれていたファイルがソースパッケージは同じでもバイナリパッケージの名前が異なる新しいパッケージに含まれるようになった場合に発生します。
インストール済みパッケージのすべてのファイルが置き換えられたら、このパッケージは削除されたとみなされます。最後に、Replaces フィールドは衝突がある場合に dpkg に置き換えられたパッケージを削除させる際に使われます。

5.2.2. 設定スクリプト

それぞれの Debian パッケージには control ファイルだけでなく control.tar.gz アーカイブが含まれており、control.tar.gz には dpkg がパッケージ処理の各段階で呼び出す多数のスクリプトが含まれているかもしれません。Debian ポリシーでは、呼び出されるスクリプトとスクリプトが受け取る引数を明記することで、スクリプトの使われ方が詳しく説明されています。スクリプトが呼び出される順番はわかりにくいかもしれません。なぜなら、スクリプトのうち 1 つでも失敗したら、dpkg はインストールを中止するか (可能ならば) 進行中の削除を中止することでシステムを整合性のある状態に戻そうとするからです。
一般的に言って、preinst スクリプトはパッケージのインストール前に実行され、postinst はインストール後に実行されます。同様に、prerm はパッケージの削除前に実行され、postrm は削除後に実行されます。パッケージの更新とは、パッケージの古いバージョンを削除して新しいバージョンをインストールすることと等価です。ここで起こりうるすべてのシナリオを詳細に説明することは不可能なので、最も一般的なケースを 2 種類だけ挙げます。具体的に言えば、インストール/更新と削除について説明します。

5.2.2.1. パッケージのインストールとアップグレード

以下にパッケージのインストール中 (または更新中) に何が起きるかを説明します。
  1. 更新する場合、dpkgold-prerm upgrade new-version を呼び出します。
  2. 更新する場合、引き続き dpkgnew-preinst upgrade old-version を実行します。これに対して、初めてインストールする場合、new-preinst install を実行します。過去にもしパッケージがインストールされてさらに削除されていた場合 (完全削除されていない場合、古い設定ファイルがまだ残っている場合)、最後の引数に古いバージョンを追加します。
  3. そして新しいパッケージのファイルが展開されます。あるファイルが既に存在した場合、そのファイルは置換されますが、一時的にバックアップコピーが作られます。
  4. 更新する場合、dpkgold-postrm upgrade new-version を実行します。
  5. dpkg はすべての内部データ (ファイルリスト、設定スクリプトなど) を更新し、置換されたファイルのバックアップを削除します。これ以降はもう後戻りできません。つまり、前の状態に戻るために必要な情報がすべて失われたため、dpkg は状態を復元できません。
  6. dpkg は設定ファイルを更新します。自動的にこの作業を完了できない場合にはユーザにどうするか尋ねます。この作業の詳細は第 5.2.3 節「チェックサム、設定ファイルのリスト」をご覧ください。
  7. 最後に、dpkgnew-postinst configure last-version-configured を実行して、パッケージを設定します。

5.2.2.2. パッケージの削除

以下にパッケージの削除中に何が起きるかを説明します。
  1. dpkgprerm remove を呼び出します。
  2. dpkg は設定ファイルと設定スクリプトを除くすべてのパッケージのファイルを削除します。
  3. dpkgpostrm remove を実行します。すべての設定スクリプトは postrm を除いて削除されます。ユーザが「purge」オプションを指定しない限り、作業はここで終了します。
  4. パッケージを完全削除する (dpkg --purge または dpkg -P が実行された) 場合、設定ファイルおよびそのコピー (*.dpkg-tmp*.dpkg-old*.dpkg-new) と一時ファイルも削除されます。さらに dpkgpostrm purge を実行します。
上で詳細を述べた 4 つのスクリプトの実行を補助するのが config スクリプトです。config スクリプトはパッケージから提供され、debconf を用いて設定に必要な情報をユーザに入力させるために使われます。ユーザからの情報は debconf データベースに保存され、後から利用されます。このスクリプトは通常 apt によって各パッケージインストールの前に実行され、処理が始まるとすべての質問をまとめてユーザに尋ねます。インストール前後に実行されるスクリプトは、ユーザの希望を反映させるために、debconf データベースに保存された情報を利用します。

5.2.3. チェックサム、設定ファイルのリスト

前の節で既に説明したメンテナスクリプトと管理情報に加えて、Debian パッケージの control.tar.gz アーカイブは興味深いファイルを含んでいる場合があります。1 つ目は md5sums です。md5sums にはパッケージに含まれる全ファイルの MD5 チェックサムが列挙されています。md5sums のおかげで dpkg --verify はインストール以降ファイルが変更されたか否かを判断できるようになります (詳しくは第 14.3.3.1 節「dpkg --verify を使ったパッケージ監視」を参照してください)。パッケージが md5sums を提供しない場合、dpkg がインストール時に動的に md5sums を生成します (そして他の管理情報ファイルと同様に dpkg データベースに内容を保存します)。
conffiles では、設定ファイルとして取り扱われるべきパッケージファイルが指定されています。管理者は設定ファイルを変更でき、dpkg はパッケージの更新中に設定ファイルの変更を保存しようとします。
実際のところ、システムに現存する設定ファイルをパッケージから提供された設定ファイルで更新する際に dpkg はできるだけ賢明に振る舞います。以下に dpkg のデフォルトの設定ファイル更新処理規則を述べます。パッケージの更新前後でパッケージから提供される標準設定ファイルの内容が同じ場合、dpkg は何もしません。しかしながら、パッケージの更新前後でパッケージから提供される標準設定ファイルの内容が違う場合、dpkg はシステムに現存する設定ファイルを更新しようとします。ここでさらに 2 つの場合が考えられます。システムに現存する設定ファイルと古いバージョンのパッケージから提供される標準設定ファイルの内容が同じ場合、dpkg は自動的に新しいパッケージから提供される標準設定ファイルをパッケージ更新完了後の設定ファイルとして採用します。一方で、システムに現存する設定ファイルと古いバージョンのパッケージから提供される標準設定ファイルの内容が違う場合、dpkg は管理者に対してシステムに現存する設定ファイルまたは新しいバージョンのパッケージから提供される標準設定ファイルのどちらを更新後の設定ファイルとして採用するかを尋ねます。この判断を手助けするために、dpkg は「diff」を使って 2 つの設定ファイルの内容の違いを表示します。管理者が現存する設定ファイルを選んだ場合、新しいバージョンのパッケージから提供される標準設定ファイルは同じ場所にファイル名の末尾に .dpkg-dist を追加して保存されます。管理者が新しいバージョンのパッケージから提供される標準設定ファイルを選んだ場合、現存する設定ファイルは同じ場所にファイル名の末尾に .dpkg-old を追加して保存されます。この段階では、一時的に dpkg の処理を中断してファイルを編集したり、もう一度バージョン間の違いを表示したり (先と同様に diff コマンドを実行する) することも可能です。