home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

C言語系/「デーモン君のソース探検」読書メモ/13, man(1)とnroff(1)

C言語系/「デーモン君のソース探検」読書メモ/13, man(1)とnroff(1)

C言語系 / 「デーモン君のソース探検」読書メモ / 13, man(1)とnroff(1)
id: 566 所有者: msakamoto-sf    作成日: 2010-01-29 12:46:51
カテゴリ: BSD C言語 

お題:manがnroffを起動する流れを追跡せよ

まず実行ファイルとソースディレクトリを特定する。

$ 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()関数の大まかな流れをまとめておく。

(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段程度ネストしているが、大枠として見れば分かりやすい。

[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"設定を見てみる。

# 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のロードと解析結果のデータ構造"で詳細を調べてみる。

今回のお題については、ここまで。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2010-01-29 12:49:07
md5:f867241d6fbe61226f847876d2a7e681
sha1:c65f8077d15ddc4390e3a4af3032a365fa6413a5
コメント
コメントを投稿するにはログインして下さい。