ハンドブック:Alpha/ワーキング/Initscripts

From Gentoo Wiki
Jump to: navigation, search
This page is a translated version of the page Handbook:Alpha/Working/Initscripts and the translation is 100% complete.

Other languages:
Deutsch • ‎English • ‎español • ‎français • ‎polski • ‎русский • ‎українська • ‎中文(中国大陆)‎ • ‎日本語 • ‎한국어
Alpha ハンドブック
インストール
インストールについて
メディアの選択
ネットワーク設定
ディスクの準備
stage3のインストール
Gentooベースシステムのインストール
カーネルの設定
システムの設定
ツールのインストール
ブートローダの設定
締めくくり
Gentooの操作
Portageについて
USEフラグ
Portageの機能
Initスクリプトシステム
環境変数
Portageの操作
ファイルとディレクトリ
変数
ソフトウェアブランチの併用
追加ツール
カスタムPortageツリー
高度な機能
ネットワーク設定
はじめに
高度な設定
モジュール式ネットワーク
無線
機能の追加
動的な管理


ランレベル

システムの起動

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

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

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

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

Initscripts

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

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

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

init の仕組み

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

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

FILE /etc/inittab初期化コマンド
si::sysinit:/sbin/openrc sysinit

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

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

FILE /etc/inittabブートコマンドの実行
rc::bootwait:/sbin/openrc boot

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

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

FILE /etc/inittabデフォルトランレベルの選択
id:3:initdefault:

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

FILE /etc/inittabランレベルの定義
l0:0:wait:/sbin/openrc shutdown
l1:S1:wait:/sbin/openrc single
l2:2:wait:/sbin/openrc nonetwork
l3:3:wait:/sbin/openrc default
l4:4:wait:/sbin/openrc default
l5:5:wait:/sbin/openrc default
l6:6:wait:/sbin/openrc reboot

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

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

FILE /etc/inittabターミナルの定義
c1:12345:respawn:/sbin/agetty 38400 tty1 linux
c2:12345:respawn:/sbin/agetty 38400 tty2 linux
c3:12345:respawn:/sbin/agetty 38400 tty3 linux
c4:12345:respawn:/sbin/agetty 38400 tty4 linux
c5:12345:respawn:/sbin/agetty 38400 tty5 linux
c6:12345:respawn:/sbin/agetty 38400 tty6 linux

有効なランレベル

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

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

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

init スクリプトの使い方

openrc プロセスが開始するスクリプトは init スクリプトと呼ばれます。/etc/init.d/ 内の各スクリプトは startstoprestartzapstatusineediuseiwantneedsmeusesme あるいは wantsme という引数で実行することができます。

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

root #/etc/init.d/postfix start
Note
指定されたサービスを必要(need)とするサービスのみが停止または再起動されます。その他の依存サービス(指定されたサービスを使用(use)するが必要(need)としないもの)は影響されません。

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

root #/etc/init.d/postfix --nodeps stop

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

root #/etc/init.d/postfix status

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

root #/etc/init.d/postfix zap

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

root #/etc/init.d/postfix ineed

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

root #/etc/init.d/postfix needsme

ランレベルの更新

rc-update

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

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

サービスの追加と削除

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

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

root #rc-update del postfix default

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

root #rc-update -v show

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

サービスの設定

追加の設定が必要な理由

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

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

conf.d ディレクトリ

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

FILE /etc/conf.d/apache2apache2 init スクリプト用のオプションの例
APACHE2_OPTS="-D PHP5"

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

initスクリプトを書く

これは必要な作業なんですか?

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

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

レイアウト

init スクリプトの基本構造は以下の通りです。

CODE (伝統的な) init スクリプトのレイアウト例
#!/sbin/openrc-run
  
depend() {
#  (依存関係情報)
}
  
start() {
#  (サービスを開始するのに必要なコマンド群)
}
  
stop() {
#  (サービスを止めるのに必要なコマンド群)
}
CODE (更新された)initスクリプトのレイアウト例
#!/sbin/openrc-run
command=/usr/bin/foo
command_args="${foo_args} --bar"
pidfile=/var/run/foo.pid
name="FooBar Daemon"
 
description="FooBar is a daemon that drinks"
extra_started_commands="drink"
description_drink="Opens mouth and reflexively swallows"
 
depend() {
#  (依存関係の情報)
}
 
start_pre() {
#  (サービスを開始する準備に必要なコマンド群)
    # ディレクトリが確実に正しい設定であることを確かめてください
    checkpath --directory --owner foo:foo --mode 0775 \
        /var/run/foo /var/cache/foo
}
  
stop_post() {
#  (サービス後の片付けに必要なコマンド群)
    # 残ったものを片付ける
    rm -rf /var/cache/foo/*
}
 
drink() {
    ebegin "Starting to drink"
    ${command} --drink beer
    eend $? "Failed to drink any beer :("
}

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

依存関係

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

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

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

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

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

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

FILE /etc/init.d/postfixpostfix サービスの依存情報
depend() {
  need net
  use logger dns
  provide mta
}

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

  • (virtual) net (これはたとえば /etc/init.d/net.eth0 によって提供されます)を必要とします。
  • (virtual) logger (これはたとえば /etc/init.d/syslog-ng によって提供されます)を使用(use)します。
  • (virtual) dns (これはたとえば /etc/init.d/named によって提供されます)を使用(use)します。
  • (virtual) mta (これはすべてのメールサーバーに共通です)を提供します。

順序の制御

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

FILE /etc/init.d/portmapportmap サービスの依存情報
depend() {
  need net
  before inetd
  before xinetd
}

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

CODE * グロブの使用
depend() {
  before *
}

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

CODE need localmount、after bootmisc とした依存設定
depend() {
  need localmount
  after bootmisc
}

標準関数

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

CODE start() 関数の例
start() {
  if [ "${RC_CMD}" = "restart" ];
  then
    # Do something in case a restart requires more than stop, start
  fi
  
  ebegin "Starting my_service"
  start-stop-daemon --start --exec /path/to/my_service \
    --pidfile /path/to/my_pidfile
  eend $?
}

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

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

Note
--exec がサービスを実際に起動しており、サービスを起動して終了するシェルスクリプトを単に呼び出しているのではないことを確認してください - それは init スクリプトがすべきことです。

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

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

CODE stop() 関数の例
stop() {
  ebegin "Stopping my_service"
  start-stop-daemon --stop --exec /path/to/my_service \
    --pidfile /path/to/my_pidfile
  eend $?
}

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

CODE foo スクリプトを開始するサービスの定義例
start() {
  ebegin "Starting my_script"
  start-stop-daemon --start --exec /path/to/my_script \
    --pidfile /path/to/my_pidfile --name foo
  eend $?
}

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

user $man start-stop-daemon

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

カスタムオプションの追加

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

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


CODE restartdelay メソッドの定義例
extra_started_commands="restartdelay"
  
restartdelay() {
  stop
  sleep 3    # Wait 3 seconds before starting again
  start
}
Important
OpenRC では restart() 関数を上書きすることはできません!

サービス設定変数

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

  • /etc/conf.d/YOUR_INIT_SCRIPT
  • /etc/conf.d/basic
  • /etc/rc.conf

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

ランレベルの動きを変える

これが役に立つ人

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

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

softlevel を使う

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

root #mkdir /etc/runlevels/offline

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

root #cd /etc/runlevels/default
root #for service in *; do rc-update add $service offline; done
root #rc-update del net.eth0 offline
root #rc-update show offline
(Partial sample Output)
               acpid | offline
          domainname | offline
               local | offline
            net.eth0 |

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

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

FILE /etc/rc.confWLAN インターフェースのホットプラグを有功にする
rc_hotplug="net.wlan !net.*"
Note
デバイスによって開始されるサービスについての詳細は /etc/rc.conf 内のコメントを見てください。

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

bootlevel を使う

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