#navi_header|C言語系| お題:manがnroffを起動する流れを追跡せよ #more|| まず実行ファイルとソースディレクトリを特定する。 $ which man /usr/bin/man $ cd /usr/src/usr.bin/man/ $ ls CVS/ Makefile man.1 man.c man.conf.5 manconf.c manconf.h pathnames.h man.cをざっと眺めた上で、先にmain()関数の大まかな流れをまとめておく。 #pre||> (1) オプション解析 【互換性維持】 "-k" → jump()関数でaproposコマンドをexecvp()で実行・終了 "-f" → jump()関数でwhatisコマンドをexecvp()で実行・終了 (2) "-h", "-c", "-w"未指定で端末経由であれば、ページャプログラムを取得・判定 (3) "/etc/man.conf"のロード・解析 (4) マシン情報取得 (5) MANPATH調整 (6) "-s" or 数字でセクション指定された場合は man.conf よりパス取得 (7) (6)で取得したパスが絶対パスの場合は内部変数調整 (8) 検索パスのリストを構築 (9) この後の処理中に一時ファイルを作成する場合がある。 SIG{INT|HUP|PIPE}を受けた時に、一時ファイルを削除するonsig()関数を シグナルハンドラとして登録 (10) manual()関数でファイルの検索と準備 (11) "-c", "-h", "-w"オプション指定に応じて処理→終了 "-c" : ファイルを標準出力にwriteして終了 "-h" : SYNOPSIS(or DESCRIPTION)をwhatis(1)と同様な形で表示して終了 "-w" : ファイルのパスを表示して終了 (12) 見つかったファイル名をスペースで連結し、ページャで表示(system(3)使用) ||< 続いてmanual()関数でのファイル検索と準備について、大まかな流れを見る。ソースコード上はループが2-3段程度ネストしているが、大枠として見れば分かりやすい。 #pre||> [loop-A] 検索パスのリストのそれぞれに対して... (A-1) glob()でパターンマッチしたファイル一覧取得 [loop-B] glob()マッチの各ファイル名に対して... (B-1) 末尾".0"についてfnmatch()でマッチ(古い"_suffix"無し用互換性維持) (B-2) man.confの"_suffix"リストを使ってfnmatch()でマッチ (B-3) man.confの"_build"リストからfnmatch()でマッチ →マッチした場合は build_page()関数 で表示用の一時ファイル生成 (※"-w"指定の場合はbuild_page()関数は実行しない) ||< ここで "/etc/man.conf" の"_suffix", "_build"設定を見てみる。 #pre||> # Files typed by suffix and their commands. # Note the order, .Z must come after .[1-9].Z, or it will match first. _suffix .0 _build .0.Z /usr/bin/zcat %s _build .0.gz /usr/bin/gunzip -c %s _build .[1-9ln] /usr/bin/nroff -msafer -man %s _build .[1-9ln].Z /usr/bin/zcat %s | /usr/bin/nroff -msafer -man _build .[1-9ln].gz /usr/bin/gunzip -c %s | /usr/bin/nroff -msafer -man _build .tbl /usr/bin/tbl %s | /usr/bin/nroff -msafer -man _build .tbl.Z /usr/bin/zcat %s | /usr/bin/tbl | /usr/bin/nroff -msafer -man _build .tbl.gz /usr/bin/gunzip -c %s | /usr/bin/tbl | /usr/bin/nroff -msafer -man _build .me /usr/bin/nroff -msafer -me %s 2>/dev/null | cat -s ||< ファイルの拡張子に応じて、zcatやgunzip, nroffなどを適切なオプションと共に起動する設定になっていることが分かる。 build_page()関数ではsnprintf()を駆使しコマンド文字列を生成、system(3)で起動、一時ファイルへ整形データを保存するようになっている。 「デーモン君のソース探検」本文では、nroffを起動するからとexec()やsystem()の使用箇所から調べていくボトムアップな調べ方だったので、読書メモの方ではmain()関数を起点に流れをまず追っていくトップダウン形式で調べてみた。 結論として、nroffなどの整形コマンドはman.confの"_build"設定に記述されており、man用のファイルを検索後、一時ファイルに整形結果を保存しページャで表示する仕組みになっている。 なお"TAILQ_FOREACH"など"TAILQ_"で始まるマクロや"TAG"など見慣れない型が頻出しているが、これらについては次のお題、"man.confのロードと解析結果のデータ構造"で詳細を調べてみる。 今回のお題については、ここまで。 #navi_footer|C言語系|