Debian JP Project

(for vocal browsers: toc, main)

Google
WWW 全体 www.debian.or.jp 検索


[ previous ] [ Contents ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ A ] [ B ] [ C ] [ D ] [ E ] [ F ] [ G ] [ next ]


Debian ポリシーマニュアル
Chapter 6 - パッケージ管理スクリプトとインストールの手順


6.1 パッケージ管理スクリプトへの手引き

パッケージをインストール、アップグレード、削除する際に、パッケージ管理システムが走らせるスクリプトをパッケージの一部として供給することが可能です。

これらのスクリプトは preinstpostinstprermpostrm という制御情報ファイルです。 これらは適正な実行可能ファイルでなくてはなりません。 もし、これらがスクリプト (スクリプトであることを推奨します) ならば、 通常行われているように #! で始めなくてはなりません。 これらのスクリプトは、誰でも読むことと実行が可能でなければならず、 誰でも書き込み可能なパーミッションであってはいけません。

パッケージ管理システムはこれらのスクリプトからの終了ステータスを見ます。 パッケージ管理システムが手続きを止められるように、 エラーがあった場合にはスクリプトが 0 でないステータスで終了するようにしておくことが重要です。 シェルスクリプトでは ほとんど常に set -e を使う必要があるということを意味します (実際には、 通常シェルスクリプトを書く場合は一般に、このようにします)。 もちろん、全てがうまくいった場合に、0 ステータスで終了することも重要です。

さらに、postinst 中で debconf を用いてユーザとの対話を行うパッケージでは、制御情報ファイル内に config スクリプトをインストールすべきです。 詳細は、メンテナスクリプト中のプロンプト使用について, Section 3.9.1 を参照ください。

パッケージがアップグレードされる時には、アップグレード手続きの間に古いパッケージと新しいパッケージのスクリプトが、組み合わせて呼び出されます。 もし、あなたのスクリプトがとても複雑になっていく場合には、このことに注意し、スクリプトの引数のチェックが必要になるでしょう。

大まかに言えば、preinst は (ある特定のバージョンの) パッケージが展開される前に、postinst は展開された後に呼び出されます。prerm は (あるバージョンの) パッケージが 削除される前に、 postrm は削除された後に呼び出されます。

管理スクリプトから呼ばれるプログラムは、通常そのスクリプトにおいてプログラムの前にパスをつけて呼び出すべきではありません。 インストールが始まる前に、パッケージ管理システムは ldconfigstart-stop-daemon、 や update-rc.d などのプログラムが指定された PATH 環境変数から発見できるかどうかをチェックします。 ですから、これらのプログラムや、PATH にあることを期待してもいいようなプログラムについては、絶対パス名をつけずに呼び出すべきです。 管理スクリプトは PATH をリセットすべきではありませんが、 PATH の前か後に、パッケージに対して特別なディレクトリを付け加えるという方法を採るのはかまいません。 このような考慮は、実際には、全てのシェルスクリプトに対して当てはまるものです。


6.2 メンテナスクリプトの再入結果の同一性

メンテナスクリプトが再入結果の同一性をもつようにすることはとても重要です。

エラー回復手続きをできるようにするため、スクリプトは同じ状況にあるときに、それを何度か起動しても無害でなければなりません。 もし、一回目の呼び出しが失敗した、または何らかの理由によって途中で中止した場合、 二回目の呼び出しでは一回目で実行し残したものを単に実行し、 もし何もかもうまくいったなら成功ステータスで終了するようにすべき [46] です。


6.3 メンテナスクリプトからのターミナルの制御

メンテナスクリプトは制御端末がある状態で実行されているとは限らず、 ユーザとの対話ができることは保証されていません。 制御端末が提供されていない場合、非対話型で処理することができるようにしなければなりません。 Debian Configuration Management Specification に準拠したプログラムを使ってプロンプトを出しているメンテナスクリプト (メンテナスクリプト中のプロンプト使用について, Section 3.9.1 参照) は、非対話型の動作になった場合の扱いを、そのプログラムが行うと仮定して構いません。

優先順位の高い、妥当な標準回答の無いような対話を行いたい場合、 制御端末がない際に異常終了することは許されています。 但し、可能な限りそのようなことが起きないようにすべきです。 これは、自動インストールや、無人インストールの妨げになるからです。 大抵の場合は、このような挙動はユーザにそのパッケージのバグと見做されるでしょう。


6.4 終了ステータス

各スクリプトは成功の場合には終了ステータスを 0 に、失敗の場合には 0 でない値にして帰ってください。これは、 パッケージ管理システムがこれらスクリプトの終了ステータスを監視しており、このデータに基づいて次に取るべき処理を決めているためです。


6.5 メンテナスクリプトの呼ばれ方のまとめ

以下は、メンテナスクリプトのすべての呼ばれ方と、 スクリプトが呼ばれる際に依存して良い機能についてまとめたものです。 スクリプト名で、new- で始まるものは、インストール/更新/ダウングレード対象の新バージョンのパッケージから呼ばれるスクリプトです。 スクリプト名で、old- で始まるものは、更新/ダウングレードされる対象の旧バージョンのパッケージから呼ばれるスクリプトです。

preinst スクリプトは以下のやり方で呼ばれる可能性があります。

new-preinst install
new-preinst install old-version
new-preinst upgrade old-version

問題のパッケージはまだ展開されていないため、preinst スクリプトはパッケージに含まれるファイルに依存することはできません。 essential パッケージと、先行依存 (predependency) (Pre-Depends) を指定したパッケージが提供されていることは期待してもかまいません。 先行依存されたパッケージは少なくとも一回は設定されていますが、ただし preinst が呼ばれた時点では単に展開状態 (Unpacked) か、 設定途中状態 (Half-Configured) 状態である可能性があります。 この状況は、先行依存を指定したパッケージの旧版がきちんと設定されていて、その後削除されていなかった場合に起きます。

old-preinst abort-upgrade new-version

新パッケージの展開後に、アップグレードが postrm upgrade 処理の失敗のために失敗した場合に、エラー処理で呼ばれます。 展開されたファイルは一部が新しい版に置き換わっていたり、一部が削除されている可能性があるため、 パッケージに含まれるファイルに依存することはできません。 パッケージの依存関係は満たされていないかもしれません。 先行依存 (pre-dependencies) 関係については、展開状態 (Unpacked) については上記と同じ考え方ですが、先行依存関係の更新に失敗した場合 設定途中状態 (Half-Installed) までに留まります [47]。

postinst スクリプトは以下のやり方で呼ばれる可能性があります。

postinst configure most-recently-configured-version

パッケージに収録されたファイルは展開されます。 依存するパッケージも少なくとも展開状態 (Unpacked) になっています。 巡回依存関係がない限り、依存するパッケージは設定状態となります。 巡回依存関係がある場合の挙動は、バイナリの依存関係 - DependsRecommendsSuggestsEnhancesPre-Depends, Section 7.2 の解説を参照ください。

old-postinst abort-upgrade new-version
conflictor's-postinst abort-remove in-favour package new-version
postinst abort-remove
deconfigured's-postinst abort-deconfigure in-favour failed-install-package version [removing conflicting-package version]

パッケージに収録されたファイルは展開されます。 依存するパッケージも少なくとも設定途中状態 (Half-Installed) ではあり、その場合は以前に設定されていて削除されていない状態になっています。 ただし、依存関係にあるパッケージは設定状態ではないかもしれず、またエラーが起きている場合は展開に失敗している可能性もあります [48]。 その場合でも、postinst は、依存関係が必要となる処理を試行すべきです。 これは、この依存関係は通常の場合は満たされているためです。 ただし、これらの処理が失敗した場合には適切なエラー処理動作を行うよう検討してください。 パッケージ依存関係で要求したコマンドや機能がなかった場合には postinst を異常終了させるのが、多くの場合適切なやり方です。

prerm スクリプトは以下のやり方で呼ばれる可能性があります。

prerm remove
old-prerm upgradenew-version
conflictor's-prerm remove in-favour package new-version
deconfigured's-prerm deconfigure in-favour package-being-installed version [removing conflicting-package version]

内部の prerm が呼ばれるパッケージは、少なくとも 設定途中状態 (Half-Installed) 状態です。 すべての依存関係にあるパッケージも少なくとも設定途中状態 (Half-Installed) 状態で、その場合は以前に設定されており、削除されていない状態です。 これら処理が呼ばれる際には、すべての依存関係のパッケージはもしエラーがない場合には少なくとも展開状態 (Unpacked) になっていますが、 さらにエラーがある場合は部分アップグレードに伴い、設定途中状態 (Half-Installed) 状態の様々なエラー状態の発生下で呼ばれます。

new-prerm failed-upgrade old-version

prerm upgrade が失敗した場合のエラー処理で呼ばれます。 新しいパッケージはまだ展開されておらず、preinst upgrade と同じ制約条件が適用されます。

postrm スクリプトは以下のやり方で呼ばれる可能性があります。

postrm remove
postrm purge
old-postrm upgrade new-version
disappearer's-postrm disappear overwriter overwriter-version

postrm スクリプトは、 パッケージのファイルが削除あるいは置き換えられたあとに呼ばれます。 postrm が呼ばれたパッケージは、以前に設定解除され、展開状態 (Unpacked) である可能性もあります。 この時点で、以降のパッケージの変更では依存関係は考慮されません。 このため、すべての postrm 処理は "essential" パッケージのみに依存し、パッケージの依存関係が必要な処理はすべて、依存関係が満たされない場合に丁寧に処理を飛ばすようにしなければいけません [49]。

new-postrm failed-upgrade old-version

古いパッケージの postrm upgrade 処理が失敗した場合に呼ばれます。 新しいパッケージは展開されていますが、"essential" パッケージと先行依存パッケージのみへの依存が可能です。 先行依存したパッケージは設定されているか、展開状態 (Unpacked) または 以前に設定されてそれ以降削除されていない設定途中状態 (Half-Configured) です。

new-postrm abort-install
new-postrm abort-install old-version
new-postrm abort-upgrade old-version

preinst が失敗した場合のエラー処理の一環として新しいパッケージを展開する際に呼ばれます。 preinst で前提とできる状態と同じ状態を、前提とすることができます。


6.6 インストール時とアップグレート時のパッケージの展開段階の詳細

インストール/アップグレード/上書き/消去 (すなわち、 dpkg --unpack が走っているとき、または dpkg --install の展開段階のとき) の手続きは下記の通りになります。どのような場合においても、 もしエラーが起これば (下記の場合を除けば) そこでの動作は、一般に逆方向へ走る処理です。 これは、管理スクリプトが異なる引数で逆順に走らされるということです。 このような呼び出しは以降の説明では「エラー回復」呼び出しとして記しています。

    1. 対象となるパッケージの、あるバージョンが既に インストール状態である場合は次の呼び出しをします。

           old-prerm upgrade new-version
      
    1. もし、これがエラーとなったら (つまり、 ゼロでない終了ステータスであったら)、 dpkg はかわりに次の呼び出しをします。

           new-prerm failed-upgrade old-version
      

      これが動作するなら、アップグレード作業を続けます。 うまくいかないなら、エラー回復は次の通りです。

           old-postinst abort-upgrade new-version
      

      これが正常動作するなら、"old-version" がインストールされています。正常動作しないなら、 "old-version" は設定途中状態 (Half-Configured) 状態になっています。

  1. 「衝突する (conflicting)」パッケージが同時に削除される場合、 またはいずれかのパッケージが壊れている (Breaks のため) 場合には

    1. もし、--auto-deconfigure が指定されている場合、 Breaks で設定破棄されるパッケージ各々に対し以下を呼び出します。

           設定破棄されるパッケージの prerm deconfigure \
             in-favour package-being-installed version
      

      このときのエラー回復は

           設定破棄されるパッケージの postinst abort-deconfigure \
             in-favour package-being-installed-but-failed version
      

      です。もし、--install が使われたばあいに再設定可能としておくため、設定破棄 (deconfigured) されたパッケージには設定を要求するマークが付けられます。

    1. もし、その削除されようとしている衝突するパッケージに依存するパッケージがあり、 --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) されたパッケージには設定を要求するマークが付けられます。

    1. 衝突しているパッケージを削除するための準備として、各パッケージに対して次の呼び出しが行われます。

           衝突しているパッケージの prerm remove \
             in-favour package new-version
      

      このときのエラー回復は

           衝突しているパッケージの postinst abort-remove \
             in-favour package new-version
      

      です。

    1. パッケージがアップグレードされる場合には、次の呼び出しが行われます。

           new-preinst upgrade old-version
      

      これらが失敗した場合、

           new-postrm abort-upgrade old-version
      

      を呼びます。

      1. これが正常終了する場合、次に

             old-postinst abort-upgrade new-version
        

        を呼びます。更にこれが正常終了する場合、旧バージョンは "Installed" 状態になっており、正常終了しない場合は 展開状態 (Unpacked) のままになっています。

      1. これが失敗した場合、旧バージョンは設定途中状態 (Half-Installed) 状態で残っています。

    1. そうではない場合、もしそのパッケージの以前のバージョンからの設定ファイルがあった (すなわち「設定ファイルのみ」の状態にあった) ならば、次の呼び出しが行われます。

           new-preinst install old-version
      

      このときのエラー回復は

           new-postrm abort-install old-version
      

      です。これが正常終了しない場合、パッケージは 設定途中状態 (Half-Installed) で残っており、この修正には再インストールが必要になります。 正常終了した場合には、パッケージは "Config-Files" 状態になっています。

    1. そうでもない (つまり、そのパッケージが完全削除されていた) 場合、次の呼び出しが行われます。

           new-preinst install
      

      このときのエラー回復は

           new-postrm abort-install
      

      です。これが正常終了しない場合、パッケージは 設定途中状態 (Half-Installed) で残っており、この修正には再インストールが必要になります。 正常終了した場合には、パッケージはインストールされていない (Not-Installed) 状態になっています。

  1. 新しいパッケージのファイルが展開され、システムに既にあるファイル、例えば同じパッケージの古いバージョンからのファイルや、 他のパッケージからのファイルに上書きされます 古いファイルのバックアップが一時的に保持され、もし何か問題が起こればパッケージ管理システムがエラー回復の一部としてそれらを元に戻そうとします。

    あるパッケージが、現在システムにある別のパッケージの ファイルと同名のファイルを含んでいる場合、Replaces (ファイルの上書きとパッケージの置換 - Replaces, Section 7.6 参照) が指定されていない場合にはエラーになります。

    パッケージにとってもっと深刻なエラーとなるのは、他のパッケージからのディレクトリがある場所に そのパッケージが普通のファイルやほかのディレクトリでないような内容物を含んでいた場合です (ここでも、Replaces が使われていない場合においてです)。もし望むなら、 --force-overwrite-dir を使ってこのエラーを無効にすることができますが、これは勧められません。

    お互いのファイルに上書きするパッケージは、決定論的に決まるのではあるけれども、システム管理者には理解しがたい振る舞いをします。 この状態では、簡単にプログラムを「見失う」事態が起こり得ます。 例えば、他のパッケージからのファイルに上書きするようなパッケージを展開して、それから、そのパッケージを削除することでこのような 「見失い」 [50] が起こります。

    ディレクトリは、決してディレクトリへのシンボリックリンクに置き換わってしまうことはありませんし、その逆もありません。 そのかわりに、現在ある状態 (シンボリックリンクであるのか否か) はそのままにされて、シンボリックリンクの場合 dpkg はそのリンクをたどります。

    1. もし、パッケージがアップグレードされている最中なら、次の呼び出しを行ないます。

           old-postrm upgrade new-version
      
    1. --> もしこれに失敗したら、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 が戻ることのできない作業を始める時です。

  1. 古いバージョンのパッケージにはあって、新しいものには無いファイルは削除されます。

  1. ファイルリストが、古いものから新しいものに置きかえられます。

  1. 新しいメンテナスクリプトで、古いものを置きかえます。

  1. あるパッケージに属するファイルが、インストールの間に全て上書きされ、依存の要求も無いような場合、そのパッケージは削除されたと見なします。 そのようなパッケージそれぞれに対して、

    1. dpkg は次の呼び出しを行ないます。

           disappearer's-postrm disappear \
           			overwriter overwriter-version
      
    1. パッケージ管理スクリプトが削除されます。

    1. パッケージ状態のデータベースには、正常な状態、 具体的にはインストールされていない状態 (Not-Installed) として記録されます (そのパッケージが持っていた conffiles があれば、それは dpkg によって削除されるのではなく、無視されます)。 dpkg は、そのパッケージが削除されそうなのかどうかは前もっては分からないので、 削除されるパッケージの `prerm' は 呼び出されないということに注意してください。

  1. 展開しようとしているパッケージの中にあって、他のパッケージのファイルリストにも記されている全てのファイルは、これらのリストから削除されます (これにより、もし「衝突する」パッケージがあれば、その衝突するパッケージのファイルリストが修正されます)。

  1. 今までのインストール作業の中で作成されていたバックアップファイルを消去します。

  1. 新しいパッケージの状態は、今では正常になっていますので、展開状態 (Unpacked) として記録されます。

    ここが次の戻れなくなるポイントです。 もし衝突するパッケージの削除に失敗したばあいでも、これから後のインストール作業を戻すようなことはしません。 衝突したパッケージは半分削除された亡霊状態で残ってしまいます。

  1. もし衝突するパッケージがあれば、次項に記載の削除作業へ移り、実行します。 削除作業は衝突するパッケージのファイルを削除することから始まります (展開されたパッケージの中にもあるファイルは、すでに衝突するパッケージのファイルリストから削除されているので、 この際に削除されてしまうことはありません)。


6.7 設定の詳細

パッケージを設定する (この状況は dpkg --installdpkg --configure で起きます) とき、まず conffile を更新し、それから次の呼び出しが行われます。

     postinst configure most-recently-configured-version

設定中にエラーが起こった後、回復は行われません。 設定に失敗した場合、パッケージは設定途中状態 (Half-Configured) になっており、エラーメッセージが作成されます。

もし最近設定されたバージョン (上の呼び出しの most-recently-configured-version) が存在しなければ、 dpkg は引数として何も渡しません。 [51]。


6.8 削除と設定の完全削除の詳細

  1.      prerm remove
    

    もし、prerm が競合 (conflict) のために置きかえに失敗する場合、

         conflictor's-postinst abort-remove \
           in-favour package new-version
    

    または、

         postinst abort-remove
    

    を実行します。

    これが正常終了しない場合、パッケージは設定途中状態 (Half-Configured) 状態か、"Installed" 状態のままのいずれかになります。

  1. パッケージのファイルを (conffile 群を除いて) 削除します。

  1.      postrm remove
    

    失敗した場合にエラーを巻き戻す方法はありません。パッケージは 設定途中状態 (Half-Installed) 状態となっています。

  1. postrm 以外のメンテナスクリプトを全て削除します。

    もしパッケージを完全削除しているのでなければ、ここで止まります。 パッケージに postrmconffile もないのであれば、削除 (remove) と完全削除 (purge) には dpkg の状態以外に違いが無いので、自動的に完全削除されることに注意してください。

  1. conffile と全てのバックアップファイル (~ ファイル、 #*# ファイル、% ファイル、 .dpkg-{old,new,tmp} など) が削除されます。

  1.      postrm purge
    

    これが失敗した場合、パッケージは "Config-Files" 状態のままになっています。

  1. パッケージのファイルリストが削除されます。


[ 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

The Debian Policy Mailing List