Gentoo Logo

1.  ランレベル

システムの起動

システムを起動したとき、多くのテキストが画面上を流れることに気がつくでしょう。 よく注意して見ると、このテキストは、システムをリブートするたびに、常に同じであることがわかるでしょう。これらすべてのアクションの進行は、ブートシーケンスと呼ばれ、(ほぼ)静的に定義されます。

最初に、ブートローダが、ブートローダの設定で指定されたカーネルイメージをメモリにロードし、その後、カーネルを実行するようにCPUに命じます。カーネルがロードされ、実行されるときに、カーネルは、カーネル固有の構造とタスク全てを初期化し、initプロセスを起動します。

その後、initプロセスは、(/etc/fstabで指定された)すべてのファイルシステムがマウントされて使用できる準備が整うことを確認します。 次に、/etc/init.dディレクトリにあるいくつかのスクリプトを実行します。それらのスクリプトは、うまくシステムが起動されるように必要なサービスを開始します。

最後に、すべてのスクリプトが実行されたら、initプロセスは、agettyという特別なプロセスを端末(ターミナル)にくっつけて、端末(ほとんどが、Alt-F1Alt-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.1: システム初期化の続き

rc::bootwait:/sbin/rc boot

ここでもrcスクリプトが必要な処理を実行します。rcに与えられているオプション(boot)は、/etc/runlevelsのサブディレクトリと同じものが使用されていることを覚えておいてください。

ここで、initプロセスは、どのランレベルで実行されるべきかを知るために設定ファイルを調べます。これを決めるために、/etc/inittabの以下の行を読みます。

コード表示 1.1: initdefault行

id:3:initdefault:

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

コード表示 1.1: ランレベルの定義

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.1: 仮想コンソールの定義

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つは、ユーザ定義のランレベルです。内部で使用されるランレベルは、sysinitshutdownrebootで、その名が示すとおりのことを適切に行います。sysinitは、システムを初期化し、shutdownは、システムを停止し、rebootは、システムのリブートを行います。

ユーザ定義のランレベルは、/etc/runlevelsに属するサブディレクトリを指します。そのサブディレクトリには、bootdefaultnonetworksingleがあります。bootランレベルは、他のすべてのランレベルが使用する、システムに必要なすべてのサービスを開始します。残りの3つのランレベルには、何のサービスを開始するかの違いがあります。 defaultは、日常の業務のために使用されます。nonetworkはネットワーク接続が必要でない場合に使用されます。singleは、システムを修復しなければならない場合に使用されます。

Initスクリプトを使いこなす

rcプロセスが起動するスクリプトは、initスクリプトと呼ばれます。 /etc/init.dディレクトリにある各スクリプトは、次の引数を伴って実行することができます。startstoprestartpausezapstatusineediuseneedsmeusesmebroken

サービス(とそれに依存するすべてのサービス)を開始、停止、再スタートするために、それぞれstartstoprestart引数が次のように使用されるでしょう。

コード表示 1.1: postfixの起動

# /etc/init.d/postfix start

注意: 指定されたサービスをneed(必要)するサービスだけが、停止されるか再スタートされます。別の依存(use(使用)であるが、need(必要)ではない)サービスは、何もされないままです。

サービスを停止したいが、それに依存するサービスは停止したくない場合、以下のようにpause引数を使用します。

コード表示 1.1: postfixを停止するが、依存するサービスは実行したままにする

# /etc/init.d/postfix pause

サービスの状態(started、stopped、paused、...)を見たいなら、以下のようにstatus引数を使用します。

コード表示 1.1: postfixの状態を見る

# /etc/init.d/postfix status

実際にはサービスが停止しているのが分かっているのに、起動中と表示される場合、以下のようにzap引数で"停止"状態に修正します。

コード表示 1.1: postfixの状態の修正

# /etc/init.d/postfix zap

サービスが持つ依存には何があるかを問い合わせるには、iuseineedを使用します。ineedでは、対象のサービスが正しく機能するために実際に必要なサービスを見ることができます。一方、iuseは、サービスが正しく機能するために必須ではないが、サービスによって使用される可能性のあるサービスを表示します。

コード表示 1.1: postfixが依存する必要なサービスのすべてを表示する要求

# /etc/init.d/postfix ineed

同様に、どのサービスが対象のサービスを要求するか(needsme)、もしくは、使用するか(usesme)を問い合わせることができます。

コード表示 1.1: postfixを必要とするすべてのサービスを表示する要求

# /etc/init.d/postfix needsme

最後に、サービスが必要としていても存在しないものを、以下のように問い合わせることができます。

コード表示 1.1: postfixの依存しているものの中で、存在しないものを表示する要求

# /etc/init.d/postfix broken

1.  rc-updateを使いこなす

rc-updateって何?

Gentooのinitシステムは、最初に起動される必要があるサービスが何であるかを決定するために、依存性ツリーを使用します。依存性ツリーの管理作業は、ユーザに手動でさせたいとは思わない退屈なものなので、ランレベルとinitスクリプトの管理を簡単にするツールを作成しました。

rc-updateを使用して、ランレベルにinitスクリプトを追加したり、削除したりできます。rc-updateツールは、その後、依存性ツリーを再構築するためにdepscan.shスクリプトを自動で呼び出します。

サービスの追加と削除

Gentooをインストールする間に、既に"default"ランレベルにinitスクリプトを追加しています。そのときには"default"が何のためにあるかということを知らなかったかもしれませんが、今は知っておくべきです。rc-updateスクリプトは、何を実行するかを指定する別の引数を必要とします。それは、adddelshowです。

initスクリプトを追加または、削除するには、rc-updateaddまたは、del引数を渡し、initスクリプトとランレベルが後ろに続きます。例えば、以下のようにします。

コード表示 1.1: defaultランレベルからpostfixを削除する

# rc-update del postfix default

rc-update -v showコマンドは、すべての利用可能なinitスクリプトとそれがどのランレベルで実行されるかを表示します。

コード表示 1.1: initスクリプトの情報を参照する

# rc-update -v show

(-vなしで)rc-update showを実行し、有効なinitスクリプトとそれらのランレベルをみることができます。

1.  サービスの設定

なぜ追加の設定が必要ですか?

initスクリプトは、極めて複雑になる可能性があります。そのため、initスクリプトをユーザーが直接編集することは、間違い起こしやすいので良くありません。しかし、そのようなサービスを設定できることは重要です。例えば、サービスに追加のオプションを足したいと思うかもしれません。

設定をinitスクリプトの外側に設ける別の理由として、変更した設定が無効になってしまうという心配をせずにinitスクリプトの上書きができるということがあります。

/etc/conf.dディレクトリ

Gentooはそのようなサービスを設定する簡単な方法を提供します。設定可能なinitスクリプトのすべてが、/etc/conf.dディレクトリにファイルを設けています。例えば、apache2のinitスクリプト(/etc/init.d/apache2)には、/etc/conf.d/apache2という設定ファイルがあります。設定ファイルには、起動されるときにApache 2サーバに与えたいオプションを含めることができます。

コード表示 1.1: /etc/conf.d/apache2に定義される変数

APACHE2_OPTS="-D PHP5"

このような設定ファイルには、サービスを非常に簡単に設定し易くする変数や変数単体(/etc/make.confのような)が記述されています。変数に関するより詳しい情報も(コメントとして)提供されます。

1.  initスクリプトの記述

記述しなければならないですか?

いいえ。Gentooは、提供されるサービスすべてに対して、すぐに使用できるinitスクリプトを提供するので、通常は、initスクリプトを記述する必要はありません。しかし、あなたは、Portageを使用しないで、サービスをインストールしているかもしれません。その場合、おそらくinitスクリプトを作成しなければならないでしょう。

サービスによって提供されるinitスクリプトは、Gentoo用に適切に書かれていないなら、使用してはいけません。Gentooのinitスクリプトは、他のディストリビューションによって使用されるinitスクリプトとは、互換性がありません。

レイアウト

initスクリプトの基本レイアウトを、以下に示します。

コード表示 1.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サービスの依存情報を見てみましょう。

コード表示 1.1: 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サービスの設定を見てみましょう。

コード表示 1.1: portmapサービスのdepend()関数

depend() {
  need net
  before inetd
  before xinetd
}

お勧めはしませんが、同一ランレベルのすべてのサービスにあてはまる"*"を使用することもできます。

コード表示 1.1: ランレベル内の最初のスクリプトとしてこのinitスクリプトを実行する

depend() {
  before *
}

もし、サービスがローカルディスクに書き込みをしなければならないものであれば、 localmountが必要となります。 もし、/var/run にpidファイルのように何か書き込むのであれば、 bootmiscのあとに開始されなければいけません。

コード表示 1.1: Example depend() function

depend() {
  need localmount
  after bootmisc
}

標準関数

depend()関数の次に、さらにstart()関数を定義する必要があります。 この関数には、あなたのサービスを初期化するために必要なすべてのコマンドを入れます。何がなされているかをユーザに知らせるために、以下のようにebegineend関数を使用することが望ましいです。

コード表示 1.1: 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ファイルを使用しないでください。 --quietstart-stop-daemonオプションに加えることもできますが、 これは、サービスがかなり冗長なメッセージを出さない限りおすすめできません。 --quietを使うことで、サービス開始に失敗した際のデバッグが困難になるかもしれません。

注意: --exec が、サービスを呼び出したり停止するシェルスクリプトではなく(これはinitスクリプトがサポートする事柄です)、実際にサービスを呼び出すようにしてください。

start()関数のより多くの例が必要なら、/etc/init.dディレクトリにある利用可能なinitスクリプトのソースコードを見てください。

定義可能な他の関数には、stop()restart()があります。 これらの関数を定義することは強制されません! Gentooのinitシステムは、start-stop-daemonを使用する場合には、自動的にinitシステム自身がこれらの関数を適切に処理します。

とはいうものの、stop()関数を作らなくてよい程度のものなので、 ここで、例を挙げます

コード表示 1.1: 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.pyfooに)ならば、--namestart-stop-daemonに追加する必要があるでしょう。スクリプトの名前がどう変わるのか指定する必要があります。 この例では、サービスがfoo.pyを起動し、そしてこの名前がfooに変わります。

コード表示 1.1: 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ページが以下のようにして利用可能です。

コード表示 1.1: 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というオプションをサポートするには、以下のようにします。

コード表示 1.1: restartdelayオプションのサポート

opts="${opts} restartdelay"

restartdelay() {
  stop
  sleep 3    # Wait 3 seconds before starting again
  start
}

サービス設定変数

/etc/conf.dの設定ファイルをサポートするのに必要なことは、何もありません。あなたのinitスクリプトが実行される場合、自動的に以下のファイルは読み込まれます。(すなわち、変数が利用可能です)

  • /etc/conf.d/<あなたのinitスクリプト>
  • /etc/conf.d/basic
  • /etc/rc.conf

さらに、あなたのinitスクリプトが(netのような)virtual依存を提供するなら、その依存に関連するファイル(/etc/conf.d/netのような)もsourceされるでしょう。

1.  ランレベルの動作を変更する

これをすることでどんな人が恩恵を受けますか?

多くのラップトップユーザは、"家ではnet.eth0を開始する必要があるが、外出先(ネットワークが利用可能な場所ではないので)ではnet.eth0を開始したくない。"という状況を理解できるでしょう。 Gentooではあなたのしたいようにランレベルの動作を変更できます。

例えば、別のinitスクリプトが割り当てられてブートする、2つ目の"default"ランレベルを作成できます。その後、使用したいdefaultランレベルがどれかをブート時に選択できます。

softlevelの使用

何はさておき、別の"default"ランレベルのためのランレベルディレクトリを作成してください。例として、offlineランレベルを以下のように作成します。

コード表示 1.1: ランレベルディレクトリの作成

# mkdir /etc/runlevels/offline

新しく作成したランレベルに必要なinitスクリプトを追加してください。例えば、net.eth0を除いた現在のdefaultランレベルの完全なコピーをしたいなら、以下のようにしてください。

コード表示 1.1: 必要なinitスクリプトの追加

(offlineランレベルにdefaultランレベルからすべてのサービスをコピーします)
# cd /etc/runlevels/default
# for service in *; do rc-update add $service offline; done
(offlineランベルから不必要なサービスを削除します)
# rc-update del net.eth0 offline
(offlineランレベルで有効なサービスを表示します)
# rc-update show offline
(出力結果例、抜粋)
               acpid | offline
          domainname | offline
               local | offline
            net.eth0 |

たとえばnet.eth0をofflineランレベルから削除した場合でも、 udevは適当なサービスを検知、開始しするすべてのデバイスを起動しようとします。 そのため、開始する必要のないネットワークサービスを(udevによって開始される他デバイスに対するサービスも同様に)/etc/conf.dに付け加える必要があります。

コード表示 1.1: /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では、以下のようになります。

コード表示 1.1: 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"ランレベルを定義するということです。

ページの更新日 2011年 3月 2日

このドキュメントのオリジナルバージョン の更新日は2011年 9月 17日

要約: Gentoo では、ほかの特徴にくわえて、依存関係に従った実行順の決定と仮想的なinitスクリプトが可能となる特別なinitスクリプト形式を採用しています。この章では、こうした特徴をすべて説明し、これらのスクリプトをどのように扱うのかを説明します。

Donate to support our development efforts.

Copyright 2001-2012 Gentoo Foundation, Inc. Questions, Comments? Contact us.