[ << ]
[ < ]
[ ホーム ]
[ > ]
[ >> ]
4. initスクリプト
目次:
4.a. ランレベル
システムの起動
システムを起動したとき、多くのテキストが画面上を流れることに気がつくでしょう。
よく注意して見ると、このテキストは、システムをリブートするたびに、常に同じであることがわかるでしょう。これらすべてのアクションの進行は、ブートシーケンスと呼ばれ、(ほぼ)静的に定義されます。
最初に、ブートローダが、ブートローダの設定で指定されたカーネルイメージをメモリにロードし、その後、カーネルを実行するようにCPUに命じます。カーネルがロードされ、実行されるときに、カーネルは、カーネル固有の構造とタスク全てを初期化し、initプロセスを起動します。
その後、initプロセスは、(/etc/fstabで指定された)すべてのファイルシステムがマウントされて使用できる準備が整うことを確認します。
次に、/etc/init.dディレクトリにあるいくつかのスクリプトを実行します。それらのスクリプトは、うまくシステムが起動されるように必要なサービスを開始します。
最後に、すべてのスクリプトが実行されたら、initプロセスは、agettyという特別なプロセスを端末(ターミナル)にくっつけて、端末(ほとんどが、Alt-F1、Alt-F2などの下に隠される仮想コンソール)を有効にします。
次に、agettyプロセスは、loginプロセスを実行することで、これらの端末を通してユーザがログインできるようにします。
initスクリプト
ここで、initプロセスは、/etc/init.dディレクトリにあるスクリプトをでたらめに実行するわけではありません。ましてや、/etc/init.dディレクトリにあるスクリプト全てを実行するわけでもありません。
/etc/runlevelsディレクトリを調べて、どのスクリプトを実行するべきかを決めます。
最初に、initプロセスは、/etc/runlevels/bootディレクトリにシンボリックリンクがある/etc/init.dの全てのスクリプトを実行します。通常は、アルファベット順にスクリプトを開始しますが、いくつかのスクリプトは、起動される前に別のスクリプトが実行されなければならないことをシステムに伝える依存情報を持っています。
/etc/runlevels/bootから参照されるすべてのスクリプトが実行されたら、initプロセスは、/etc/runlevels/defaultにシンボリックリンクがあるスクリプトの実行を続けます。
やはり、スクリプトが依存情報を持たない場合は、どのスクリプトを最初に実行するべきかを決めるためにアルファベット順を使用しますが、うまく動作するスタートアップシーケンスを提供するために順番が変更される場合があります。
initプロセスはどのように動作するか
もちろん、initプロセス自身が勝手に全てを決定するわけではありません。
どんなアクションを取ることが必要かを指定する設定ファイルが必要です。
この設定ファイルは、/etc/inittabです。
最初に説明したブートシーケンスを覚えているなら、initプロセスの最初のアクションは、すべてのファイルシステムをマウントすることであることを覚えているでしょう。これは、/etc/inittabに以下のような行で指定されています。
コード表示 1.1: /etc/inittabのシステム初期化を指示する行 |
si::sysinit:/sbin/rc sysinit
|
この行は、initプロセスに、システムを初期化するために/sbin/rc sysinitを実行しなければならないことを伝えています。/sbin/rcスクリプトが初期化を担当するので、initはあまり何もしないじゃないかと思うかもしれません。そうです、別のプロセスにシステムの初期化処理を委譲しています。
次に、initプロセスは、/etc/runlevels/bootにシンボリックリンクがあるスクリプトすべてを実行します。これは、以下の行で指定されます。
コード表示 1.2: システム初期化の続き |
rc::bootwait:/sbin/rc boot
|
ここでもrcスクリプトが必要な処理を実行します。rcに与えられているオプション(boot)は、/etc/runlevelsのサブディレクトリと同じものが使用されていることを覚えておいてください。
ここで、initプロセスは、どのランレベルで実行されるべきかを知るために設定ファイルを調べます。これを決めるために、/etc/inittabの以下の行を読みます。
コード表示 1.3: initdefault行 |
id:3:initdefault:
|
この場合(Gentooユーザの大多数が使用する)、ランレベルidは3です。
この情報を使って、initはランレベル3を開始するために、何を実行しなければならないかを調べます。
コード表示 1.4: ランレベルの定義 |
l0:0:wait:/sbin/rc shutdown
l1:S1:wait:/sbin/rc single
l2:2:wait:/sbin/rc nonetwork
l3:3:wait:/sbin/rc default
l4:4:wait:/sbin/rc default
l5:5:wait:/sbin/rc default
l6:6:wait:/sbin/rc reboot
|
レベル3を指定する行は、やはり、サービスを起動するためにrcスクリプトを使用します(ここでは、defaultの引数を渡す)。
ここでも、rcの引数が、/etc/runlevelsのサブディレクトリと同じであることを覚えておいてください。
rcが完了したら、initプロセスは、以下のように、どの仮想コンソールを有効にすべきで、何のコマンドがそれぞれのコンソールで実行されなければならないかを決定します。
コード表示 1.5: 仮想コンソールの定義 |
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プロセスがどのランレベルを有効にすべきかを決めるために、番号付け体系を使用することを見ました。ランレベルは、システムの実行状態であり、ランレベルに入ったりランレベルから抜けたりするときに実行されるべきスクリプト(runlevel scriptsもしくは、initscripts)のコレクションを意味します。
Gentooでは、7つのランレベルが定義されています。そのうちの3つは、システム内部で使用されるランレベルで、あとの4つは、ユーザ定義のランレベルです。内部で使用されるランレベルは、sysinitとshutdownとrebootで、その名が示すとおりのことを適切に行います。sysinitは、システムを初期化し、shutdownは、システムを停止し、rebootは、システムのリブートを行います。
ユーザ定義のランレベルは、/etc/runlevelsに属するサブディレクトリを指します。そのサブディレクトリには、bootとdefaultとnonetworkとsingleがあります。bootランレベルは、他のすべてのランレベルが使用する、システムに必要なすべてのサービスを開始します。残りの3つのランレベルには、何のサービスを開始するかの違いがあります。
defaultは、日常の業務のために使用されます。nonetworkはネットワーク接続が必要でない場合に使用されます。singleは、システムを修復しなければならない場合に使用されます。
Initスクリプトを使いこなす
rcプロセスが起動するスクリプトは、initスクリプトと呼ばれます。
/etc/init.dディレクトリにある各スクリプトは、次の引数を伴って実行することができます。start、stop、restart、pause、zap、status、ineed、iuse、needsme、usesme、broken。
サービス(とそれに依存するすべてのサービス)を開始、停止、再スタートするために、それぞれstart、stop、restart引数が次のように使用されるでしょう。
コード表示 1.6: postfixの起動 |
# /etc/init.d/postfix start
|
注意:
指定されたサービスをneed(必要)するサービスだけが、停止されるか再スタートされます。別の依存(use(使用)であるが、need(必要)ではない)サービスは、何もされないままです。
|
サービスを停止したいが、それに依存するサービスは停止したくない場合、以下のようにpause引数を使用します。
コード表示 1.7: postfixを停止するが、依存するサービスは実行したままにする |
# /etc/init.d/postfix pause
|
サービスの状態(started、stopped、paused、...)を見たいなら、以下のようにstatus引数を使用します。
コード表示 1.8: postfixの状態を見る |
# /etc/init.d/postfix status
|
実際にはサービスが停止しているのが分かっているのに、起動中と表示される場合、以下のようにzap引数で"停止"状態に修正します。
コード表示 1.9: postfixの状態の修正 |
# /etc/init.d/postfix zap
|
サービスが持つ依存には何があるかを問い合わせるには、iuseかineedを使用します。ineedでは、対象のサービスが正しく機能するために実際に必要なサービスを見ることができます。一方、iuseは、サービスが正しく機能するために必須ではないが、サービスによって使用される可能性のあるサービスを表示します。
コード表示 1.10: postfixが依存する必要なサービスのすべてを表示する要求 |
# /etc/init.d/postfix ineed
|
同様に、どのサービスが対象のサービスを要求するか(needsme)、もしくは、使用するか(usesme)を問い合わせることができます。
コード表示 1.11: postfixを必要とするすべてのサービスを表示する要求 |
# /etc/init.d/postfix needsme
|
最後に、サービスが必要としていても存在しないものを、以下のように問い合わせることができます。
コード表示 1.12: postfixの依存しているものの中で、存在しないものを表示する要求 |
# /etc/init.d/postfix broken
|
4.b. rc-updateを使いこなす
rc-updateって何?
Gentooのinitシステムは、最初に起動される必要があるサービスが何であるかを決定するために、依存性ツリーを使用します。依存性ツリーの管理作業は、ユーザに手動でさせたいとは思わない退屈なものなので、ランレベルとinitスクリプトの管理を簡単にするツールを作成しました。
rc-updateを使用して、ランレベルにinitスクリプトを追加したり、削除したりできます。rc-updateツールは、その後、依存性ツリーを再構築するためにdepscan.shスクリプトを自動で呼び出します。
サービスの追加と削除
Gentooをインストールする間に、既に"default"ランレベルにinitスクリプトを追加しています。そのときには"default"が何のためにあるかということを知らなかったかもしれませんが、今は知っておくべきです。rc-updateスクリプトは、何を実行するかを指定する別の引数を必要とします。それは、addかdelかshowです。
initスクリプトを追加または、削除するには、rc-updateにaddまたは、del引数を渡し、initスクリプトとランレベルが後ろに続きます。例えば、以下のようにします。
コード表示 2.1: defaultランレベルからpostfixを削除する |
# rc-update del postfix default
|
rc-update -v showコマンドは、すべての利用可能なinitスクリプトとそれがどのランレベルで実行されるかを表示します。
コード表示 2.2: initスクリプトの情報を参照する |
# rc-update -v show
|
(-vなしで)rc-update showを実行し、有効なinitスクリプトとそれらのランレベルをみることができます。
4.c. サービスの設定
なぜ追加の設定が必要ですか?
initスクリプトは、極めて複雑になる可能性があります。そのため、initスクリプトをユーザーが直接編集することは、間違い起こしやすいので良くありません。しかし、そのようなサービスを設定できることは重要です。例えば、サービスに追加のオプションを足したいと思うかもしれません。
設定をinitスクリプトの外側に設ける別の理由として、変更した設定が無効になってしまうという心配をせずにinitスクリプトの上書きができるということがあります。
/etc/conf.dディレクトリ
Gentooはそのようなサービスを設定する簡単な方法を提供します。設定可能なinitスクリプトのすべてが、/etc/conf.dディレクトリにファイルを設けています。例えば、apache2のinitスクリプト(/etc/init.d/apache2)には、/etc/conf.d/apache2という設定ファイルがあります。設定ファイルには、起動されるときにApache 2サーバに与えたいオプションを含めることができます。
コード表示 3.1: /etc/conf.d/apache2に定義される変数 |
APACHE2_OPTS="-D PHP5"
|
このような設定ファイルには、サービスを非常に簡単に設定し易くする変数や変数単体(/etc/make.confのような)が記述されています。変数に関するより詳しい情報も(コメントとして)提供されます。
4.d. initスクリプトの記述
記述しなければならないですか?
いいえ。Gentooは、提供されるサービスすべてに対して、すぐに使用できるinitスクリプトを提供するので、通常は、initスクリプトを記述する必要はありません。しかし、あなたは、Portageを使用しないで、サービスをインストールしているかもしれません。その場合、おそらくinitスクリプトを作成しなければならないでしょう。
サービスによって提供されるinitスクリプトは、Gentoo用に適切に書かれていないなら、使用してはいけません。Gentooのinitスクリプトは、他のディストリビューションによって使用されるinitスクリプトとは、互換性がありません。
レイアウト
initスクリプトの基本レイアウトを、以下に示します。
コード表示 4.1: initスクリプトの基本レイアウト |
#!/sbin/runscript
depend() {
}
start() {
}
stop() {
}
restart() {
}
|
initスクリプトではstart()関数が定義されていることが必須です。他のすべてのセクションは、定義してもしなくてもよいです。
依存関係
二つの依存関係が指定可能です。それは、useと、needです。
前に述べたように、need依存は、use依存より制約が強いです。
依存タイプ(needかuse)の後に、依存するサービスか、virtual依存を記述します。
virtual依存とは、あるサービスが提供する依存関係ですが、そのサービスだけが提供するものではありません。たとえば、あるinitスクリプトがシステムロガーに依存するとします。しかし、たくさんのシステムロガー(metalogd、syslog-ng、sysklogd等々)が存在しているので、その中の一つのシステムロガーだけにneed依存することはできません(また、すべてのシステムロガーをインストールして、実行することのもナンセンスです)。このような場合、すべてのシステムロガーがvirutal依存関係をprovide(提供)するようにします。
postfixサービスの依存情報を見てみましょう。
コード表示 4.2: postfixの依存情報 |
depend() {
need net
use logger dns
provide mta
}
|
見たとおり、postfixサービスには以下のような依存情報があります。
-
(virtual)依存のnet(例えば、/etc/init.d/net.eth0によってprovide(提供)されます)を要求します
-
(virtual)依存のlogger(例えば、/etc/init.d/syslog-ngによってprovide(提供)されます)を使用します
-
(virtual)依存のdns(例えば、/etc/init.d/namedによってprovide(提供)されます)を使用します
-
(virtual)依存のmta(すべてのメールサービスに共通です)をprovide(提供)します
順番の制御
場合によっては、別のサービスを要求はしないが、もしシステムに存在し(注意: この条件は依存ではありません)、かつ、同一ランレベルで実行する(注意:この条件は同一ランレベルのサービスだけが対象です)別のサービスのbefore(前に)(もしくは、after(後に))開始したいサービスがあるでしょう。
例として、portmapサービスの設定を見てみましょう。
コード表示 4.3: portmapサービスのdepend()関数 |
depend() {
need net
before inetd
before xinetd
}
|
お勧めはしませんが、同一ランレベルのすべてのサービスにあてはまる"*"を使用することもできます。
コード表示 4.4: ランレベル内の最初のスクリプトとしてこのinitスクリプトを実行する |
depend() {
before *
}
|
もし、サービスがローカルディスクに書き込みをしなければならないものであれば、
localmountが必要となります。
もし、/var/run にpidファイルのように何か書き込むのであれば、
bootmiscのあとに開始されなければいけません。
コード表示 4.5: Example depend() function |
depend() {
need localmount
after bootmisc
}
|
標準関数
depend()関数の次に、さらにstart()関数を定義する必要があります。
この関数には、あなたのサービスを初期化するために必要なすべてのコマンドを入れます。何がなされているかをユーザに知らせるために、以下のようにebeginとeend関数を使用することが望ましいです。
コード表示 4.6: start()関数の例 |
start() {
ebegin "Starting my_service"
start-stop-daemon --start --exec /path/to/my_service \
--pidfile /path/to/my_pidfile
eend $?
}
|
--exec と --pidfile の両方がstart, stop関数のなかで必要です。
もしサービスがpidファイルを作らないならば、
できる限り--make-pidfileを使ってください。
ただし、テストをして確認してください。
そうでなければ、pidファイルを使用しないでください。
--quietをstart-stop-daemonオプションに加えることもできますが、
これは、サービスがかなり冗長なメッセージを出さない限りおすすめできません。
--quietを使うことで、サービス開始に失敗した際のデバッグが困難になるかもしれません。
注意:
--exec が、サービスを呼び出したり停止するシェルスクリプトではなく(これはinitスクリプトがサポートする事柄です)、実際にサービスを呼び出すようにしてください。
|
start()関数のより多くの例が必要なら、/etc/init.dディレクトリにある利用可能なinitスクリプトのソースコードを見てください。
定義可能な他の関数には、stop()とrestart()があります。
これらの関数を定義することは強制されません! Gentooのinitシステムは、start-stop-daemonを使用する場合には、自動的にinitシステム自身がこれらの関数を適切に処理します。
とはいうものの、stop()関数を作らなくてよい程度のものなので、
ここで、例を挙げます
コード表示 4.7: 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に)ならば、--nameをstart-stop-daemonに追加する必要があるでしょう。スクリプトの名前がどう変わるのか指定する必要があります。
この例では、サービスがfoo.pyを起動し、そしてこの名前がfooに変わります。
コード表示 4.8: 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ページが以下のようにして利用可能です。
コード表示 4.9: start-stop-daemonコマンドのmanページを参照する |
$ man start-stop-daemon
|
Gentooのinitスクリプトの構文は、Bourne Again シェル(bash)準拠です。
よって、initスクリプトでは、bash構文のスクリプトを自由に使用することができますが、
POSIX仕様に準拠したスクリプトを書くようにしましょう。将来のinitスクリプトのシステムは、
/bin/shからのシンボリックリンクがbash以外のシェルを指すことを許可するかもしれません。
この場合、bash特有の特徴に依存するinitスクリプトは、設定ファイルを壊し問題になります。
特別なオプションの追加
initスクリプトに、既に説明したもの以外に追加のオプションをサポートさせたいなら、opts変数にオプションを追加して、オプションと同じ名前を持つ関数を作成しなければなりません。例えば、restartdelayというオプションをサポートするには、以下のようにします。
コード表示 4.10: restartdelayオプションのサポート |
opts="${opts} restartdelay"
restartdelay() {
stop
sleep 3
start
}
|
サービス設定変数
/etc/conf.dの設定ファイルをサポートするのに必要なことは、何もありません。あなたのinitスクリプトが実行される場合、自動的に以下のファイルは読み込まれます。(すなわち、変数が利用可能です)
- /etc/conf.d/<あなたのinitスクリプト>
- /etc/conf.d/basic
- /etc/rc.conf
さらに、あなたのinitスクリプトが(netのような)virtual依存を提供するなら、その依存に関連するファイル(/etc/conf.d/netのような)もsourceされるでしょう。
4.e. ランレベルの動作を変更する
これをすることでどんな人が恩恵を受けますか?
多くのラップトップユーザは、"家ではnet.eth0を開始する必要があるが、外出先(ネットワークが利用可能な場所ではないので)ではnet.eth0を開始したくない。"という状況を理解できるでしょう。
Gentooではあなたのしたいようにランレベルの動作を変更できます。
例えば、別のinitスクリプトが割り当てられてブートする、2つ目の"default"ランレベルを作成できます。その後、使用したいdefaultランレベルがどれかをブート時に選択できます。
softlevelの使用
何はさておき、別の"default"ランレベルのためのランレベルディレクトリを作成してください。例として、offlineランレベルを以下のように作成します。
コード表示 5.1: ランレベルディレクトリの作成 |
# mkdir /etc/runlevels/offline
|
新しく作成したランレベルに必要なinitスクリプトを追加してください。例えば、net.eth0を除いた現在のdefaultランレベルの完全なコピーをしたいなら、以下のようにしてください。
コード表示 5.2: 必要なinitスクリプトの追加 |
# cd /etc/runlevels/default
# for service in *; do rc-update add $service offline; done
# rc-update del net.eth0 offline
# rc-update show offline
acpid | offline
domainname | offline
local | offline
net.eth0 |
|
たとえばnet.eth0をofflineランレベルから削除した場合でも、
udevは適当なサービスを検知、開始しするすべてのデバイスを起動しようとします。
そのため、開始する必要のないネットワークサービスを(udevによって開始される他デバイスに対するサービスも同様に)/etc/conf.dに付け加える必要があります。
コード表示 5.3: /etc/conf.d/rc内でサービスを開始するデバイスを無効にする |
RC_COLDPLUG="yes"
RC_PLUG_SERVICES="!net.eth0"
|
注意:
For more information on device initiated services, please see the comments
inside /etc/conf.d/rc.
|
ここで、ブートローダの設定を編集して、offlineランレベルのための新しいエントリを追加してください。例えば、/boot/grub/grub.confでは、以下のようになります。
コード表示 5.4: offlineランレベルのためのエントリ追加 |
title Gentoo Linux Offline Usage
root (hd0,0)
kernel (hd0,0)/kernel-2.4.25 root=/dev/hda3 softlevel=offline
|
ほら、もう全てが設定されました。システムをブートしてブート時に新しく追加されたエントリを選択すれば、offlineランレベルは、defaultランレベルの代わりに使用されます。
bootlevelの使用
bootlevelの使用は、まったくもってsoftlevelに類似しています。ここでのただ一つの違いは、別の"default"ランレベルを定義する代わりに、別の"boot"ランレベルを定義するということです。
[ << ]
[ < ]
[ ホーム ]
[ > ]
[ >> ]
このドキュメントの内容は、他のものが明示されない限りは、
CC-BY-SA-2.5ライセンスです。
Gentoo Name and Logo Usage Guidelines (日本語訳)が適用されます。
|