[PREVIOUS CHAPTER] [NEXT CHAPTER]

6 FML のプロセス

    ＭＬサーバの基本動作を知っておくとカスタマイズの時役にたちます。

    6.1	ＭＬサーバの動作 (fml と sendmail の役割分担)

       メールが SMTP で送られてくる

                 ↓

       SMTP で待ち構えているプログラムがうけとる (例: sendmail)

                 ↓

       /etc/aliases から何をすれば良いのかを理解して、
       setuid 操作等を行なった後 fml.pl の STDIN にメールが送り込まれる。

                 ↓

       (sendmail -> fml.pl へ引き渡される。ここからが FML の担当)
       config.ph による設定に従い、ヘッダの解析、ＭＬメンバーのリストに従い
       配送 or コマンド要求を処理した結果のメールを配送リストと共に
       sendmail 等のSMTPサーバへ引き渡す

                 ↓

       (ここから再び sendmail の担当)
       sendmail 等のSMTPサーバがメールの配送を行なう。

    フィルタだけなら sed でも十分だし"配るだけ"なら Sendmail 8.x でも十分
    でしょう。しかし、+αでログをとり、スプールし、必要なら取り寄せられる
    ようにちょこっとだけ複雑なことをしようとするならこのサーバ まで必要と
    なるというわけです。

    なおこの図でわかるとおり、まとめおくりはこれとは"全く別の"プロセスです。
    まとめおくりは自動的に作動するわけではありません。
    まとめおくりとは、一定時間ごとにスプールされたＭＬの記事を送ってあげる
    "別のプロセス"です。このプロセスは別の仕掛けで定期的に実行されなければ
    なりません。
    ../digest 2.0
    ../digest 2.0

    6.2	Sendmail -> fml.pl 時の動作

    sendmail から fml.pl へメールが渡される時は次のように動作します。

    ○ まず /etc/aliases にある

    	Elena: :include:/usr/local/list/Elena
    	owner-Elena:fukachan

    のような部分から /usr/local/list/Elena を実行すればよいことがわかるの
    で sendmail はこのファイルを実行します。/usr/local/list/Elena の中身は

    	"|/usr/local/fml/fml.pl /var/spool/ml/elena"

    のようになっています。

    次に fml が上の引数は /var/spool/ml/elena を Elena ML の HOME だと見な
    し /var/spool/ml/elena/config.ph に従い fml の設定を行います。

    そのあと設定に従いメールを処理します。 コマンドラインオプションを指定
    するときは /usr/local/list/Elena の中で

    	"|/usr/local/fml/fml.pl /var/spool/ml/elena --ctladdr "

    のように書きます(コマンドラインオプションについては Chapter ../debug 4.0)。
    引数の書き方の順番は任意ですが、引数の中の最初の directory を ML の
    HOME (config.phのある場所 もしくは spool やメンバーファイルのある場所)
    と見なします。

    6.3	ライブラリのファイルを探す順番 (fml.pl と ARGV)

    	/usr/local/fml/fml.pl /var/spool/ml/elena

    のように起動されるわけですが、この場合/usr/local/fml/fml.pl の
    /usr/local/fml 部分をとりだし /usr/local/fml を実行ファイルやライブラ
    リのパスとみなします。

    	1   /var/spool/ml/elena
    	2   /usr/local/fml

    この順番で dynamic loading するファイルを探します。例えば config.ph や
    libsmtp.pl をこの順番で探します。もし、この後に directory 名がさらに付
    け加えられていた(複数可能)場合、例えば

       "|/usr/local/fml/fml.pl /var/spool/ml/elena /usr/lib/uja /lib/aja"

    の時は

    	1   /var/spool/ml/elena
    	2   /var/spool/ml/etc/fml/
    	3   /usr/local/fml
    	4   /usr/lib/uja
    	5   /lib/uja

    のような順番でファイルを探します。

    6.4	設定ファイルのサーチ順番

    オプション設定の強い順番に並べると

    	1 コマンドラインオプション (fml.pl -d や fml.pl --ctladdr 等)
    	  なおコマンドラインオプションについては Chapter ../debug 4.0。
    	2 sitedef.ph による設定のoverwrite(サイト共通の設定等が望ましい)
    	3 各MLごとの config.ph による設定
    	4 site_init.ph によるデフォールト設定
    	5 fml デフォールト設定

    普通の program と同様ですね。ＭＬごとではなくそのマシン共通の設定にな
    るもの

    	tar や gzip はどこにある？

    等を sitedef.ph に書くと便利でしょう。

    site_init.ph は各MLの config.ph の前に評価されデフォールトを決めます。
    sitedef.ph は各MLの config.ph の評価後に適用され、各ＭＬの設定を強制的
    に書き換えることもできます。それぞれ使いわけると良いでしょう。いずれに
    しろ config.ph にない変数であればどちらを使っても同じことです。

    sitedef.ph site_init.ph のサーチは

    				Example
    	-----------------------------------------------
    	$DIR			/var/spool/ml/elena/
    	$ML_DIR/etc/fml/	/var/spool/ml/etc/fml/
    	$EXEC_DIR		/usr/local/fml/
    	perl standard path	@INC

    の順にサーチされます。共通の場所なので

    	$ML_DIR/etc/fml/	/var/spool/ml/etc/fml/
    	$EXEC_DIR		/usr/local/fml/

    のいづれかでしょう。fml 2.2.1 で $ML_DIR/etc/fml/ が先頭になりました。
    これはversion up時に/usr/local/fmlの下をいじらなくてもよいようにという
    配慮からです。

    6.5	fmlのプロセス(STDINからの読み込みの第一段階)

    STDIN からの読み込みは第壱段階でハッシュテーブル %Envelope

    	ヘッダ	$Envelope{'Header'}
    	ボディ	$Envelope{'Body'}
    7.3
    7.3

    に保存されます。この時ボディ(メールの本文)に対しては次のようなチェック
    がなされます。

    ○ 最初の $GUIDE_CHECK_LIMIT 行に対して $GUIDE_KEYWORD のキーワードが
    現れるか否か？
    メンバー以外からのメールでこのキーワードをキャッチした場合は、ガイドを
    送り返してそれ以外のことはしない。

    ○ 最初の $COMMAND_CHECK_LIMIT 行に対して
    	^#(\s*\w+\s|^\#\s*\w+)
    	^#$CHADDR_KEYWORD

    	# で始まり、英文字が続く行 (\s*\w+\s|^\#\s*\w+)

    	# で始まり、$CHADDR_KEYWORD のキーワード
    	が現れる行があるか否か？あった場合はコマンドモードへ移行。

    の2つのチェックをしています。それぞれの LIMIT を調節すると、つまり
    LIMIT を 0にすればチェックをしないということになるし、全文すべてをコマ
    ンドの対象にすることもできます。デフォールトではそれぞれ最初の3行のみ
    を対象にしています。

    なお、それぞれのキーワードデフォールトは次のように設定されています。

    	$GUIDE_KEYWORD  = "guide";
    	$CHADDR_KEYWORD = "chaddr|change-address|change";

    6.6	fmlのプロセス(第２段階, %Envelopeの処理)

    %Envelope にヘッダとボディを読み込んだ後はヘッダの解析プロセスが続きま
    す。詳細については次の章を見て下さい。
    7.3
    ../header_rewrite 5.0
    7.3
    ../header_rewrite 5.0

    この後ロックして、メインのプロセスが続くことになります。

    6.7	fml process の lock と signal handling

    現在の flock を使うロックアルゴリズムは次のように設定されています。
    flock(2) と alarm(3) によるTIMEOUT処理による一般的な方法です。
    sendmail のような alarm(3) ベースの event 駆動をするようにプロセス管理
    をしています。

    NT4 上では Activestate ntperl を使っています。この ntperl では
    flock(2) は動きます(かなり怪しいという話も聞くが詳細は不明)が alarm(3)
    がないので Win32::Process による wrapper で alarm(3) を emulate してい
    ます。emulation といってもTIMEOUTしたら強制終了するだけですが。

    sub Flock {

        &SetEvent($TimeOut{'flock'} || 3600, 'TimeOut') if $HAS_ALARM;
    	...

    TIMEOUTを待つ時間は $TimeOut{'flock'} で決まります。(flock でない場合
    は 3秒+α 程度の sleep を $MAX_TIMEOUT 回して待ってみる)

        # signal handling
        $SIG{'ALRM'} = 'TimeOut';
        $SIG{'INT'}  = $SIG{'QUIT'} = 'SignalLog';

    $TimeOut{'flock'} (デフォールトは3600秒)後 $SIG{'ALRM'} で定義された関
    数(TimeOut)を実行します。

    関数 TimeOut は管理者へ TIMEOUT を知らせ、ログを残しfmlを終了します。
    これがないとずっとロック(flock)がかかったままになるからです。

    なお flock を使わない時はTIMEOUTしたメールを保存し管理者へ TIMEOUT を
    知らせます。詳細は liblock.pl を見るとわかるでしょう。
    ../references 1.1
    ../references 1.1

    6.8	イベント・スケジューラ

    TIMEOUT 等は現在実行している処理内容によらず特定の時間が来たら(割り込
    んで) 実行する必要がありますがそれは伝統の味 alarm(3) を使って実装しま
    す。なお Windows NT 4.0 Version では alarm(3) が使えないのこの処理は実
    行されません。

    6.9	ロックの仕方(flock でない場合)
    ../troubleshoot 9.2

    ロックアルゴリズムは二通り用意されてます。flockがお奨めです。flock(2)
    参照

    	$USE_FLOCK    = 1; (default 1)

    で flock system call

    	$USE_FLOCK    = 0;

    で大昔からある link(2) を使う方式を使います。この方式はロックするファ
    イルへの link() ができるか否か?を排他制御に使います。このロックするファ
    イルは

    	$LOCK_FILE

    という変数で変更できます。デフォールトは $DIR/var/run/lockfile.v7 です。

    	"$FP_VARRUN_DIR/lockfile.v7"

    つまり ML の home の下の var/run/lockfile.v7 です。この方式の問題は OS
    がいきなり落ちた時にこのファイルが残ってしまうので手動でこのファイル群
    を消さなければならないという点が最大の問題点です。そのため flock() の
    ようなOSが直接ロックを支援する形が望ましいです。

    そういう場合は reboot 直後に

    	"$FP_VARRUN_DIR/lockfile.v7"
    	"$FP_VARRUN_DIR/lockfile.数字"

    すべてを消して下さい。

    fmlの何かプロセスが走っている状態ではどのロックファイルを消していいか
    はプロセステーブルを見る必要があります。数字はプロセス番号ですからプロ
    セステーブルを見て(ps(1))、該当する数字(fml の process)がなければ、そ
    のファイルは消して良いです。

    なお link(2) スタイルの場合 $MAX_TIMEOUT 秒後、var/log/ の下にTIMEOUT
    したメールは保存され管理者へTIMEOUTが通知されます。

    [捕捉]	flock(2) を見れば分かりますが

    	$LOCK_SH                       = 1;
    	$LOCK_EX                       = 2;
    	$LOCK_NB                       = 4;
    	$LOCK_UN                       = 8;

         #include <sys/file.h>
         #define   LOCK_SH   1    /* shared lock */
         #define   LOCK_EX   2    /* exclusive lock */
         #define   LOCK_NB   4    /* don't block when locking */
         #define   LOCK_UN   8    /* unlock */

         int
         flock(int fd, int operation)

    排他制御については例えば A. S. Tanenbaum, "Modern Operating Systems" など

[PREVIOUS CHAPTER] [NEXT CHAPTER]