[PREVIOUS CHAPTER] [NEXT CHAPTER]
6 FML のプロセス

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

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


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

なおこの図でわかるとおり、まとめおくりはこれとは"全く別の"プロセスです。
まとめおくりは自動的に作動するわけではありません。
まとめおくりとは、一定時間ごとにスプールされたMLの記事を送ってあげる
"別のプロセス"です。このプロセスは別の仕掛けで定期的に実行されなければ
なりません。
../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	ブートストラップ過程での変数の設定

今の初期化の順番は( elena ML の場合)

	/var/spool/ml/etc/fml/site_init.ph (もし、あれば読み込む)
	/usr/local/fml/default_config.ph
	/var/spool/ml/elena/config.ph
	/var/spool/ml/etc/fml/site_force.ph (もし、あれば読み込む)

の順に読み込んで上書きしていきます。

	/usr/local/fml/default_config.ph

がインストール時に作成され、その中では各変数のデフォルト値が設定されて
います。


6.4	ライブラリのファイルを探す順番 (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.5	設定ファイルのサーチ順番


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

	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 と同様ですね。MLごとではなくそのマシン共通の設定にな
るもの

	tar や gzip はどこにある?

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

site_init.ph は各MLの config.ph の前に評価されデフォールトを決めます。
sitedef.ph は各MLの config.ph の評価後に適用され、各MLの設定を強制的
に書き換えることもできます。それぞれ使いわけると良いでしょう。いずれに
しろ 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.6	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.7	fmlのプロセス(第2段階, %Envelopeの処理)

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

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

6.8	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.9	イベント・スケジューラ

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

6.10	ロックの仕方(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]