[% title = "Debian ポリシーマニュアル - パッケージ管理スクリプトとインストールの手順" %]
[ previous ] [ Contents ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ A ] [ B ] [ C ] [ D ] [ E ] [ F ] [ G ] [ next ]
パッケージをインストール、アップグレード、削除する際に、パッケージ管理システムが走らせるスクリプトをパッケージの一部として供給することが可能です。
これらのスクリプトは
preinst
、postinst
、prerm
と
postrm
という制御情報ファイルです。
これらは適正な実行可能ファイルでなくてはなりません。 もし、これらがスクリプト
(スクリプトであることを推奨します) ならば、 通常行われているように
#! で始めなくてはなりません。
これらのスクリプトは、誰でも読むことと実行が可能でなければならず、
誰でも書き込み可能なパーミッションであってはいけません。
パッケージ管理システムはこれらのスクリプトからの終了ステータスを見ます。 パッケージ管理システムが手続きを止められるように、 エラーがあった場合にはスクリプトが 0 でないステータスで終了するようにしておくことが重要です。 シェルスクリプトでは ほとんど常に set -e を使う必要があるということを意味します (実際には、 通常シェルスクリプトを書く場合は一般に、このようにします)。 もちろん、全てがうまくいった場合に、0 ステータスで終了することも重要です。
さらに、postinst
中で debconf
を用いてユーザとの対話を行うパッケージでは、制御情報ファイル内に
config
スクリプトをインストールすべきです。 詳細は、メンテナスクリプト中のプロンプト使用について,
Section 3.9.1 を参照ください。
パッケージがアップグレードされる時には、アップグレード手続きの間に古いパッケージと新しいパッケージのスクリプトが、組み合わせて呼び出されます。 もし、あなたのスクリプトがとても複雑になっていく場合には、このことに注意し、スクリプトの引数のチェックが必要になるでしょう。
大まかに言えば、preinst
は (ある特定のバージョンの)
パッケージが展開される前に、postinst
は展開された後に呼び出されます。prerm
は (あるバージョンの)
パッケージが 削除される前に、 postrm
は削除された後に呼び出されます。
管理スクリプトから呼ばれるプログラムは、通常そのスクリプトにおいてプログラムの前にパスをつけて呼び出すべきではありません。
インストールが始まる前に、パッケージ管理システムは
ldconfig
、start-stop-daemon
、 や
update-rc.d
などのプログラムが指定された PATH
環境変数から発見できるかどうかをチェックします。
ですから、これらのプログラムや、PATH
にあることを期待してもいいようなプログラムについては、絶対パス名をつけずに呼び出すべきです。
管理スクリプトは PATH をリセットすべきではありませんが、
PATH
の前か後に、パッケージに対して特別なディレクトリを付け加えるという方法を採るのはかまいません。
このような考慮は、実際には、全てのシェルスクリプトに対して当てはまるものです。
メンテナスクリプトが再入結果の同一性をもつようにすることはとても重要です。
エラー回復手続きをできるようにするため、スクリプトは同じ状況にあるときに、それを何度か起動しても無害でなければなりません。 もし、一回目の呼び出しが失敗した、または何らかの理由によって途中で中止した場合、 二回目の呼び出しでは一回目で実行し残したものを単に実行し、 もし何もかもうまくいったなら成功ステータスで終了するようにすべき [46] です。
メンテナスクリプトは制御端末がある状態で実行されているとは限らず、 ユーザとの対話ができることは保証されていません。 制御端末が提供されていない場合、非対話型で処理することができるようにしなければなりません。 Debian Configuration Management Specification に準拠したプログラムを使ってプロンプトを出しているメンテナスクリプト (メンテナスクリプト中のプロンプト使用について, Section 3.9.1 参照) は、非対話型の動作になった場合の扱いを、そのプログラムが行うと仮定して構いません。
優先順位の高い、妥当な標準回答の無いような対話を行いたい場合、 制御端末がない際に異常終了することは許されています。 但し、可能な限りそのようなことが起きないようにすべきです。 これは、自動インストールや、無人インストールの妨げになるからです。 大抵の場合は、このような挙動はユーザにそのパッケージのバグと見做されるでしょう。
各スクリプトは成功の場合には終了ステータスを 0 に、失敗の場合には 0 でない値にして帰ってください。これは、 パッケージ管理システムがこれらスクリプトの終了ステータスを監視しており、このデータに基づいて次に取るべき処理を決めているためです。
以下は、メンテナスクリプトのすべての呼ばれ方と、 スクリプトが呼ばれる際に依存して良い機能についてまとめたものです。 スクリプト名で、new- で始まるものは、インストール/更新/ダウングレード対象の新バージョンのパッケージから呼ばれるスクリプトです。 スクリプト名で、old- で始まるものは、更新/ダウングレードされる対象の旧バージョンのパッケージから呼ばれるスクリプトです。
preinst
スクリプトは以下のやり方で呼ばれる可能性があります。
問題のパッケージはまだ展開されていないため、preinst
スクリプトはパッケージに含まれるファイルに依存することはできません。
essential パッケージと、先行依存 (predependency)
(Pre-Depends)
を指定したパッケージが提供されていることは期待してもかまいません。
先行依存されたパッケージは少なくとも一回は設定されていますが、ただし
preinst
が呼ばれた時点では単に展開状態 (Unpacked) か、
設定途中状態 (Half-Configured) 状態である可能性があります。
この状況は、先行依存を指定したパッケージの旧版がきちんと設定されていて、その後削除されていなかった場合に起きます。
新パッケージの展開後に、アップグレードが postrm upgrade 処理の失敗のために失敗した場合に、エラー処理で呼ばれます。 展開されたファイルは一部が新しい版に置き換わっていたり、一部が削除されている可能性があるため、 パッケージに含まれるファイルに依存することはできません。 パッケージの依存関係は満たされていないかもしれません。 先行依存 (pre-dependencies) 関係については、展開状態 (Unpacked) については上記と同じ考え方ですが、先行依存関係の更新に失敗した場合 設定途中状態 (Half-Installed) までに留まります [47]。
postinst
スクリプトは以下のやり方で呼ばれる可能性があります。
パッケージに収録されたファイルは展開されます。 依存するパッケージも少なくとも展開状態 (Unpacked) になっています。 巡回依存関係がない限り、依存するパッケージは設定状態となります。 巡回依存関係がある場合の挙動は、バイナリの依存関係 - Depends、 Recommends、Suggests、Enhances、 Pre-Depends, Section 7.2 の解説を参照ください。
パッケージに収録されたファイルは展開されます。
依存するパッケージも少なくとも設定途中状態 (Half-Installed)
ではあり、その場合は以前に設定されていて削除されていない状態になっています。
ただし、依存関係にあるパッケージは設定状態ではないかもしれず、またエラーが起きている場合は展開に失敗している可能性もあります
[48]。
その場合でも、postinst
は、依存関係が必要となる処理を試行すべきです。
これは、この依存関係は通常の場合は満たされているためです。
ただし、これらの処理が失敗した場合には適切なエラー処理動作を行うよう検討してください。
パッケージ依存関係で要求したコマンドや機能がなかった場合には
postinst
を異常終了させるのが、多くの場合適切なやり方です。
prerm
スクリプトは以下のやり方で呼ばれる可能性があります。
内部の prerm
が呼ばれるパッケージは、少なくとも 設定途中状態
(Half-Installed) 状態です。
すべての依存関係にあるパッケージも少なくとも設定途中状態 (Half-Installed)
状態で、その場合は以前に設定されており、削除されていない状態です。
これら処理が呼ばれる際には、すべての依存関係のパッケージはもしエラーがない場合には少なくとも展開状態
(Unpacked) になっていますが、
さらにエラーがある場合は部分アップグレードに伴い、設定途中状態 (Half-Installed)
状態の様々なエラー状態の発生下で呼ばれます。
prerm upgrade が失敗した場合のエラー処理で呼ばれます。 新しいパッケージはまだ展開されておらず、preinst upgrade と同じ制約条件が適用されます。
postrm
スクリプトは以下のやり方で呼ばれる可能性があります。
postrm
スクリプトは、
パッケージのファイルが削除あるいは置き換えられたあとに呼ばれます。
postrm
が呼ばれたパッケージは、以前に設定解除され、展開状態
(Unpacked) である可能性もあります。
この時点で、以降のパッケージの変更では依存関係は考慮されません。
このため、すべての postrm
処理は "essential"
パッケージのみに依存し、パッケージの依存関係が必要な処理はすべて、依存関係が満たされない場合に丁寧に処理を飛ばすようにしなければいけません
[49]。
古いパッケージの postrm upgrade 処理が失敗した場合に呼ばれます。 新しいパッケージは展開されていますが、"essential" パッケージと先行依存パッケージのみへの依存が可能です。 先行依存したパッケージは設定されているか、展開状態 (Unpacked) または 以前に設定されてそれ以降削除されていない設定途中状態 (Half-Configured) です。
preinst
が失敗した場合のエラー処理の一環として新しいパッケージを展開する際に呼ばれます。
preinst
で前提とできる状態と同じ状態を、前提とすることができます。
インストール/アップグレード/上書き/消去 (すなわち、 dpkg --unpack が走っているとき、または dpkg --install の展開段階のとき) の手続きは下記の通りになります。どのような場合においても、 もしエラーが起これば (下記の場合を除けば) そこでの動作は、一般に逆方向へ走る処理です。 これは、管理スクリプトが異なる引数で逆順に走らされるということです。 このような呼び出しは以降の説明では「エラー回復」呼び出しとして記しています。
対象となるパッケージの、あるバージョンが既に インストール状態である場合は次の呼び出しをします。
old-prerm upgrade new-version
もし、これがエラーとなったら (つまり、 ゼロでない終了ステータスであったら)、
dpkg
はかわりに次の呼び出しをします。
new-prerm failed-upgrade old-version
これが動作するなら、アップグレード作業を続けます。 うまくいかないなら、エラー回復は次の通りです。
old-postinst abort-upgrade new-version
これが正常動作するなら、"old-version" がインストールされています。正常動作しないなら、 "old-version" は設定途中状態 (Half-Configured) 状態になっています。
「衝突する (conflicting)」パッケージが同時に削除される場合、 またはいずれかのパッケージが壊れている (Breaks のため) 場合には
もし、--auto-deconfigure が指定されている場合、 Breaks で設定破棄されるパッケージ各々に対し以下を呼び出します。
設定破棄されるパッケージの prerm deconfigure \ in-favour package-being-installed version
このときのエラー回復は
設定破棄されるパッケージの postinst abort-deconfigure \ in-favour package-being-installed-but-failed version
です。もし、--install が使われたばあいに再設定可能としておくため、設定破棄 (deconfigured) されたパッケージには設定を要求するマークが付けられます。
もし、その削除されようとしている衝突するパッケージに依存するパッケージがあり、 --auto-deconfigure が指定されているならば、 該当の各パッケージについて、次の呼び出しを行ないます。
設定破棄されるパッケージの prerm deconfigure \ in-favour package-being-installed version \ removing conflicting-package version
このときのエラー回復は
設定破棄されるパッケージの postinst abort-deconfigure \ in-favour package-being-installed-but-failed version \ removing conflicting-package version
です。もし、--install が使われたばあいに再設定可能としておくため、 設定破棄 (deconfigured) されたパッケージには設定を要求するマークが付けられます。
衝突しているパッケージを削除するための準備として、各パッケージに対して次の呼び出しが行われます。
衝突しているパッケージの prerm remove \ in-favour package new-version
このときのエラー回復は
衝突しているパッケージの postinst abort-remove \ in-favour package new-version
です。
パッケージがアップグレードされる場合には、次の呼び出しが行われます。
new-preinst upgrade old-version
これらが失敗した場合、
new-postrm abort-upgrade old-version
を呼びます。
これが正常終了する場合、次に
old-postinst abort-upgrade new-version
を呼びます。更にこれが正常終了する場合、旧バージョンは "Installed" 状態になっており、正常終了しない場合は 展開状態 (Unpacked) のままになっています。
これが失敗した場合、旧バージョンは設定途中状態 (Half-Installed) 状態で残っています。
そうではない場合、もしそのパッケージの以前のバージョンからの設定ファイルがあった (すなわち「設定ファイルのみ」の状態にあった) ならば、次の呼び出しが行われます。
new-preinst install old-version
このときのエラー回復は
new-postrm abort-install old-version
です。これが正常終了しない場合、パッケージは 設定途中状態 (Half-Installed) で残っており、この修正には再インストールが必要になります。 正常終了した場合には、パッケージは "Config-Files" 状態になっています。
そうでもない (つまり、そのパッケージが完全削除されていた) 場合、次の呼び出しが行われます。
new-preinst install
このときのエラー回復は
new-postrm abort-install
です。これが正常終了しない場合、パッケージは 設定途中状態 (Half-Installed) で残っており、この修正には再インストールが必要になります。 正常終了した場合には、パッケージはインストールされていない (Not-Installed) 状態になっています。
新しいパッケージのファイルが展開され、システムに既にあるファイル、例えば同じパッケージの古いバージョンからのファイルや、 他のパッケージからのファイルに上書きされます 古いファイルのバックアップが一時的に保持され、もし何か問題が起こればパッケージ管理システムがエラー回復の一部としてそれらを元に戻そうとします。
あるパッケージが、現在システムにある別のパッケージの ファイルと同名のファイルを含んでいる場合、Replaces (ファイルの上書きとパッケージの置換 - Replaces, Section 7.6 参照) が指定されていない場合にはエラーになります。
パッケージにとってもっと深刻なエラーとなるのは、他のパッケージからのディレクトリがある場所に そのパッケージが普通のファイルやほかのディレクトリでないような内容物を含んでいた場合です (ここでも、Replaces が使われていない場合においてです)。もし望むなら、 --force-overwrite-dir を使ってこのエラーを無効にすることができますが、これは勧められません。
お互いのファイルに上書きするパッケージは、決定論的に決まるのではあるけれども、システム管理者には理解しがたい振る舞いをします。 この状態では、簡単にプログラムを「見失う」事態が起こり得ます。 例えば、他のパッケージからのファイルに上書きするようなパッケージを展開して、それから、そのパッケージを削除することでこのような 「見失い」 [50] が起こります。
ディレクトリは、決してディレクトリへのシンボリックリンクに置き換わってしまうことはありませんし、その逆もありません。
そのかわりに、現在ある状態 (シンボリックリンクであるのか否か)
はそのままにされて、シンボリックリンクの場合 dpkg
はそのリンクをたどります。
もし、パッケージがアップグレードされている最中なら、次の呼び出しを行ないます。
old-postrm upgrade new-version
--> もしこれに失敗したら、dpkg
は次の呼び出しを試みます。
new-postrm failed-upgrade old-version
これが正常終了する場合、インストールを続行します。 うまくいかない場合には、エラー回復は
old-preinst abort-upgrade new-version
です。これが失敗した場合、パッケージは設定途中状態 (Half-Installed) 状態で残っています。 これが正常終了した場合、dpkg は次に、
new-postrm abort-upgrade old-version
を実行します。これが失敗した場合、パッケージは 設定途中状態 (Half-Installed) で残っています。 これが正常終了した場合、dpkg は次に、
old-postinst abort-upgrade new-version
を実行します。これが失敗した場合、旧バージョンは 展開状態 (Unpacked) になっています。
ここが戻れなくなるポイントです。dpkg
がさらに先に進むと、エラーがあった場合にもこのポイントより前には戻りません。
この場合、パッケージが非常に悪い状態で残り、
これをきれいにするためには、再インストールを成功させる必要があります。
ですが、ここは dpkg
が戻ることのできない作業を始める時です。
古いバージョンのパッケージにはあって、新しいものには無いファイルは削除されます。
ファイルリストが、古いものから新しいものに置きかえられます。
新しいメンテナスクリプトで、古いものを置きかえます。
あるパッケージに属するファイルが、インストールの間に全て上書きされ、依存の要求も無いような場合、そのパッケージは削除されたと見なします。 そのようなパッケージそれぞれに対して、
dpkg
は次の呼び出しを行ないます。
disappearer's-postrm disappear \ overwriter overwriter-version
パッケージ管理スクリプトが削除されます。
パッケージ状態のデータベースには、正常な状態、
具体的にはインストールされていない状態 (Not-Installed) として記録されます
(そのパッケージが持っていた conffiles
があれば、それは
dpkg
によって削除されるのではなく、無視されます)。
dpkg
は、そのパッケージが削除されそうなのかどうかは前もっては分からないので、
削除されるパッケージの `prerm' は 呼び出されないということに注意してください。
展開しようとしているパッケージの中にあって、他のパッケージのファイルリストにも記されている全てのファイルは、これらのリストから削除されます (これにより、もし「衝突する」パッケージがあれば、その衝突するパッケージのファイルリストが修正されます)。
今までのインストール作業の中で作成されていたバックアップファイルを消去します。
新しいパッケージの状態は、今では正常になっていますので、展開状態 (Unpacked) として記録されます。
ここが次の戻れなくなるポイントです。 もし衝突するパッケージの削除に失敗したばあいでも、これから後のインストール作業を戻すようなことはしません。 衝突したパッケージは半分削除された亡霊状態で残ってしまいます。
もし衝突するパッケージがあれば、次項に記載の削除作業へ移り、実行します。 削除作業は衝突するパッケージのファイルを削除することから始まります (展開されたパッケージの中にもあるファイルは、すでに衝突するパッケージのファイルリストから削除されているので、 この際に削除されてしまうことはありません)。
パッケージを設定する (この状況は dpkg --install や dpkg --configure で起きます) とき、まず conffile を更新し、それから次の呼び出しが行われます。
postinst configure most-recently-configured-version
設定中にエラーが起こった後、回復は行われません。 設定に失敗した場合、パッケージは設定途中状態 (Half-Configured) になっており、エラーメッセージが作成されます。
もし最近設定されたバージョン (上の呼び出しの
most-recently-configured-version) が存在しなければ、
dpkg
は引数として何も渡しません。 [51]。
prerm remove
もし、prerm が競合 (conflict) のために置きかえに失敗する場合、
conflictor's-postinst abort-remove \ in-favour package new-version
または、
postinst abort-remove
を実行します。
これが正常終了しない場合、パッケージは設定途中状態 (Half-Configured) 状態か、"Installed" 状態のままのいずれかになります。
パッケージのファイルを (conffile 群を除いて) 削除します。
postrm remove
失敗した場合にエラーを巻き戻す方法はありません。パッケージは 設定途中状態 (Half-Installed) 状態となっています。
postrm
以外のメンテナスクリプトを全て削除します。
もしパッケージを完全削除しているのでなければ、ここで止まります。 パッケージに
postrm
も conffile もないのであれば、削除 (remove)
と完全削除 (purge) には dpkg
の状態以外に違いが無いので、自動的に完全削除されることに注意してください。
conffile と全てのバックアップファイル (~ ファイル、 #*# ファイル、% ファイル、 .dpkg-{old,new,tmp} など) が削除されます。
postrm purge
これが失敗した場合、パッケージは "Config-Files" 状態のままになっています。
パッケージのファイルリストが削除されます。
[ previous ] [ Contents ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ A ] [ B ] [ C ] [ D ] [ E ] [ F ] [ G ] [ next ]
Debian ポリシーマニュアル
バージョン 3.9.5.0, 2014-07-03