ソースコード・リテラシーのススメ

第12回 システム起動用のスクリプトを読む

この記事を読むのに必要な時間:およそ 6 分

モジュールドライバの読み込み

256行目くらいからは雑多な起動時処理という感じですが,ざっと眺めて行きます。

256  # Fix console loglevel
257  if [ -n "$LOGLEVEL" ]; then
258          /bin/dmesg -n $LOGLEVEL
259  fi
260  
261  # Only read this once.
262  cmdline=$(cat /proc/cmdline)
263  
264  # Initialize hardware
265  if [ -f /proc/sys/kernel/modprobe ]; then
266     if ! strstr "$cmdline" nomodules && [ -f /proc/modules ] ; then
267         sysctl -w kernel.modprobe="/sbin/modprobe" >/dev/null 2>&1
268     else
269         # We used to set this to NULL, but that causes 'failed to exec' messages"
270         sysctl -w kernel.modprobe="/bin/true" >/dev/null 2>&1
271     fi
272  fi
273  
 ……
290  /sbin/start_udev
291  
292  # Load other user-defined modules
293  for file in /etc/sysconfig/modules/*.modules ; do
294    [ -x $file ] && $file
295  done
296  
297  # Load modules (for backward compatibility with VARs)
298  if [ -f /etc/rc.modules ]; then
299          /etc/rc.modules
300  fi

256行目から259行目は$LOGLEVELという変数が設定されているかを調べて,設定されていれば/bin/dmesg -n $LOGLEVELというコマンドを実行します。$LOGLEVELという変数も236行目にあった$BOOTUP同様,/etc/sysconfig/initの中で定義されています。

/bin/dmesg-nオプションはカーネルのログメッセージのうち,コンソール画面に出力されるメッセージレベルを指定するもので,0から7の数字を指定でき,数字が大きくなるほど詳細なメッセージがコンソール画面に出力されるようになります。

262行目は$( .. )内のコマンドの結果を$cmdlineという変数に代入する処理で,右辺は`cat /proc/cmdline`と同じです。/proc/cmdlineは起動時にブートローダからカーネルに与えられるパラメータを記録しているファイルで,これらの情報はルートファイルシステムの位置やマウントオプション,カーネルの機能やシステムの動作を調整するために利用されます。

264行目以降はモジュールドライバを読み込んで各種ハードウェアを利用可能にするための処理です。267行目で実行しているsysctlコマンドは/procファイルシステム経由でカーネルの動作を変更するコマンドで,ここではカーネルが必要なモジュールを組み込む際に利用するコマンドの指定であるkernel.modprobe/sbin/modprobeを設定しています。もし起動時カーネルパラメータとしてnomodulesが指定されると270 行目のようにkernel.modprobeに/bin/trueが設定され,カーネル自身によるモジュールの読み込み処理はできなくなります。

UNIX/Linuxのコマンドは,終了時に何らかの整数値を返すように設計されています。それらの整数値は0が正常終了で,0以外の場合は何らかのエラーが発生したことによる異常終了と定義されています。一方,/bin/true は何もせずに0という値を返すだけのコマンドで,何らかのコマンドの代わりに/bin/trueを実行することで,そのコマンドが正常終了したように見せかけるために利用されます。

少し飛ばして,290行目で実行している/sbin/start_udevは,最近のLinuxで採用されているudev機能を開始するコマンドです。udevとは,アプリケーションがハードウェアを操作する際に利用するデバイスファイルを動的に生成する仕組みで,udevdというデーモンがカーネルの認識してしているハードウェア情報を利用して,それぞれのハードウェアに応じたデバイスファイルを/dev以下に作っていきます。この/sbin/start_udevは必要な環境を整えてudevdを起動するためのコマンドです。

通常はカーネルが自動認識して組み込むモジュールドライバだけで十分なはずですが,自動的には組み込まれないモジュールドライバを組み込ませたい場合は 293行目に見られるように/etc/sysconfig/modules/の下にmy.modulesのようなファイルを用意して,そこで必要なモジュールを組み込む指定をしておけば,rc.sysinitの中で組み込んでくれます。また,/etc/rc.modulesというファイルでモジュールを組み込むことも可能です。

対話モードの確認とrc.sysinitの終了

この後,Red Hat系Linuxに独自のrhgbというコマンドを起動してXウィンドウを用いた綺麗な画像を表示し,ユーザにはプログレスバーによる進捗表示だけを示しながら,処理は背後で進めていきます。rc.sysinitの中ではLVMを用意したり,ファイルシステムのチェックをしたりと大忙しになりますが,それらの部分はばっさりと飛ばして,最後の部分だけを見てみます。

826  # Now that we have all of our basic modules loaded and the kernel going,
827  # let's dump the syslog ring somewhere so we can find it later
828  [ -f /var/log/dmesg ] && mv -f /var/log/dmesg /var/log/dmesg.old
829  dmesg -s 131072 > /var/log/dmesg
830  
831  # create the crash indicator flag to warn on crashes, offer fsck with timeout
832  touch /.autofsck &> /dev/null
833  
834  if [ "$PROMPT" != no ]; then
835      while :; do
836          pid=$(/sbin/pidof getkey)
837          [ -n "$pid" -o -e /var/run/getkey_done ] && break
838          usleep 100000
839      done
840      [ -n "$pid" ] && kill -TERM "$pid" >/dev/null 2>&1
841  fi
842  } &
843  if strstr "$cmdline" confirm ; then
844          touch /var/run/confirm
845  fi
846  if [ "$PROMPT" != "no" ]; then
847          /sbin/getkey i && touch /var/run/confirm
848          touch /var/run/getkey_done
849  fi
850  wait
851  [ "$PROMPT" != no ] && rm -f /var/run/getkey_done
852  
853  # Let rhgb know that we're leaving rc.sysinit
854  if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then
855      /usr/bin/rhgb-client --sysinit
856  fi
857  

このあたりまでにファイルシステムのチェックとマウントが終了し,各種ログファイルの初期化やスワップファイルの設定なども済ませて,ほぼ基本的なコマンド類は利用可能になっています。

828,829行目ではすでに同じ名前のファイルがあれば別名で保存した上で,dmesgコマンドでここまでのカーネルのログを/var/log/dmesgに保存しています。

832行目では/.autofsckという隠しファイルを作ります。このファイルは,haltやshutdownコマンドによりシステムが正常に終了した場合には削除されるようになっており,もし起動時にこのファイルが残っていれば,何らかの理由で前回は正常終了していないことから,ファイルシステムをチェックした方がいいことがわかります。今回は省略しましたが,rc.sysinitの375行目からがそのためのチェックになっています。

834行目から851行目はキーボードからの入力をチェックする部分です。今回読んでいるrc.sysinitを採用しているRed Hat系のディストリビューションでは,rc.sysinitの動作中にiを入力すると,rc.sysinit以降で各種サービスを起動するかどうかを手動で指定できるようになっており,この部分がそのためのチェックになっています。

具体的には847行目の/sbin/getkey iでiが入力されたかを調べ,入力されていれば/var/run/confirmというファイルを作り,848行目で/var/run/getkey_doneを作成して入力チェックが終わったことを他のプロセスに知らせます。作成された/var/run/confirmファイルは,rc.sysinitの次に起動されるスクリプトから参照され,起動すべきサービスごとに確認を求めるようになります。

シェルスクリプト的に見ると,⁠リストを省略した)771行目から842行目が中括弧({ })で囲われたグループコマンドとして別プロセスで実行され(842行目の&⁠⁠,そちらのプロセスと850行目のwaitで同期を取りながらキーボードからの入力チェックを行う,という複雑な作りになっています。このような構成を取った理由はよく分かりませんが,独立性の高い処理を並列化することで処理速度を上げるような意図があるのでしょう。

最後の853行目から856行目は,グラフィカルな画面を表示しているrhgbにrhgb-client経由でrc.sysinitが終了したことを伝えています。このコマンドを受けた rhgb はXウィンドウでのキーボードの設定を行なって対話モードの入力に備えます。

以上,駆け足でrc.sysinitスクリプトを眺めてみました。rc.sysinitが終了すれば,/sbin/initがランレベルを引数にして/etc/rc.d/rcスクリプトを起動し,/etc/rc.d/rcスクリプトがそれぞれのレベルに応じたサービスを起動してシステムの準備を整えていきます。それらの過程については次回にでも読んでみる予定です。

著者プロフィール

こじまみつひろ

Plamo Linuxとりまとめ役。もともとは人類学的にハッカー文化を研究しようとしていたのが,いつの間にかミイラ取りがミイラになってOSSを仕事にするようになってしまいました。最近はスペシャリスト養成を目的とした専門職大学院で教壇に立ったりもしています。

URLhttp://www.linet.gr.jp/~kojima/Plamo/index.html