/etc/init.d/functions を読む

それらしい起動スクリプトを作りたくて /etc/init.d/functions を読んだので、メモを残しておきます。所々に書かれているコメント以外にも制約が多く、「まぁソース嫁や」と暗に要求してくれる漢気溢れるスクリプトでした。

当然内容は無保証ですので利用される場合はご注意ください。また、基本的に「メモの公開」でして興味ある部分しか調べてないのと、清書する気力が残っていないので結構ばらばらな文章となっています。ご容赦。

今回確認したのは CentOS5 です。

ファイル構造と用語

  program
  
    起動されるプログラム。正確には実行可能ファイルのパス文字列。

  basename
  
    ここでは起動される daemon のプログラム名を差す様子。apache なら httpd。

  pidfile

    /var/run/{basename}.pid で配置される。ここに起動された program の pid が入
    る。

  /var/lock/subsys/*

    program が動いていれば、program の basename と同名のファイルをここに
    touch することでロックをかける慣習の様子。でもロックファイル作る関数が
    functions には存在しない。えーw

データ構造
  /etc/sysconfig/init
    このファイルがないと functions 自身に書かれたデフォルト値を利用する。

    BOOTUP      color        ブートアップする際に色を利用するか
    RES_COL     60           [ ok ] とかの表示をどこから始めるか

    以下からSETCOLOR シリーズは echo を利用して何かやっているみたい
    エスケープシーケンスをしていることはわかるのだが。MOVE_TO_COL 以外は
    色の設定。MOVE_TO_COL は名前からしてカーソルの移動か何かっぽいが、エスケープ
    シーケンス見てみないと判らない。 echo -e がエスケープシーケンスのための
    ものっぽい。
      MOVE_TO_COL
      SETCOLOR_SUCCESS
      SETCOLOR_FAILURE
      STECOLOR_WARNING
      SETCOLOR_NORMAL

    LOGELEVEL   3           ブート時のログレベル。カーネルの。
                            syslog はこれでリセットされるって書いてある。
    PROMPT                  no 以外をセットすると hotkey interactive startup が
                            有効になるらしい。何かは不明。
    AUTOSWAP                よくわからん。。
  
    __sed_discard_ignored_files

関数

  fstab_decode_str()
  checkpid()
  __umount_loop()
  __umount_loopback_loop()

  __pids_var_run

    Usage:
      __pids_var_run  {base}  {pidfile}

    return:
      0 ...     プロセスは生きている
      1 ...     プロセスは死んでるけれどpidfileが残っている
      3 ...     プロセスは死んでいる

    memo:

      中身的には渡された引数をもとに pidfile のチェックをしている。読みづらいが
      /proc を見て、プロセスが生きているかどうかを判断している。

      のだが、プロセスが生きているかど蚊の判断基準が pidfile に記載されている
      pid だけっぽく、basename を見ている気がしない。同じ pid が生きてると「生き
      ているとみなされる」ことがありそう。まぁ現実的にはあまりないのかな。

      というかグローバル変数にチェックしたPIDを入れたりしてる。シェルだと仕方な
      いのかなぁ。

      この関数見ると pidfile は複数行に対応していないことが判る。プロセスを複数
      起動するプログラムの場合、一行に空白文字区切りで複数書かないといけない。

  __pids_pidof()

  daemon()
  
    program を daemon として起動するための関数。--check とかのオプションがあるけ
    れど、本質的には、1.重複なくプロセスを起動する 2.起動したプロセスの pid
    を記録する 3.ユーザにわかりやすく起動の成功/失敗を伝える ためにある様
    子。

    意外と設定できることが多い。

    Usage: daemon [+/-nicelevel] {program}
      options
        --check {base}            # base とはプログラムの basename の模様
        --user  {user}
        --pidfile {pidfiile}
        --force

        これらのオプションは、例えば --user=hoge といった形式でも利用できる様子。

      variables:
        gotbase     プログラムの basename を取得したかどうかのフラグ
                    取得できていない場合、 ${1##*/} で取得する。
        force       強制のフラグ
        nicelevel   default 0.
        corelimit   実体は "ulimit -S -c ${DAEMON_COREFILE_LIMIT:-0}"
                    見てのとおりデフォルト 0 が設定されている。
        pid         起動要求した program がすでに起動していればここにその pid が
                    入る。
                    __pids_var_run のところにも書いたがグローバル変数。
                    __pids_var_run でセットするという荒業をやっているみたい。
        base        起動要求されたプログラムの basename。
        user        --user に指定された username が入る。
        nice        環境変数 $NICELEVEL が設定されていればそれを適用させる。
                    なければ 0 にする。
        bg          使われてるところが見当たりません。
        pid_file    --pidfiile を指定した場合に入るみたい。

      memo:

        基本的な流れとしては、要求された program の basename を取得して、
        basenameから pidfile 名を取得して生きているかどうかを調べる。生きている
        場合、--force であれば処理を続行し、でなければ終了する。生きていない場合
        はもちろん続行。

        で、ulimit で corefile のサイズ上限を設定したあと、nicelevel を設定。こ
        のあたりはオプショナルっぽい。

        このあとに起動処理に入る。起動処理では --user で設定した user で起動す
        る。user の指定がなければそのまま起動(なので、通常 root のはず)。

        で、この起動なのだが $* を実行することで起動している。つまり起動したいプ
        ログラムのパスを最後に持ってこないとエラーになるはず。

  killproc()

    Usage:
      killproc [-p pidfile] [-d delay] {program} [-signal]

    起動している program を落とすためにある。性格にはシグナルを送信するためにある
    様子。書き方からしてオプションの指定の順番がシビアで、-p とか -d とかの
    Usage の順番に書かないとたぶん動かない。

    -signal は program に与えるシグナルを指定する。kill コマンドの引数ママになっ
    ているので任意で指定できる。よく判らない挙動だけれど、-signal を指定していな
    い場合は先ず TERM を送り、sleep 1 の後 program が停止していなければ delay 秒
    sleep した後に、再度チェック、それでも生きていれば -KILL して usleep 100000
    (=0.1秒スリープ)した後に生存確認を行い、生きていると failure、死んでれば
    successとする。一方、-signal が指定されていると、シグナルを投げた後まったく
    スリープせずに成否判定を行う、というか kill コマンドが成功していれば成功扱い
    になる。たぶん停止は TERM シグナルですべきだよね、他のシグナル指定されたら停
    止要求かどうか判らないからシグナル投げられたかどうかだけ判定するよ、というこ
    とだと思う。

    戻り値:
      0   停止成功またはシグナル成功
      7   program は起動していない

  pidfileofproc()
  pidofproc()

  status()
  
    Usage:  status [-p pidfile] {program}

      詳しくは見ていないけれど、与えられた program の basename を調べて pidfile
      を探索し、program が動作しているかどうかなどのステータスを返す。

      例えば、
        status /usr/sbin/httpd
      とか
        status httpd
      とかってできる。

  echo_success()
  echo_failure()
  echo_passed()
  echo_warning()
  update_boot_stage()

  success()

    program 起動成功時に表示される [  OK  ] を出す関数。
    source /etc/init.d/functions してから success って打つと面白い(俺は)。

  failure()

    success の失敗版。

  passed()

    success のところに PASSED って表示される

  warning()

    success のところに WARNING って(ry

    画面が WARNING で埋め尽くされることを期待して while [ 0 ]; do warning; done
    とかやったけれど期待通りにならなかった。echo 入れればいいのか。

  action()

    面白げなのだが深入りはしない(ぉ

  strstr()
  confirm()
  get_numeric_dev()
  resolve_dm_name()
  is_ignored_file()