起動スクリプトを知って基礎を理解しよう〜FreeBSD/Solaris編〜

 いちばん近道なLinuxマスター術
連載第1回目では,Linuxの起動プロセスを紹介した。今回は,FreeBSDとSolarisの起動プロセスを解説しよう。UNIXは起動プロセスを知ってこそ,基礎が理解できることを忘れないでほしい。FreeBSD,Solaris共にLinuxの起動プロセスとの共通点はあるものの,それぞれ特有の部分も多いのだ。


起動スクリプトを知って基礎を理解しよう〜FreeBSD/Solaris編〜

 起動プロセスはFreeBSDやSolarisであっても,Linuxと同じくinitがいちばん最初に起動される。今回は,2つのOSでの処理内容を紹介していこう。まず最初はFreeBSDの起動処理パターンだ。

  1. /kernelを実行
  2. /sbin/initを実行
  3. /etc/rcを実行
  4. /etc/ttysを実行

 FreeBSDは,initの最後に「/etc/rc」というファイル名のシェルスクリプトを実行する。このrcスクリプトに記述された順番に起動処理が行われるのだ。rcスクリプトの処理が終わると,「/etc/ttys」スクリプトを実行し,「login:」というログインプロンプトを表示してユーザーのログイン待ち状態になる。FreeBSDでは,ほとんどの起動処理がrcスクリプトの中で行われることを覚えておこう。

 どのような初期化を行うかは,rcスクリプトの最初で読み込む/etc/rc.confによって設定する。このファイル内に設定を記述することにより,特定のプログラムを起動させることが可能だ。このため,rc.confファイルは管理者がもっともよく知らなければならないファイルの1つといえる。

 rcスクリプトの処理プロセスを具体的に追っていこう。rcスクリプトでは,おもに次のような処理が順番に行われている。ただし,例として挙げている内容のため,SendmailなどのMTAは,インストール環境によって異なるため注意が必要だ。

icon /etc/rcスクリプトの処理内容を理解しよう

PATH の設定 内 容
/etc/rc.diskless1 の実行 ディスクレスブートの際の設定
/etc/rc.conf の読み込み 設定項目の読み込み
ファイルシステムのマウント fstab の内容にそってディスクをマウント
adjkerntz の実行  
/var の中を削除 一時ファイルを削除
/etc/rc.sysctl を実行  
/etc/rc.serial を実行 シリアルの設定を行う
/etc/rc.pccard を実行 PCカードサービスを起動する
/etc/rc.network を実行 ネットワークサービスを開始する
/tmp の中を削除 一時ファイルを削除
syslogd を実行 syslog を起動する
quota の有効化 quota を有効にする
inetd の実行 inetd を起動する
cron の実行 cron を起動する
lpd の実行 lpd を起動する
sendmail の実行 sendmail を起動する
usbd の実行 usbd を起動する
/etc/rc.i386 の実行 アーキテクチャ依存(APMなど)の設定を行う
/etc/rc.devfs の実行 devfs の設定を行う
rc.d の実行 /usr/local/etc/rc.d
/usr/X11R6/etc/rc.d の中にある *.sh スクリプトを実行
/etc/rc.local の実行 独自の設定を行う

icon rc.confのオプションを理解しよう

rc スクリプトでは、各種の外部スクリプトを呼ぶことによって rc スクリプトそのものを編集する必要を極力減らしている。

 rc.confは,/etc/または/etc/default/ディレクトリに置かれている。ただし,/etc/default/の方が先に読み込まれる。ファイル内容を変更する場合には,変更するものだけ,もしくは標準のrc.confを/etcディレクトリにコピーしてから編集するようにしたい。

icon 起動処理を付け加えてみよう

 次に独自に処理を追加する方法を解説しよう。ここでは,例としてhttpサーバのApacheを自分でインストールして起動スクリプトを追加する手順を見る。Apacheのインストール先は,/usr/local/apacheディレクトリだ。

 Apacheの起動スクリプト例は,次の通りだ。

#!/bin/sh
APACHE=/usr/local/apache
if [ -x $APACHE/bin/httpd -a -x $APACHE/bin/apachectl ]; then
        $APACHE/bin/apachectl start
        echo -n 'apache '
fi

 次にこのスクリプトを apache.sh というファイル名で,/usr/local/etc/rc.dディレクトリに保存する。ファイルのパーミッションは,必ず755に設定しておくことを忘れずに。

# cp apache.sh /usr/local/etc/rc.d
# cd /usr/local/etc/rc.d
# chmod 755 apache.sh

 これで,次回のマシン起動時から自動的に実行されるようになる。これは,先に紹介したrcスクリプトの中で,/etc/rc.d や/usr/local/etc/rc.dディレクトリの中の「*.sh」スクリプトを自動的に実行するようになっているからである。

icon シャットダウン時のスクリプト/etc/rc.shutdown

 このように,独自に追加したサーバの自動起動は /etc/rc.dディレクトリ,あるいは/usr/local/etc/rc.dディレクトリに起動用シェルスクリプトを作成しておくのだ。

 マシンをシャットダウンする際に何らかの特定の終了処理を行わなければならないような場合もあるだろう。こんな時は,起動スクリプトを設置するだけでは不十分である。そのような場合には,/etc/rc.shutdownファイルのスクリプトの中で,終了のための処理ファイルを別に呼び出すようにする。

リスト
別ウィンドウで見る or 03a2.txt

 例えば,Apacheの場合には,「Insert shutdown procedures here」という記述の後に,次のように追加しよう。このように,FreeBSDではRedHat Linuxなどと比べて比較的シンプルに設定を行うことが可能である。

echo -n Shutting down daemon processes: 
# Insert shutdown procedures here
/usr/local/apache/bin/apachectl stop


icon サーバ起動以外の処理はrc.localで行おう

 ここまでに紹介したように/etc/rc.dや, /usr/local/etc/rc.d に置かれた *.sh スクリプトは無条件に実行される。サーバの起動であってもその他の処理であってもまったく同じように起動時に実行することができるのだ。

 しかし,ちょっとしたコマンドの実行などで,専用スクリプトを用意するまでもないという場合もあるだろう。そのような場合には,/etc/rc.localスクリプトに記述しておくのがよい。

 このスクリプトファイルは,rc.d ディレクトリのスクリプトの実行が終わった後に実行されるファイルだ。インターネットサービスの起動以外のちょっとしたツールの起動処理などに適している。

icon Solarisの起動プロセスを理解しよう

 Solarisの起動プロセスについて解説しよう。Solarisでも,LinuxやFreeBSDと同じくinitが最初のプロセスとなり起動処理が行われる。initの動作設定は,/etc/inittabファイルに記述されている。

 また,inittabファイル内では,次のような共通書式になっているため,基本さえ押さえておけば内容を理解するのは難しくないだろう。

<id>:<rstate>:<action>:<process>

フィールド 内容
id 1,2 文字のユニークな文字列ap, fs, s0
rstate エントリを処理する run level
action エントリのふるまい  
process 実行するプログラム /sbin/rc3

 実際のinittabファイルを見てみよう。

リスト
別ウィンドウで見る or 04a2.txt

icon inittabオプションを知ろう

 「id」フィールドは,そのエントリを識別するための1文字,ないしは2文字のユニークな文字列を指定する。「rstate」では,そのエントリを実行するrun levelを指定する。例えば,そのエントリをrun level「2,3,4,5」で実行する場合,「2345」と記述する。「s」という文字列がついている場合,シングルユーザーモードの場合に実行される。

 「action」は,そのエントリの挙動を指定するもので,ここで指定されているものの内容は以下の通りである。

オプション 処理内容
initdefault initが最初に起動された時に実行される
sysinit initの起動後,特定のrun levelに移行する前に実行される
respawn プロセスが実行されていなければ実行される
wait 該当するrun levelに入ったらprocessを実行してその終了を待つ
powerfail initがSIGPWRシグナルを受けた時に実行される

 「process」フィールドは,そのエントリで実行されるプロセスを指定する。これらを総合すると,Solarisの起動時には,まずinitが起動され,

ap::sysinit:/sbin/autopush -f /etc/iu.ap
ap::sysinit:/sbin/soconfig -f /etc/sock2path
fs::sysinit:/sbin/rcS sysinit
           >/dev/msglog 2<>/dev/msglog </dev/console

が実行される。次の行が読み取られ結果としてrunlevel 3に移行する。

is:3:initdefault:

 さらに,次の行が読みとられ,必要なアプリケーションの起動などが行われる。

s2:23:wait:/sbin/rc2
                    >/dev/msglog 2<>/dev/msglog </dev/console
s3:3:wait:/sbin/rc3
                    >/dev/msglog 2<>/dev/msglog </dev/console

 最後には,次の行が読み込まれて完了する。

c:234:respawn:/usr/lib/saf/sac -t 300 co:234:respawn:
/usr/lib/saf/ttymon -g -h -p "`uname -n` console login: "
 -T sun-color -d /dev/console -l console -m ldterm,ttcompat

 スクリプトファイルの中を見てみよう。rcスクリプトの仕組みは次のようになっている。

 Solaris では起動時の初期化やサーバアプリケーションの起動などは,/etc/rc2.d,/etc/rc3.dの中にあるスクリプトで行われる。initによって実行される/sbin/rc2,/sbin/rc3は,それぞれ/etc/rc2.dや,/etc/rc3.d の中のスクリプトを実行するのだ。

 ここでは,実際に起動時の run level において,どのような処理が行われているのかを順を追って見ていき,その後で独自のプログラムの起動などを追加したい場合の方法を解説する。inittabによると,起動時のrun levelは「3」となっており,run levelが3の場合に実行される処理は次の2つである。

s2:23:wait:/sbin/rc2  >/dev/msglog 2<>/dev/msglog </dev/console
s3:3:wait:/sbin/rc3   >/dev/msglog 2<>/dev/msglog </dev/console

 /sbin/rc2 は,/etc/rc2.d の中のスクリプトを実行する。rc2.dディレクトリの中を確認すれば,実行されるサービスが確認できる。

% ls /etc/rc2.d/
K07dmi S40llc2 S73cachefs.daemon S80lp S94ncalogd K07snmpdx S47asppp S73nfs.client S80spc S95IIim K16apache S69inet S74autofs S85power S96ab2mgr K28nfs.server S70uucp S74syslog S88sendmail S99atsv README S71ldap.client S74xntpd S88utmpd S99audit S01MOUNTFSYS S71rpc S75cron S90loc.ja.cssd S99dtlogin S05RMTMPFILES S71sysid.sys S75savecore S90wbem S20sysetup S72autoinstall S76nscd S92volmgt S21perf S72inetsvc S80PRESERVE S93cacheos.finish S30sysid.net S72slpd S80kdmconfig S94Wnn6 %


icon スクリプト実行の流れ

 まず,「K」で始まるスクリプトを次のように実行した後,

/etc/rc2.d/K07dmi stop
/etc/rc2.d/K07snmpdx stop
/etc/rc2.d/K16apache stop
/etc/rc2.d/K28nfs.server stop

「S」で始まるスクリプトを次のように実行する。

/etc/rc2.d/S01MOUNTFSYS start
/etc/rc2.d/S5RMTMPFILES start
/etc/rc2.d/S20sysetup start
...
/etc/rc2.d/S99audit start
/etc/rc2.d/S99dtlogin start

 これらのスクリプトは,Linux の場合と同じように「start」や「stop」をコマンドライン引数として取るようになっている。「start」の時には起動処理を,「stop」の場合には終了処理を行うようになっている。 例えば,「S88sendmail」の場合は次のようになっていて,1つのスクリプトで起動と終了ができるようになっている。

例:「/sbin/sh」スクリプト
別ウィンドウで見る or 06a2.txt

icon 起動後の各種設定は/etc/ディレクトリ下の設定ファイルで行われる

 run level 3の場合でも,run level 2と同じく,/etc/rc3.d の中のスクリプトが「K」スクリプト,「S」スクリプトの順番に起動される。

% ls /etc/rc3.d
README  S15nfs.server  S50apache
S76snmpdx  S77dmi
%

 上記の場合では,「K」スクリプトがないため「S」スクリプトが順番に次のように実行される。

/etc/rc3.d/S15nfs.server start
/etc/rc3.d/S50apache start
/etc/rc3.d/S76snmpdx start
/etc/rc3.d/S77dmi start

 実際に独自の処理を追加する方法を解説しよう。rc スクリプトで処理を追加する場合,「start」や「stop」をコマンドライン引数として理解できるスクリプトを作成する必要がある。テンプレート(雛型)としては,次のようになるだろう。この中に記述されている「start」や「stop」に該当する処理を記述するのだ。

#!/sbin/sh
case "$1" in
start)
        echo "start"
        ;;
stop)
        echo "stop"
        ;;
*)
        echo "Usage: $0 {start|stop}"
        exit 1
        ;;
esac
exit 0


icon 独自の起動スクリプトを追加

 例えば,Apacheを/usr/local/apacheにインストールした場合,次のようになる。これでApacheを起動,終了することのできるスクリプトができたことになる(Apacheの場合は制御するapachectlと呼ばれるプログラムが用意されている)。

#!/sbin/sh
killproc() {
        pid=`/usr/bin/ps -e |
             /usr/bin/grep -w $1 |
             /usr/bin/sed -e 's/^  *//' -e 
's/ .*//'`
        [ "$pid" != "" ] && kill $pid
}
case "$1" in
start)
        /usr/local/apache/bin/httpd
        echo "start"
        ;;
stop)
        killproc httpd
        echo "stop"
        ;;
*)
        echo "Usage: $0 {start|stop}"
        exit 1
        ;;
esac
exit 0

 ここで定義されている「killproc」という関数は,プログラム名で指定してプロセスを終了するためのものだ。プロセスIDが分かっていないような場合に利用することができる。あとは,この完成したスクリプトを,起動または終了させたいrun level用のrcディレクトリに,「S??apache」または「K??apache」のような名前でコピーするだけである。「??」の部分は,該当するrun levelの中で処理される順番になる。前後のスクリプト番号から判断する必要がある。例えば,run level 3で50番目に起動させたい場合には次のようになる。

# cp apache.sh /etc/rc3.d/S50apache
# chmod 755 /etc/rc3.d/S50apache