debconfで楽々パッケージ設定 debconfとは、Debianにおいてパッケージの設定を行なうために開発されたパッケージである。そもそもdebconfは前Debian Project LeaderのWichert Akkerman発案のconfiguration database framework構想に基づくJoey Hessによる実装である。 今やConnectivaやVine、Holonなどで採用されているaptがDebianで開発されたというのを知っているのはどれくらいいるのだろうか。私の予言した通り(?)新世代のパッケージングシステムaptはDebian以外にも広く採用されるようになってきている。aptにより多くのパッケージをまとめて扱うのはやりやすくなった。しかしながらまだパッケージごとの設定というのが統一されていないのが現状だ。そこであらわれたのがdebconfである。debconfによりパッケージの設定を統一されたインターフェースで提供することができるのだ。 なお、debconfの仕様自体は/usr/share/doc/debian-policy/debconf_specification.*というファイルに書かれているので一読しておくべし。 ■debconfを使ってるパッケージでの設定の仕方 まぁ、これに関してはあまり書くことはないのだけれどもDebianユーザでない人むけに簡単に紹介しておく。 まずはパッケージをインストールするのはapt-getである。これはいまさら言うまでもないだろう。まだ知らない人は、ちょっとヤバイです(笑) # apt-get install パッケージ そうするとパッケージがもしdebconf化されていて、ユーザに聞くべき質問があればダイアログが表示される。debconfでは設定データベースとフロントエンドが分離されているのでいくつかのフロントエンドのタイプがある。まぁどれも単に設定するだけなら説明するまでもないだろう。 あとになって設定かえたいなー という時は dpkg-reconfigure を使う # dpkg-reconfigure パッケージ ただしこれだとデフォルトのプライオリティレベルが使われるのでdebconfでできるはずの細かい設定などができない場合がある。debconfでできる設定をすべてやりたい場合は次のように実行することで一時的にプライオリティレベルをlowにする。 # dpkg-reconfigure -plow パッケージ dpkg-reconfigureで設定しなおしができるのは既に設定ができた(configuredな)パッケージだけである。configureに失敗している状態のパッケージに関してはこれでは設定をかえられない。 ■debconfの裏側 aptを使っている場合、debconfおよびapt-utilsをインストールしておけば、aptがパッケージをダウンロードしパッケージを展開する前に設定をまとめておこなうことができる。debconfの設定がおわったあとにパッケージの展開、設定はほぼ自動的におこなえる。ただし今のところconffilesに関してはdebconfでは扱うことはできない。これはconffilesで扱っているようなファイルをdebconfを使って読みこみ/生成できるようになればすべてdebconfにおきかえることができるはずである。 apt-getがパッケージをダウンロードしてくると/etc/apt/apt.conf.d/70debconfというファイルによりdpkg-preconfigure -apt が実行される。 ★ 70debconf ○---------------------------------------------------------------- // Pre-configure all packages with debconf before they are installed. // If you don't like it, comment it out. DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt || true";}; ○---------------------------------------------------------------- dpkg-preconfigureではapt-utilsのapt-mergetemplatesを使っているためapt-utilsがインストールされていないとdebconfの設定はこのタイミングではおこなわれないことに注意する必要がある。よほどの事情がない限りapt-utilsもインストールしておくべきだ。 さて、dpkg-preconfigure -aptはいまダウンロードしたパッケージのリストがわたされるのでそれらに対してテンプレートの読みこみとconfigスクリプトの実行をおこなう。 このconfigスクリプトにより、テンプレートから生成される変数に設定していくことでパッケージの設定をおこなうことになる。 ★debconfの流れ □---------------------------------------------------------------- apt-getによる*.debのダウンロード: /var/cache/apt/archives/にパッケージがたまる ↓ dpkg-preconfigure -apt /var/cache/apt/archives/からインストールするdebを見る control情報のtemplatesとconfig等をとりだす templatesをloadし/var/cache/debconf/templates.dat、config.datに登録 configスクリプトを実行する ↓ dpkg --unpackでパッケージを展開 preinstを実行 ファイルをおきかえ ↓ dpkg --configureでパッケージの設定 postinstを実行 □---------------------------------------------------------------- 基本的にconfigスクリプトではユーザに対して設定情報を尋ね(もしくはデフォルト値を設定し)、postinstスクリプトでそれを読みだして実際のパッケージの設定ファイルなどに書きだすなどの処理を行うことになる。 □---------------------------------------------------------------- db_input db_go +------ configスクリプト <--------> user | debconfデータベース-----+ /var/cache/debconf | +------ postinstスクリプト ---> 設定ファイル db_get □---------------------------------------------------------------- debconfではこのconfigスクリプト/postinstスクリプトとdebconfデータベース間のやりとりのプロトコルを決めている。これによりフロントエンドをかえたりバックエンドデータベースの実装を変更したりすることができるようになっているのだ。 □configスクリプト configスクリプトでやることはユーザとのやりとり、もしくは既存の設定ファイルの内容などからdebconfデータベースに登録することである。 基本的には次のような流れになる。ここでは/bin/shスクリプトについてのみ解説しとく。 ★ . /usr/share/debconf/confmodule まず/usr/share/debconf/confmoduleを.でよみこむ。これでfrontendとbackendのプロセスにわかれそれぞれ通信するようになる。ちなみにfrontendはperlで書かれていて標準のファイルディスクリプタを介して通信している。なおdebconfシェルモジュールではすべてのコマンドにはdb_が前についてるが、プロトコル上はこのdb_は実際にはつけない。 ★ db_version 2.0 通信に使うdebconfプロトコルのバージョンをネゴシエーションする。これは「version 2.0で通信したい」といっているわけで、それがdebconfでサポートできないようなバージョンだとリターンコード30をかえす。リターンコードは変数$RETにはいる。このコマンドはpostinstなんかでも使う。 ★ db_capb キャパビリティ 必要とするキャパビリティを要求する。指定できるのはbackupおよびmultiselectのふたつ。backupは前の質問に戻るをサポート、multiselectは複数のセレクトをできるようにする機能である。 ★ db_title タイトル 質問ダイアログを出すときのタイトルを設定する。 ★ db_input プライオリティ 変数名 || true もしプライオリティがdebconf設定のプライオリティより高ければ変数名に対応しているテンプレートを使ってユーザにデータを入力させる。つまりdb_input lowだとその質問はあまり重要ではなく細かい設定がしたい人だけがやればいいというような項目になる。逆にdb_input criticalだとユーザが与えないとまともな設定ができないような項目になる。 どのようにデータを入力するかはそのテンプレートにわりあてられている型によってかわる(後述)。もしユーザに提示しなかったら$RETが30になる。 なお、|| true としているのはdb_inputがエラーコードを返すことでシェルのset -eがきいてそこで終了しないようにするためである。他のコマンドでも || true をつけてるのはこのためだ。 ちなみにdb_inputだけだと「質問してよー」とdebconfに伝えるだけで実際にユーザに提示するまではいかない。それをするのが次のdb_goだ。 ★db_go || true db_inputで与えられてきた「質問してよー」というのを実際にユーザに提示する。 ここでダイアログがでてきてユーザとやりとりすることになる。 基本的に以上だけでもいいわけだがデフォルト設定をしたい場合などはdb_setなどで変数に設定しておくこともできる。 ★db_set 変数名 値 || true 変数名に値を与える。この場合ユーザとのやりとりは発生しない。 □postinstスクリプト postinstスクリプトではdebconfからデータをよみだして実際の設定ファイルを生成することが仕事となる。debconf以前ではpostinst自身がechoやreadコマンドなどをつかってユーザの入力をいれていたのをここではdebconfからとってくるようにしておく。 ★db_get 変数名 (おそらくconfigスクリプトで)設定した変数の値をとりだす。結果は$RETにはいっている。 ★db_stop ここでdebconfの処理を終了。consoleに何か表示する前にdebconfを止めておく必要がある。さもないとconsoleに出そうとしている文字列がdebconfの方におくられて変なことになったりしがち。 □テンプレートと変数 debconfではテンプレートと変数というものがある。これは似てるようで別なものというかちょっと違う。誤解をおそれずにいうとテンプレートがクラスで、変数がそのインスタンスだと言えばいいのかもしれない。 ○テンプレート テンプレートにはユーザに対してどのような情報を尋ねるかというものが書いてある。テンプレートには名前があり、型があり、デフォルト値があり、説明がある。 ★テンプレート □---------------------------------------------------------------- Template: 名前 Type: 型 Default: デフォルト値 Description: 短かい説明 長い説明 □---------------------------------------------------------------- 名前としては「パッケージ名/識別子」というふうな文字列をつかう。これによりパッケージ間でテンプレートの衝突がなくなる。ちなみに複数のパッケージで共有するようなテンプレートは「share/シェア名/識別子」のようなかんじにしてある。 型には次のようなものがある。 string 文字列 boolean true か false select Choices:に設定されている空白もしくはコンマで区切られた複数 の値から一つ multiselect selectは一つしか選べないのに対して複数選べる note たんにDescription:の説明を提示するだけ。メールもおくる text Description:の説明を提示する password 入力するときにecho backしないstring ○変数 変数はテンプレートから生成される。テンプレートで指示された型および説明を使ってユーザに提示し、その結果を記憶しておくのが変数である。基本的にはテンプレート名と同じ名前の変数がある。しかし、同じテンプレートを使って違う変数に結果を覚えておくこともできる。 ★テンプレートと変数の対応(1対多) □---------------------------------------------------------------- テンプレート -+---------> テンプレートと同じ名前の変数 | +---------> 別の名前の変数 +---------> 別の名前の変数 +---------> 別の名前の変数 +---------> 別の名前の変数 □---------------------------------------------------------------- db_inputやdb_goは変数名を引数にあたえている。上の図のように変数に対応するテンプレートはひとつしか存在しないので変数名をあたえればそれはどの型か、どのようにユーザに提示すればいいかがわかる。 なおテンプレートと同名の変数は最初から存在するので、変数名を使うところでテンプレート名をつかえば いきなりその名前のテンプレートに対応した変数を使うことができる。 逆にテンプレート名と違う変数を使いたい時は、前もってその変数がどのテンプレートを使うのかを指示しなくてはいけない。それをするのがdb_registerだ。 ★db_register テンプレート 変数名 これでテンプレートに対応した新しい変数を作ることができる。このようにして新しい変数を作成しておけば、この後 db_inputやdb_getでその変数を使うことができるようになる。なお、その変数が必要なくなった時は「db_unregister 変数名」で削除することができる。 ○テンプレートと変数の実装は? テンプレートおよび変数はそれぞれ/var/cache/debconf/template.datおよび/var/cache/debconf/config.datにプレーンテキストで格納されている。ただいろいろな言語が様々なエンコーディングでDescriptionにかいているので扱いには若干注意する必要がある。 config.datの方をよくみるとOwners:やFlags:とかがある。Owners:はその変数はどのパッケージのものかという情報を保持している。db_purgeする時にパッケージが保持している変数を削除するためである。 Flags:はその変数を実際につかったかどうかのフラグだ。seenだとその変数を設定するのにユーザが見たという意味になる。フラグはdb_fgetおよびdb_fsetコマンドで書いたり読んだりできる。 ■debconfを使ってるスクリプトのデバッグ debconfを使ってるスクリプトのデバッグはやや難しい。しかし基本はDEBCONF_DEBUGに値を設定してスクリプトを実行すればいい。 # DEBCONF_DEBUG='.*' /var/lib/dpkg/info/パケージ.postinst configure これでパッケージの設定する時のdebconfの動きを追うことができる。なお簡単にするためにdpkg-reconfigure -plow debconfでdebconfフロントエンドをReadlineなどをにしておいた方がいいかもしれない。 DEBCONF_DEBUG='.*'というのは DEBCONF_DEBUG=user、DEBCONF_DEBUG=developer、DEBCONF_DEBUG=dbすべてを指定したのと同じ意味になる。 debconfにはいくつか便利なツールがある。これらを使うとデバッグも少しは楽になるだろう。またconfigureに失敗していてdebconfデータベースの値を編集したい場合にも使うことができる。これらのツールを使う場合debconfデータベースにアクセスする必要があるためにrootで実行する必要がある。 ★debconf-show パッケージ パッケージに属する変数の値をすべて表示する。 ★debconf-loadtemplate パッケージ テンプレート パッケージのテンプレートファイルをテンプレートデータベースによみこむ。 ★debconf-communicate debconfプロトコルでおしゃべりするためのプログラム。標準入力からコマンドをあたえると標準出力に結果をかえす。たとえば次のように使う。 # echo 'get adduser/homedir-permission' | debconf-communicate 0 true 0は成功、trueが返り値(db_getなら$RETに設定される値)である。 ■まとめ 締切真近にたまたまメイリングリストに流れていた話に刺激されて書いたという適当なネタだが、それなりに量が書けたのでこのあたりで終わりとする。debconfにはまだcapb backupの戻る機能やsubstによる動的テンプレート生成やテンプレートのフィールドをとりだすmetagetなどもあるがそれについての説明はdebconf_specificationをみよ ということで。 ちなみに当初はdebconfのライセンスはGPLでしたが、Debian以外でもできるだけ多くのプラットフォームでも使ってもらいたいということで関係者各位全ての合意の上でBSDライセンスに変更されているのでGPLが嫌いな人でもok! # というかこのスピードで例の本を書け > 私 (笑)