Handbook:Parts/Working/Initscripts/ja

システムの起動
システムが起動すると、たくさんのテキストが流れます. 注意して見ると、(通常) それが毎回同じ内容であることに気づくでしょう. これら全てのアクションの実行はブートシーケンスと呼ばれ、(ほぼ) 静的に定義されます.

まずブートローダーが、ブートローダーの設定で定義されたカーネルイメージを読み込みます. そしてブートローダーはCPUにカーネルを実行するよう指示します. カーネルが読み込まれ実行されると、全てのカーネル内の構造やタスクが初期化され、initプロセスを開始します.

このプロセスではまず ( に書かれた) すべてのファイルシステムをマウントし、使用可能な状態にします. そして に置かれたいくつかのスクリプトを実行します. これらのスクリプトは、システムのブートに必要なサービスを立ち上げます.

全てのスクリプトを実行したら、initは最後に端末 (ほとんどの場合 + や + などの下に隠された仮想端末ですが) を と呼ばれる特別なプロセスに接続します. このプロセスは login を実行することで各端末からユーザーがログオンできるようにします.

Initscripts
ところで、initは 内のスクリプトを適当に実行するわけではありません. それどころか、 内のスクリプトを全て実行するわけでもなく、指示されたスクリプトだけを実行します. 実行するスクリプトは を見て決定しています.

まずinitは にあるスクリプトのうち、 にシンボリックリンクが存在するものを全て実行します. 基本的にはアルファベット順に開始しますが、一部のスクリプトは自身の前に開始しなければならないスクリプトを示す依存情報を持っています.

から参照されている全てのスクリプトを実行すると、続けてinitは にシンボリックリンクが存在するスクリプトを実行します. 繰り返しになりますが、正しい起動シーケンスのために順序を変更する依存情報をスクリプトが持っていない限り、アルファベット順でスクリプトの実行順が決まります. これは Gentoo Linux のインストールで実行した などのコマンドで   を使った理由でもあります.

init の仕組み
もちろん、init 自身がこれらすべてを決定するわけではありません. どのような動作をすべきか指定する設定ファイルが必要です. この設定ファイルが です.

先ほど説明したブートシーケンスを思い出してください - init が最初にする動作はすべてのファイルシステムをマウントすることです. これは の以下の行で定義されています:

この行は init に対し、システムを初期化するために を実行するよう指示します. スクリプトが初期化を処理するので、init はあまり多くのことをしないと言えるかもしれません - システム初期化のタスクは他のプロセスに委譲しているのです.

第二に、init は にシンボリックリンクがあるすべてのスクリプトを実行します. これは以下の行で定義されています:

再び openrc スクリプトが必要なタスクを処理します. openrc に渡されるオプション(boot)が、使用する のサブディレクトリと同じであることに注目してください.

ここで、init はどのランレベルを実行すべきか見るために設定ファイルを調べます. これを決定するために から以下の行が読み込まれます:

この場合(Gentoo ユーザーの多くはこれを使用しています)、ランレベルの id は3です. この情報を使って、init はランレベル3を開始するために何を実行する必要があるかを調べます:

レベル3を定義している行では、サービスを開始するために再度 openrc を(今度は引数  とともに)使用しています. 今回も openrc の引数が のサブディレクトリと同じであることに注目してください.

openrc が終了すると、init はどの仮想コンソールを有効化すべきか、また各コンソールでどのコマンドを実行しなければならないかを決定します:

有効なランレベル
前の節では、init がどのランレベルを有効化するか決めるために番号を用いていることを説明しました. ランレベルはシステムが動作する際の状態であり、ランレベルを開始したり終了したりした時に実行されるスクリプト(ランレベルスクリプトあるいは init スクリプト)の一群を含んでいます.

Gentoo では7つのランレベルが定義されています: 3つの内部ランレベルと4つのユーザー定義ランレベルです. 内部ランレベルはそれぞれ sysinit、shutdown そして reboot と呼ばれており、まさに名前が示す通りに動作します: システムの初期化、システムのパワーオフ、そしてシステムの再起動を行うのです.

ユーザー定義ランレベルはそれぞれ付随する のサブディレクトリーを持ちます: boot、default、nonetwork そして single です. boot ランレベルは、他のランレベルによって使用される、システムに必要なすべてのサービスを起動します. 残りの3つのランレベルは開始するサービスに違いがあります: default は日常的な作業に使われ、nonetwork は一切のネットワーク接続が不要な場合に使われ、そして single はシステムを修復する必要がある時に使われます.

init スクリプトの使い方
openrc プロセスが開始するスクリプトは init スクリプトと呼ばれます. 内の各スクリプトは 、 、 、 、 、 、 、 、 、  あるいは   という引数で実行することができます.

サービス(およびすべての依存サービス)を開始、停止、あるいは再起動するには、 、 および   引数を使います:

あるサービスを停止するが依存サービスは停止させたくない場合には、 引数とともに   オプションも使用します:

サービスがどのような状態にあるか(started、stopped、 ...)見るには  引数を使用します:

サービスが実行中であるというステータス情報が表示されたのに実際はそうでない場合には、 引数を使用してステータス情報を "stopped" にリセットします:

サービスがどのような依存関係を持っているか問い合わせるには、 、 あるいは   引数を使用します. を使うとそのサービスが正しく機能するために本当に必要なサービスが表示されます. 一方  や   は、そのサービスから使用することができるけれども、正しく機能する上で必要というわけではないサービスを表示します.

同じように、そのサービスを必要としているサービスやそのサービスを使用できるサービス( または  )を問い合わせることもできます:

rc-update
Gentoo の init システムはまずどのサービスを開始する必要があるかを決めるために依存関係ツリーを使用しています. これはユーザーに手動でやってもらうには退屈な作業なので、ランレベルや init スクリプトの管理を簡略化するツールが作成されました.

を使って init スクリプトをランレベルに追加したり削除することができます. ツールはその後自動的に スクリプトを使って依存関係ツリーを再構築します.

サービスの追加と削除
これまでの説明では init スクリプトはすでに "default" ランレベルに追加されていました. "default" の意味するところはこの文書の前の方で説明しました. ランレベルの他に、 スクリプトは動作を定義する第二の引数を必要とします: 、  または   です.

init スクリプトを追加または削除するには、 に  または   引数、その後に init スクリプトとランレベルを渡します. 一例:

コマンドは利用可能なすべての init スクリプトと、それらが実行されるランレベルの一覧を出力します:

を( 引数なしで)実行して有効になっている init スクリプトとそのランレベルのみを表示させることもできます.

追加の設定が必要な理由
init スクリプトはとても複雑です. したがって、ユーザーに init スクリプトを直接編集してもらうのは間違いを起こしやすくなり必ずしも合理的ではありません. しかしながら、サービスを設定できるということは重要です. たとえば、ユーザーがサービス自体により多くのオプションを渡したい場合があるでしょう.

init スクリプトの外部に設定を持つ第二の理由は、ユーザーの設定変更を取り消してしまうおそれなしに init スクリプトを更新できるということです.

conf.d ディレクトリ
Gentoo はこうしたサービスを設定する簡単な方法を提供しています: 設定可能なすべての init スクリプトは にファイルを持ちます. たとえば、 init スクリプトは という設定ファイルを持っており、これには Apache2 サーバーに起動時に渡すオプションを含めることができます:

こうした設定ファイルは( のように)変数のみ を含んでおり、サービスの設定を非常に容易にします. また、これにより変数について(コメントとして)より多くの情報を提供できるようになっています.

initスクリプトを書く
有用な資料として OpenRC の service script guide もあります.

これは必要な作業なんですか？
いいえ、Gentoo は提供しているすべてのサービスについてそのまま使える init スクリプトを提供しているので、通常は init スクリプトを書く必要はありません. しかしながら、一部のユーザーは Portage を使わずにサービスをインストールしているかもしれません. このような場合にはたいてい init スクリプトを作成しなければなりません.

サービスによって提供されている init スクリプトは、明示的に Gentoo 用に書かれているのでなければ使用してはいけません: Gentoo の init スクリプトは他のディストリビューションで使われている init スクリプトとは互換性がありません！ そのディストリビューションが OpenRC を使っているのでない限りは、ということですが！

レイアウト
init スクリプトの基本構造は以下の通りです.

すべての init スクリプトは  関数または   変数を必要とします. それ以外のすべての部分は任意です.

依存関係
init スクリプトの開始や順位付けに影響する、依存関係によく似た3つの設定が定義できます: 、  および   です. さらに、順番に影響する2つのメソッド  と   もあります. 最後の2つは本来依存関係ではありません - 選択されたサービスの開始がスケジュールされていない場合(または開始に失敗した場合)でも、もとの init スクリプトは失敗しないのです.


 * の設定は、このスクリプトが選択されたスクリプトによって提供される機能を使う(use)ものの、それに直接は依存していないことを init システムに対し通知します.  や   が良い例です. これらのサービスが利用可能なら活用しますが、システムにロガーや DNS サーバーがなくてもサービスは動作します. (訳註: use で指定された)サービスが存在する場合、それらはその機能を使用するスクリプトの前に開始されます.
 * の設定は1つの例外を除いて  と同じです.   は init レベルに追加されたサービスのみを考慮します.   は init レベルに追加されていなくても、利用可能なサービスを起動しようとします.
 * は強い依存関係です. つまり、他のスクリプトを必要とする(need)スクリプトはその(訳註: 必要とされている)スクリプトが正常に開始されるより前には開始できません. また、その(訳註: 必要とされている)スクリプトが再起動される場合にはこの(訳註: 必要としている)スクリプトも再起動されます.
 * を使用した場合、そのスクリプトは、選択されたスクリプトが init レベルに含まれていればそれよりも前に起動されます.  を定義している xdm という init スクリプトは、alsasound が同じ init レベルで開始されるようにスケジュールされている場合に限り、alsasound スクリプトよりも前に開始されます. alsasound の開始がスケジュールされていない場合はこの設定には効果がなく、xdm は init システムが最も適切とみなす時に開始されます.
 * 同様に  はそのスクリプトが、選択されたスクリプトが init レベルに含まれている場合にはその後に起動されるべきであることを init システムに対し通知します. 選択されたスクリプトが init レベルに含まれていない場合にはこの設定には効果がなく、そのスクリプトは init システムが最も適切とみなす時に開始されます.

ここから分かるように、 はスクリプトが開始されるかどうかに影響を与えるので、これが唯一の"真の"依存関係の設定です. それ以外はすべて、スクリプトがどのような順番で起動できるか(あるいはされるべきか)を明確にするための init システムに対する助言に過ぎません.

さて、Gentoo で利用可能なたくさんの init スクリプトを見てみると、そのいくつかに init スクリプトでないものへの依存関係があることに気がつきます. これらの"もの"を virtual と呼びます.

virtual 依存は、あるサービスが提供しているものの、そのサービスのみによって提供されているわけではない依存関係です. init スクリプトはシステムロガーに依存することができますが、利用可能なシステムロガーは数多くあります(metalogd、syslog-ng、sysklogd、 ...). スクリプトはこれらのどれか一つを必要とする(need)ことはできません(実用的なシステムにおいて、これらのシステムロガーすべてがインストールされ実行されているということはありません)から、これらのサービスすべてで virtual 依存を必ず提供するようにしています.

一例として、postfix の依存情報を見てみましょう:

表示されているように、postfix サービスは:


 * (virtual) net (これはたとえば によって提供されます)を必要とします.
 * (virtual) logger (これはたとえば によって提供されます)を使用(use)します.
 * (virtual) dns (これはたとえば によって提供されます)を使用(use)します.
 * (virtual) mta (これはすべてのメールサーバーに共通です)を提供します.

順序の制御
前の節で説明しているように、init システムにスクリプトを開始(または停止)するのに使用する順序を指示することができます. この順序は use および need という依存関係の設定を介してだけでなく、before および after という順序の設定によっても扱うことができます. 前者についてはすでに説明しましたから、こうした init スクリプトの例として portmap サービスを見てみましょう.

同じランレベルのすべてのサービスを表す "*" グロブを使うこともできますが、これは推奨されません.

サービスがローカルディスクに書き込む必要があるなら、localmount を need にするべきです. サービスが に pidfile といったものを配置する場合は bootmisc の後(after)に起動すべきです.

標準関数
関数に続いて、 関数も定義する必要があります. これにはサービスを初期化するために必要なすべてのコマンドが含まれています. ユーザーに何が起きているか通知するため  および   関数を使用することをお勧めします:

start と stop 関数では、 と   の両方を使用すべきです. サービスが pidfile を作成しない場合は、それを確かめるためにテストすることが推奨されますが、可能であれば  を使ってください. そうでなければ、pidfile を使用しないようにします. また、start-stop-daemon のオプションに  を追加することもできますが、サービスが極めて詳細な出力をする場合以外にはお勧めしません. はサービスの開始が失敗する場合にデバッグを妨げることがあります.

上の例の中で注目すべきもう一つの設定は RC_CMD 変数の内容のチェックです. 以前の init スクリプトシステムとは異なり、新しい OpenRC システムはスクリプト特有の再起動機能をサポートしていません. 代わりに、スクリプトは関数( や  )が再起動の一環として呼ばれたのかどうか知るために RC_CMD 変数の内容を調べる必要があります.

関数の更なる例については、 ディレクトリーで利用可能な init スクリプトのソースコードを読んでください.

もう一つの定義できる(が必須ではない)関数が  です. init システムは start-stop-daemon が使用されている場合にはこの関数を自身で補うことができます.

サービスが他のスクリプト(たとえば Bash、Python あるいは Perl など)を実行し、かつこのスクリプトの名前が後で変わる場合(たとえば が foo になるなど)には、start-stop-daemon に   を加える必要があります. これにはスクリプトの変更後の名前を指定しなければなりません. この例では、サービスは を実行し、その名前が foo に変わります:

start-stop-daemon は、より多くの情報が必要になった際に利用可能な素晴らしい man ページを備えています:

Gentoo の init スクリプトの文法は POSIX シェルをもとにしているので、init スクリプトの中で sh 互換の構文を使うことができます. Gentoo がもし init システムに変更を加えてもスクリプトが機能し続けるようにするために、それ以外の構文、たとえば bash 特有のものなどは init スクリプトに含めないでください.

カスタムオプションの追加
init スクリプトがこれまでに見たもの以外のオプションをサポートする必要がある場合、そのオプションを以下の変数のうちの一つに追加し、オプションと同名の関数を作成してください. たとえば  というオプションをサポートするには:


 * extra_commands - コマンドはすべての状態のサービスにおいて利用可能です
 * extra_started_commands - コマンドはサービスが開始済み(started)の時に利用可能です.
 * extra_stopped_commands - コマンドはサービスが停止中(stopped)の場合に利用可能です

サービス設定変数
の設定ファイルをサポートするために詳細な実装をする必要はありません: init スクリプトが実行される際には以下のファイルが自動的に読み込まれます(つまり、変数が利用可能になります):



また、init スクリプトが virtual 依存(net など)を提供している場合、その依存と関連付けられているファイル( など)も読み込まれます.

これが役に立つ人
多くのラップトップユーザーはこうした状況を経験したことがあるでしょう: 自宅では net.eth0 を開始する必要があるけれど、移動中は(使えるネットワークがないので) net.eth0 を開始してほしくない. Gentoo ではランレベルの動作を意のままに変更できます.

たとえば、異なる init スクリプトが割り当てられた第二の起動可能な "default" ランレベルを作成することができます. こうすれば、ユーザーはブート時にどのデフォルトランレベルを使用するか選択できます.

softlevel を使う
まず最初に、第二の "default" ランレベル用のランレベルディレクトリーを作成します. 一例として、offline ランレベルを作成します:

新しく作成したランレベルに必要な init スクリプトを追加します. たとえば、net.eth0 以外は現在のデフォルトランレベルを完全にコピーするには:

offline ランレベルから net.eth0 は削除されましたが、それでも udev は自身が検出したすべてのデバイスを開始して適切なサービスを起動しようとするかもしれません. これはホットプラグと呼ばれる機能です. デフォルトでは、Gentoo はホットプラグを有効化していません.

選択したいくつかのスクリプトのみについてホットプラグを有効にするには、 の rc_hotplug 変数を使います:

ブートローダーの設定を編集し、offline ランレベル用の新しい項目を追加します. この項目では、 をブートパラメーターとして追加します.

bootlevel を使う
bootlevel を使用する場合も softlevel とよく似ています. 唯一の違いは、この場合は第二の "default" ランレベルではなく第二の "boot" ランレベルが定義されることです.