でびあんの initrd (4)
昨晩の続きを。
次は get_prereqs() 手続き。
get_prereqs() { set_initlist for gp_x in ${initlist}; do tmp=$(${initdir}/${gp_x} prereqs) eval array_${gp_x}=\"${tmp}\" done }
ええと、set_initlist は
set_initlist() { unset initlist for si_x in ${initdir}/*; do if [ ! -x ${si_x} ]; then continue fi initlist="${initlist} ${si_x#${initdir}/}" done }
なカンジで initdir の中にある実行属性が付いてるファイル名のリストを initlist にセットする手続きになっている模様。initlist を初期化した後、何をしているか、というと
- initlist から要素を一つづつ取り出して gp_x に格納しつつ以下
- tmp に initdir/gp_x prereqs の実行結果 (というか標準出力) を格納
- array_* (ファイル名) に tmp の値を格納
という事は initdir の中にあるファイル名な変数がそれだけ分できるのか。例えばデフォルトの local-top だと
scripts/local-top/udev_helper scripts/local-top/mdrun scripts/local-top/lvm
みたいなカンジになっていますが、作成されるシェル変数は
array_udev_helper array_mdrun array_lvm
なソレ達ができて、それぞれの値は prereqs 付けて実行した出力が入ってる、と。
あと、eval の使い方も参考になります。例えば
eval array_${gp_x}=\"${tmp}\"
だと先に変数が値に展開されてナニ。lvm を例に考えたらまず
eval array_lvm=\"mdadm mdrun lvm2\"
になって eval されるはず。なかなか凄い。
ぢつは
ここまでイメージできた時点で何しようとしてるのか、がようやくイメージできてたり。呼び出しの優先順位を設定できるんですな。なんて賢いんでしょ。全部シェルスクリプトでヤッツケてしまっているあたりもなかなか。
閑話休題
ちなみに scripts/local-top 配下で試した結果が以下です。
$ ./scripts/local-top/udev_helper prereqs $ ./scripts/local-top/mdrun prereqs udev_helper $ ./scripts/local-top/lvm prereqs mdadm mdrun lvm2 $
どっちが先か、は reduce を確認しないと分かりません。ので早速見ていくことに。とりあえず reduce_rereqs() 手続きが以下。
# This function generates the runlist, so we clear it first. reduce_prereqs() { unset runlist set_initlist set -- ${initlist} i=$# # Loop until there's no more in the queue to loop through while [ ${i} -ne 0 ]; do oldi=${i} for rp_x in ${initlist}; do reduce_satisfied ${rp_x} count_unsatisfied $(render array_${rp_x}) cnt=${?} if [ ${cnt} -eq 0 ]; then runlist="${runlist} ${rp_x}" pop_list_item ${rp_x} ${initlist} initlist=${tmppop} i=$((${i} - 1)) fi done if [ ${i} -eq ${oldi} ]; then panic "PANIC: Circular dependancy. Exiting." fi done }
こいつが call_scripts() 手続きで使っている runlist を作る模様。set_initlist は略しますが再度 initlist 作り直しているみたい。で、次の
set -- ${initlist} i=$#
もなかなか凄い。man bash によると
オプションが処理された後に残っている引数があれば、これは位置パラメータの値として扱われ、$1, $2, ... $n の順に代入されます。
とある。知りませなんだ。しかし具体的にどうやって優先順位を解決しているんでしょうか。ちょっと集中力切れたんで頼まれもののお使いに行ってまいります。
続き
帰宅。昼飯の支度をする準備完了。同居人が病院に行っているので戻るまででどこまで掘れるか。ちょっと reduce_prereqs() 手続き長いんでちょっとづつ引用しながらメモな方式で。
まず、先頭部分ですが
reduce_prereqs() { unset runlist set_initlist set -- ${initlist} i=$#
set_initlist して_位置パラメータ_にセット。セットされたパラメータの個数を i に代入してますな。
で、次、後全部引用。
# Loop until there's no more in the queue to loop through while [ ${i} -ne 0 ]; do oldi=${i} for rp_x in ${initlist}; do reduce_satisfied ${rp_x} count_unsatisfied $(render array_${rp_x}) cnt=${?} if [ ${cnt} -eq 0 ]; then runlist="${runlist} ${rp_x}" pop_list_item ${rp_x} ${initlist} initlist=${tmppop} i=$((${i} - 1)) fi done if [ ${i} -eq ${oldi} ]; then panic "PANIC: Circular dependancy. Exiting." fi done
- i が 0 になるまで繰り返し。
- oldi に i を退避
- initlist の要素を rp_x に順に取り出しつつ以下
- reduce_satisfied を rp_x を引数に呼び出し
- count_unsatisfied を render array_${rp_x} の出力を引数に呼び出し
- cnt に count_unsatisfied の終了ステイタスをセット
- cnt が 0 なら云々
- i と oldi が同じ値なら panic
というカンジですな。ちなみに略した部分は
- cnt が 0 なら以下
- runlist に rp_x を追加
- pop_list_item を rp_x と initlist を引数に呼び出し
- initlist に tmppop を代入
- i に i - 1 を代入
上記は runlist への追加と initlist の再設定 (追加された要素の除去) ですな。ちょっとまだ i が減る仕組みと panic が出力する "Circular dependancy" というメセジのナニが微妙。
# panic が出力するナニはなんとなく想像できますが
もう少し
reduce_satisfied() 手続きは以下。
reduce_satisfied() { deplist="$(render array_${1})" unset tmpdeplist for rs_y in ${deplist}; do if [ ! -f ${initdir}/${rs_y} ]; then continue fi tmpdeplist="${tmpdeplist} ${rs_y}" done deplist=${tmpdeplist} for rs_x in ${runlist}; do pop_list_item ${rs_x} ${deplist} deplist=${tmppop} done eval array_${1}=\"${deplist}\" }
render は渡された引数を echo するソレですので、deplist には array_* の中身が格納される格好。リストの要素が initdir に存在するかを確認してリストを再設定 (あるもののみが残る) している模様。
その上で、runlist を走査して云々してますが微妙に読みづらい。
ええと整理してみるに reduce_prereqs() 手続きは
while [ ${i} -ne 0 ]; do # 略 for rp_x in ${initlist}; do #略 done # 略 done
みたいな二重ループになってて、内側の for で最低一つは i の値が減らなければならない、のが前提に見える。i の値が減るのは
- reduce_satisfied ${rp_x} して
- count_unsatisfied $(render array_${rp_x}) して
- cnt=${?} で count_unsatisfied の戻りを保存して
- cnt が 0 の場合
になります。cnt が 0 になるのは array_* が空リスト (って言ってよいのかどうか微妙) になった場合、という事になるんでしょうが、そのあたりの根拠は以下で。
てーかも一度 reduce_satisfied() 手続きのポイントを以下に。
- render array_* で戻されたリストから initdir に存在しない要素を除く
- runlist の要素を取り出しつつ 上記のリスト (deplist) にその要素があった場合はそれを除く
- array_* に再設定
てーコトはやはり prereqs なソレはそのスクリプトが依存する (自分より先に実行されている必要のある) スクリプト、という事になりますな。あと、お互いに依存しあってたらいつまで経っても array_* は空にならないな。Circular dependancy はそーゆー意味ッスか。
とりあえずメシ食って再度でかける用件があるんで、ここで再投入。
さらに続き
count_satisfied() 手続きの定義は以下。
count_unsatisfied() { set -- ${@} return ${#} }
これは何をしているか、というとリストで指定された引数の要素数が戻る。空リストであればゼロですな。ちなみに呼び出しは以下な形。
count_unsatisfied $(render array_${rp_x})
array_* のナニが渡される。return しておいて直後で ${?} を検査、というのはなかなかウマいな、と。
あと、スルーしてたんですが、pop_list_item() 手続きも確認。
# Removes $1 from initlist pop_list_item() { item=${1} shift set -- ${@} unset tmppop # Iterate for pop in ${@}; do if [ ${pop} = ${item} ]; then continue fi tmppop="${tmppop} ${pop}" done }
呼び出しな例が以下。
pop_list_item ${rp_x} ${initlist} initlist=${tmppop}
tmppop に ${1} 以外の要素なリストがセットされるので、呼び出し後にリセットする必要がある。こうして見てるに functions にある手続き達は引数というか位置パラメータというヤツを上手に使ってますな。
とりあえず load_modules() 手続きと parse_numeric() 手続きは別途で。