隠れた便利ツールを活用する

以下のテキストは、執筆時当時の情報を元に書いたものであり、 現在の情勢にそぐわないことを含む場合があるので注意されたい。 また、テキストは最終提出原稿で校正を経る前のものなので、実際にUNIXUSER 本誌に記載されたものとは異なる。誤字脱字等そのままである。

致命的な誤り以外は加筆修正等は行なわないので情報の鮮度に気をつけつつ 利用して欲しい。

目次


【Part 5 まだまだあるぞ(仮)】

Part5では、あまり知られてはいないがとても便利に使える気の利いたツールを
紹介しよう。

■
■clockspeed
■

種々のネットワークサービスを公開するサーバで意外に見落しがちなのが「時刻
合わせ」である。外部のホストとデータのやりとりをするわけであるから、デー
タの持つタイムスタンプがずれてしまったりしては支障をきたすだろう。また、
サーバホストに限らず、ユーザが個人的に使うクライアントマシンでも、電子メ
イルの送信を行なう場合、間違った日付の入ったメッセージを送ったりしては多
くの人にかなり不快な思いをさせることもある。時刻合わせをするためのツール
としてはNTPを利用したntpd(Network Time Protocol Daemon)が一般的である。
NTPでは、GPSなどから基準時刻をもらった Stratum 1 時刻サーバを頂点として、
その時刻を参照する時刻サーバが Stratum 2, 3, ... と木構造の親子関係を形
成する利用形態となっている。このため、NTPによる時刻サーバは常にネットワー
ク接続している必要がある。

clockspeedはCPUのクロックカウンタを利用して内蔵時計の進み方を精密にコン
トロールし、つねに正確な時刻(にとても近い値)を刻み続けさせるためのツール
である【註 い】。ntpdが上位(あるいは兄弟関係の)NTPサーバと同期しながら時
刻を合わせるのと違い、clockspeedは一つのUnixマシンが単体で正確な時刻を刻
み続けるように設計されたツールである。とはいえ、clockspeedを利用する場合
でも、必ずどこかから基準時刻を得る必要があるのでそのためにNTPサーバを参
照する必要がある。

--[註 い]-------------------------------------------------------------
時刻同期では理論的に真の意味で「正確な」時刻を保ち続けることはまず不可能
である。ただし、常にその断り書きを付けても読みづらいので、本稿では標準
時刻との差が無視できる程微小な状態の時計を「正確」と表現することとする)
----------------------------------------------------------------------

●clockspeedの利点

既にntpd導入済みのところでは敢えてclockspeedに入れ換える必要がないように
感じるかもしれないが、以下のような事由に該当するホストの場合は、
clockspeedを採用するのが相応しいだろう。

	* セキュリティ

	  やはりDJBが注意深く書いたツールであり、qmailと同様1998年にリリー
	  ス(0.62)以来問題が見つかっていない。

	* 間欠接続でも利用できる

	  最近では常時接続が手頃になって来たが、まだ必要なときのみインター
	  ネット接続する所もあるだろう。そのような場合でも、数日、あるい
	  は数週間に一度インターネット接続してNTPサーバを参照するだけで
	  十分に正確な時刻を保たせることができるだろう。

	* クロック追随性が高い

	  これは内蔵時計の精度が高い場合にはあまり関係ないが、clockspeed 
	  では3秒に一度強制的にずれを修正してくれるので内蔵時計の精度が
	  かなり低いハードウェアでも定常的に正確な時刻を刻み続けることが
	  できる【註 ろ】。

--[註 ろ]-------------------------------------------------------------
実際のところ筆者の個人所有PCで内蔵時計が不調になり、ntpdで同期しきれなく
なるケースが散見されるようになったものがclockspeedで見事調整できた。詳細
は調べていないのでこれは単なる一事例としてとらえて頂きたい。
----------------------------------------------------------------------

●clockspeedのしくみ

導入作業に入る前に、clockspeedが時計を合わせる考え方について簡単に説明し
ておこう。何の前提知識もなくやみくもに作業をしたのでは効果的な事前準備が
行なえない。

clockspeedでは Pentium CPUのRDTSC(Read Time Stamp Counter)命令または
Solarisシステムのgethrtime()を時刻合わせに利用している【註 は】。
--[註 は]-------------------------------------------------------------
したがって Pentium アーキテクチャで動くシステムか、Solaris のみの対応と
なる。
----------------------------------------------------------------------

たとえば、Pentiumアーキテクチャの場合、電源を入れてからの総クロック数を
64ビットカウンタで覚えていて rdtsc 命令を使うとこれを読み出すことができ
る。近年のCPUでは100MHz over のものがありふれていて、もしこれを時計の発
振子と見立てると1クロックあたり 10^-8秒 という高精度なものとして利用でき
る。clocksppedの時刻合わせでは、まずNTPサーバなどを利用して内蔵時計が合
わせてある状態からスタートする。一定時間経過したところで内蔵時計とNTPサー
バの時刻を比較する。ここでずれている秒数と、スタート時点からのrdtscでク
ロックの進んだカウンタ数を記録する。これにより、クロックカウンタ数あたり
の内蔵時計のずれる秒数が求まるので、以後これを利用して定期的に内蔵時計を
修正して行くことができる。

非常に大まかな説明だが、この考え方を頭に入れて置くと実際の導入作業で起動
するコマンドの意味が明らかになるだろう。さらに、clockspeedを利用する上で
もう一点知っておくべき事柄がある。

●UTCとTAI

唐突だが、1秒の長さは一体どのように決められているかご存じだろうか。時刻
という概念そのものが、一日のリズムを計るために生まれたものなので、かつて
は太陽が南中したときから翌日の南中時までが24時間つまり86400秒という、地
球の天体運動を基準にしたものだった。これは地球の自転速度が変わらない、と
いう大前提に立ったものである。ところが実際には摩擦などで年々非常に僅かだ
が地球の自転速度は遅くなっている。これでは、1 秒の長さが現在と未来で違っ
たものになってしまうため、1967年に1秒の長さはセシウム原子の遷移に対応す
る放射波の9192631770周期の継続時間と定義が変更された。これに基づく時刻体
系をTemps Atomique International (フランス語で国際原子時の意) つまり、
TAIという。これにより、「1秒」が未来永劫不変のものとなって安心できるのだ
が、今度は地球の自転が遅れるごとに実際の生活時刻がずれていってしまう。こ
の不都合を避けるため、1秒の長さは変えずに地球の自転基準による時刻(世界時;
UT1)との差が0.9秒を超えそうになったときに1秒余計に追加することにした。こ
れが「閏秒」である。TAIに閏秒を積算して生活に合うように調整されたものを
協定世界時 UTC(Coordinated Universal Time)と呼ぶ。放送局の時報やNTPサー
バの基準となっているのがUTC である。2002年現在UTCはTAIより32秒遅れた値と
なっている。

さて、Unixに話を戻そう。Unixでは時刻をUnixの「エポック」(1970年1月1日0時
GMT)を起点とする秒数で保持している。これを Unix time といい、たとえば、
1009810800という時刻は日本時間(JST)で2002年1月1日0時0分0秒を意味する。
Unix time をタイムゾーンにしたがった年月日時分秒…形式に変換するのが
localtime()関数である。どのUnixでもlocaltime() はPOSIX規格に則ったものな
のだが、実はこれには閏秒の概念が無いのである。実際に閏秒が起きたときの
xntpdの動作は次のようになる【註 に】。

--[註 に]-------------------------------------------------------------
http://cr.yp.to/proto/utctai.html より引用。
----------------------------------------------------------------------

	1997-06-30 23:59:59.7 UTC -> 867715199.7 xntpd
	1997-06-30 23:59:59.8 UTC -> 867715199.8 xntpd
	1997-06-30 23:59:59.9 UTC -> 867715199.9 xntpd
	1997-06-30 23:59:60.0 UTC -> 867715200.0 xntpd
	1997-06-30 23:59:60.1 UTC -> 867715200.1 xntpd
	1997-06-30 23:59:60.2 UTC -> 867715200.2 xntpd
	1997-06-30 23:59:60.3 UTC -> 867715200.3 xntpd
	1997-06-30 23:59:60.4 UTC -> 867715200.4 xntpd
	1997-06-30 23:59:60.5 UTC -> 867715200.5 xntpd
	1997-06-30 23:59:60.6 UTC -> 867715200.6 xntpd
	1997-06-30 23:59:60.7 UTC -> 867715200.7 xntpd
	1997-06-30 23:59:60.8 UTC -> 867715200.8 xntpd
	1997-06-30 23:59:60.9 UTC -> 867715200.9 xntpd
	1997-07-01 00:00:00.0 UTC -> 867715200.0 xntpd
	1997-07-01 00:00:00.1 UTC -> 867715200.1 xntpd
	1997-07-01 00:00:00.2 UTC -> 867715200.2 xntpd

つまり、 23:59:60.9 UTC が 00:00:00.0 UTC に変わると同時に、Unix time を
巻き戻しているのである。時刻の連続性がこのときに失われる。何年かに一度1
秒間だけ発生することなので「些細なこと」と済ますこともできるが、実際のと
ころこれを直すのは難しくないので多くのベンダは、「TAI+閏秒」の処理ができ
るライブラリを作っていることが多い。幸いなことに、PC-UnixではどれもPOSIX
規格の処理をデフォルトにしつつも、閏秒処理できるものも選べるようになって
いる。

clockspeedでは、時刻の連続性を守れるように、TAIベースで内蔵時計を処理す
る仕様となっている。利用しているOSに応じて、閏秒処理できるようにタイムゾー
ン情報を書き換える必要がある(後述)。


●clockspeedの導入

原稿執筆時のclockspeedの最新版は clockspeed-0.62 で
http://cr.yp.to/clockspeed.html または今月号付録CD-ROMから入手する。
clockspeedの導入は、次のような手順で行なう。

	1. clockspeedパッケージのコンパイルとインストール
	2. クロックの測定と調整(1週間〜1ヶ月)
	3. 閏秒処理への切り替え
	4. taiclockdの起動 (LAN内の時刻サーバとする場合)


1. clockspeedパッケージのコンパイルとインストール

   ソースアーカイブ clockspeed-0.62.tar.gz を適当な作業ディレクトリに展
   開しインストールドキュメントに目を通そう。

	# tar vxpf clockspeed-0.62.tar.gz
	# cd clockspeed-0.62
	# less INSTALL

   コンパイルの要領はqmailなどと同様である。コンパイル時の環境は conf-*
   ファイルに記述されていて、デフォルトでは以下のようになっている。

	% head conf-*
	==> conf-cc <==
	gcc -O2
	
	This will be used to compile .c files.
	
	==> conf-home <==
	/usr/local/clockspeed
	
	This is the clockspeed home directory. Programs will be installed in
	.../bin.
	
	==> conf-ld <==
	gcc -s
	
	This will be used to link .o files into an executable.

   インストール先は conf-home を書き換えることで変更できる。デフォルトで
   は、/usr/local/clockspeed 以下にインストールされる(コマンド群は
   /usr/local/clockspeed/bin に入る)。

   先にプログラムのコンパイル【註 ち】と、マニュアルページの作成を行なう。

	% make

   続いて、rootユーザとなりファイル群をインストールする。

	% su
	# make setup check

   これで /usr/local/clockspeed 以下に関連ファイルがインストールされ、さ
   らに /etc/leapsecs.dat がコピーされる。このファイルは、TAI制定後に挿
   入された閏秒の一覧が記録されるものである。

   また、以後の作業で clockspeed の各種コマンドを多用するので、コマンド
   サーチパス($PATH)に /usr/local/clockspeed/bin を足しておこう。

---[註 ち]------------------------------------------------------------
最近の Linux では clockview.c のコンパイルでエラーが出るかもしれない。
その場合、
http://www.geocrawler.com/archives/3/509/2001/3/0/5427615/
が参考になるだろう。
----------------------------------------------------------------------

2. クロックの測定と調整(1時間〜1週間〜1ヶ月)

   NTPサーバのうち、ネットワーク的に一番近いものを探す。日本国内で利用で
   きるNTPサーバは http://www.kt.rim.or.jp/~ksakai/ntp.html などで知るこ
   とができる。ただし通常は契約しているISP、または大学や企業などの大きな
   ネットワークであれば、ネットワーク管理部門にたいていNTPサーバを置いて
   いて然るべきである、外を探す前にすぐ上流の管理者に問い合わせてみて欲
   しい。エチケットの問題もあるが、ネットワーク的に近いサーバからの方が
   正確な時刻を得られやすいという利点もある。

   以下の例では ntp.koeki-u.ac.jp(211.120.119.69; Stratum 2) をNTPサーバ
   として利用するものとする。211.120.119.69 の部分は読者自身の管理するホ
   ストから、ネットワークトポロジ的に近い距離にあるNTPサーバのIPアドレス
   に読みかえて欲しい。

   まず、NTPサーバの基準時刻と現在の内蔵時計のずれを表示する。

	% sntpclock 211.120.119.69 | clockview
	  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	before: 2002-05-09 17:01:03.362059000000000000
	after:  2002-05-09 17:01:04.421865999951221048

   二つの時刻が表示されたなら、NTPサーバからの時刻獲得がうまくいっている。
   そうでない場合は別のNTPサーバを探してやり直す。

   続いて root になり、NTPサーバからもらった基準時刻を内蔵時計にセットす
   る。

	# sntpclock 211.120.119.69 | clockadd

   すると、clockviewによるずれの表示が減少しているはずである。

	% sntpclock 211.120.119.69 | clockview
	  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	  before: 2002-05-09 17:18:18.855419000000000000
	  after:  2002-05-09 17:18:18.853083999849356710

   この状態を起点として、clockspeedを起動し、初回時刻調整を行なう。

	# clockspeed &
	# sntpclock 211.120.119.69 > /usr/local/clockspeed/adjust &

   ここで数時間休憩する(重要)。その間に次項の「閏秒処理への切り替え」を
   済ませておくと良いだろう。数時間経過したら、二回目の時刻調整を行なう。

	# sntpclock 211.120.119.69 > /usr/local/clockspeed/adjust &

   これにより、初回と二回目の時刻調整の間隔を測定基準とする内蔵時計調整
   パラメータが設定される。以後、測定誤差をなるべく小さくして行くために
   調整作業の時間的間隔を指数関数的に増やしながら時刻調整を行なう。たと
   えば、一週間後、一ヶ月後、一年後、などに

	# sntpclock 211.120.119.69 > /usr/local/clockspeed/adjust &

   する。その都度、
   
	% sntpclock 211.120.119.69 | clockview

   にて、どの程度内蔵時計がずれているかを確認すると良いだろう。数ヶ月の
   のちには、NTPサーバに全く頼らずに「1世紀あたり数秒」の精度でNTPサーバ
   の基準時刻と同期し続ける内蔵時計になるだろう。

3. 閏秒処理への切り替え【註 ほ】

--[註 ほ]-------------------------------------------------------------
Pentium アーキテクチャで動くOSでの利用を前提とするので、以下の説明で
は、PC-Unixのみを想定している。実際には、FreeBSD, NetBSD, RedHat系
Linux、Debian/GNU Linux でのみ確認を行なった。
----------------------------------------------------------------------

   手元のハードウェアでclockspeedの動作が確認でき、実際に継続利用する意
   志が固まったら、システムを閏秒対応にしよう。

   clockspeedを導入しようとしているUnixマシンに、/etc/localtime があるこ
   とを確認して欲しい。これは、ローカルタイム情報を持ったファイルで、シ
   ステムによっては /usr/share/zoneinfo 内のファイルへのシンボリックリン
   クになっているものもあるだろう。/usr/share/zoneinfo ディレクトリには、
   Unix time を世界各地域での標準時に変換するためのタイムゾーンファイル
   が格納されている。システム全体を閏秒対応させるためには、

	1. /usr/share/zoneinfo のタイムゾーンファイル全体の置き換え
	2. 置き換えたタイムゾーンファイルを /etc/localtime にコピー

   の二つの処理を行なえば良い。以下、それぞれの方法をOSごとに示す。どれ
   もJSTの場合の作業例なので、JST以外のタイムゾーンで行なうときは適宜読
   みかえて欲しい。また、いずれも /usr/share/zoneinfo ディレクトリを書き
   換えるので、心配な場合はバックアップを取っておくと良いだろう。

   * FreeBSD

     (1)まずFreeBSDのソースディストリビューションをインストールしよう。
     ディスクに余裕の無い場合は /usr/share のソース(src/sshare.*) だけイ
     ンストールすれば良いだろう。インストールした状態で、
     /usr/src/share/zoneinfo/Makefile を参照して欲しい。make変数
     LEAPSECONDSが定義されている場合に、閏秒処理するものがインストールさ
     れる。root権限で以下のように実行すると完了する。

	# cd /usr/src/share/zoneinfo
	# make LEAPSECONDS=yes install

     (2)続いて、更新された /usr/share/zoneinfo/Asia/Tokyo を
     /etc/localtime にコピーする。

	# rm -f /etc/localtime
	# cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

   * NetBSD

     (1)FreeBSD同様 /usr/share のソースを入手し展開しておく。
     /usr/src/share/zoneinfo/Makefile を確認してから、次のようにインストー
     ルを行なう。

	# cd /usr/src/share/zoneinfo
	#  make REDO=right_posix install

     (2)/etc/localtime を更新する。

	# rm -f /etc/localtime
	# cp /usr/share/zoneinfo/Japan /etc/localtime

   * Linux全般

      (1)既に /usr/share/zoneinfo に、POSIX規格のものと、閏秒対応のもの
      両方のタイムゾーンファイル両方がインストールされている。それぞれ、
      /usr/share/zoneinfo/posix, /usr/share/zoneinfo/right であり、デフォ
      ルトでは前者のディレクトリ内のファイル群が /usr/share/zoneinfo に
      同じ配置で置かれている。これらを right ディレクトリ内のもので置き
      換えれば良い。

	# cd /usr/share/zoneinfo/right
	# cp -r * ..

     (2)/etc/localtime を更新する。

	# rm -f /etc/localtime
	# cp /usr/share/zoneinfo/Japan /etc/localtime

   ちなみに、タイムゾーンファイルはデータファイルなので別のOSのものをコ
   ピーしても構わない。OSのソースにアクセスするのが困難な場合は、付録
   CD-ROMに、NetBSD/i386 1.5ZCの閏秒対応化したタイムゾーンファイルを格納
   したので試しに利用してみるのも良いだろう(ただし自己責任で、バックアッ
   プを取ってから試して欲しい)。

   
4. taiclockdの起動 (LAN内の時刻サーバとする場合)

   clocksppedパッケージには、LAN内で時刻同期するための taiclockd が用意
   されている。時刻サーバを作るためには、clockspeedを走らせているホスト
   上で taiclockd を起動するだけでよい。

	% taiclockd &

   これは一般ユーザ権限で構わない。

   手順3で時刻調整するときに利用した sntpclock コマンドの代わりに、
   クライアントホストでは、taiclock コマンドを利用する。この点以外は1〜3
   の手順と同じことを繰り返せば良い。簡潔に作業例を記述すると以下のよう
   になる(taiclockdを起動したLAN内時刻サーバのアドレスを10.0.0.110とする)。

	時刻のずれを確認する
	% taiclock 10.0.0.110 > adjustment
	% clockview < adjustment

	rootになり、taiclockdホストの持つ時刻に合わせる。
	# clockadd < adjustment

	clockspeedを起動し、初回の時刻調整を行なう。
	# clockspeed &
	# taiclock 10.0.0.110 > /usr/local/clockspeed/adjust &

	この時刻調整を数時間後、1日後、1ヶ月後....という風に間隔を延ばし
	ながら繰り返す。

   なお、手順 3, 4 で行なっている時刻調整は必ずしもrootで行なう必要はな
   い。その場合 /usr/local/clockspeed/adjust ファイルを一般ユーザ(時刻管
   理する人自身のユーザにすると良い)の所有に変更しておけば良い。

●clockspeedの組込み

インストールと時刻調整が済んだら、システム起動時にclockspeedが起動される
ようにしよう。これも、daemontoolsのサービスディレクトリにしておけば、
svscanが自動的に検出して起動してくれる。clockspeed起動のためのサービスディ
レクトリを作成しよう。以下の例では、/usr/local/clockspeed/clockspeed と
いうディレクトリをサービスディレクトリとしている。

	# mkdir /usr/local/clockspeed/clockspeed
	# cd /usr/local/clockspeed/clockspeed
	# touch run
	# chmod +x run
	# vi run
	(以下の内容にする)
---[ /usr/local/clockspeed/clockspeed/run ]---------------------------
#!/bin/sh
exec 2>&1
echo 'Starting clockspeed...'
exec env - PATH="$PATH" \
/usr/local/clockspeed/bin/clockspeed
----------------------------------------------------------------------

なお、電源を落とす時間の長いホストの場合は、runスクリプトでclockspeedを
起動する前(上記リストなら2行目)に、

	/usr/local/clockspeed/bin/sntpclock 211.120.119.69 \
		| /usr/local/clockspeed/bin/clockadd

のような直接的な時刻合わせのコマンドを入れておいた方が良いかもしれない。

runスクリプトが完成したら、/service ディレクトリにシンボリックリンクを張
る。もし、コマンドラインから clockspeed を起動していたら最初にclockspeed
をkillするのを忘れずに。

	# kill 「clockspeedのPID」
	# ln -s /usr/local/clockspeed/clockspeed /service
	(5秒程待ってから)
	# svstat /service/clockspeed

●時刻の正確さの調査

一度このようなツールを入れると、内蔵時計がどの程度ずれているかがしばらく
の間非常に気になるようになる(笑)。また、clockspeedを入れるかどうか悩んで
いる人は、本当にそんなに正確な時計に変身できるのかが気になるところだろう。
そこで、筆者の環境で試した結果を簡単に紹介しよう。まず始めに「正確な時計」
とは何かを考える必要がある。clockspeedは、インストール初期に参照するNTP 
サーバの持つ時刻と同期することを目的としている。ただし、NTPサーバの持つ
内蔵時計も完ぺきにUTCと等しいわけではなく、実用上無視できる程度の微小な
誤差を常に持っている。したがって、ある時点t1でのUTCとの誤差が小さいこと
を「正確」と呼ぶよりも、じゅうぶん長い時間が経過した後(t2)のUTCとの誤差
が、t1での誤差とほとんど変わらないことのほうが重要である。つまり、

	誤差t2 - 誤差t1

がゼロに近ければ近い程良い。リスト【へ】のシェルスクリプトは、内蔵時計と
NTPサーバの時刻の差を表示するものである(簡単のため不完全な部分を含む)。

---[リスト へ clockcheck.sh]------------------------------------------
#!/bin/sh
#以下のNTPサーバアドレスは適宜変更すること
SNTPSV=211.120.119.69
PATH=/usr/local/clockspeed/bin:$PATH

check () {
  echo -n "`date` "
  echo `sntpclock $SNTPSV | clockview \
	| awk -F: '{print $NF}' | tr '\012' '-' \
	| sed 's/-$//'` | bc -l
}

while true; do
  check
  sleep 10
done
----------------------------------------------------------------------

このシェルスクリプトを利用して筆者の環境

	CPU:	Athlon XP 2000+
	OS:	NetBSD 1.5ZC

でclockspeedを運用したときの時計の正確性を調べてみた。時刻調整は同一組織
内にある Stratum 2 NTPサーバを利用し、「1週間」の調整間隔で行なった。そ
ののちリスト【へ】のclockcheck.shを利用して、このマシンの内蔵時計の時刻
を、同一組織内でGPSと直結した Stratum 1 NTP サーバと比較してみた。以下が
その実行結果である。ネットワーク遅延の揺らぎなどもあるので5回の平均値で
比較した。

	時点 t1
	Thu May  9 22:32:01 JST 2002 -.021324499860517680
	Thu May  9 22:32:11 JST 2002 -.021237499778561293
	Thu May  9 22:32:21 JST 2002 -.021186499866738915
	Thu May  9 22:32:31 JST 2002 -.021297999775581061
	Thu May  9 22:32:41 JST 2002 -.021248499933503567
	(以上5回の平均値 = -0.021258999842980505)

	t1の1時間後
	Thu May  9 23:32:01 JST 2002 -.021898999815851449
	Thu May  9 23:32:11 JST 2002 -.021811499922394752
	Thu May  9 23:32:21 JST 2002 -.021762499892465770
	Thu May  9 23:32:31 JST 2002 -.021873499859705567
	Thu May  9 23:32:41 JST 2002 -.021823999831154942
	(以上5回の平均値 = -0.021834099864314498)

	その差 ≒ -0.0213 - (-0.0218) = 0.0005

1時間あたり 0.0005 秒の誤差変動は、1ヶ月に換算すると 0.0005*24*30=0.36秒
の誤差変動となる。つまり、約1週間の時刻同期調整をするだけで「1ヶ月あたり
約0.4秒の誤差」の精度を持つ時計が得られる。さらに1ヶ月後に時刻調整をすれ
ば1年は十分に正確な時刻を刻み続ける精度が得られるだろう。

●まとめ

clockspeedは、閏秒も正常に扱えるし、定常的に正確な時刻を刻み続けられ、プ
ログラムの安全性も高い、という「客観的」なメリットも確かに大きい。その一
方で、自分の管理する計算機が自身の力だけで極めて高い精度で時を刻み続ける
ようになるのは、あたかも超高級クォーツ時計を手に入れたかのような嬉しさが
ある。実際のところこのような感性に訴えるメリットの方が大きいようにも感じ
る。ぜひ一度、clockspeedで「超高級時計」を手に入れてみて頂きたい。


■
■ publicfile
■

ADSLなどの手ごろな価格のインターネット常時接続が普及して、随分と多くの人
がその恩恵にあずかれるようになった。常時接続環境を手に入れたのちに最初に
やりたくなることの一つが外部に向けてのコンテンツ公開だろう。ところがその
ような意欲があるいっぽうで、サーバのセキュリティホールが将来見つかったと
きに気づかないままでいて、そのときに外部から悪者にアタックされたらどうな
るだろう…という不安感は付きまとう。実際のところまめにサーバソフトウェア
のバージョンアップをしていれば大丈夫だといえるが、もし、自分で公開したい
コンテンツサーバに必要以上の機能を望まないのならば、迷わず publicfile を
選ぼう。「お客さん向け」のほとんど使われないような機能は全てそぎ落とし、
純粋にファイルを公開する目的での利用に特化したものがpublicfileである。も
ちろん、これまでにプログラムの問題点が発見されたことは、無い。

http://cr.yp.to/publicfile.html より、publicfileの特徴をまとめると以下の
ようになる。

	* コマンドリクエストを受け付ける前には公開ファイルエリアに
          chroot()し、root権限も剥ぎ落とす。
	* ユーザに「ログイン」をいっさいさせない。このため侵入者がユー
          ザ名とパスワードチェックのためにpublicfileを使うことはできない。
	* ファイルの属性が、user, group, other いずれかに読み取り不能に
          設定されたものは、外部からの取得を拒否する。
	* 公開ファイルエリアは一切改変しない。HTTP, FTPどちらで
          もサーバエリアの修正のためのあらゆるコマンドを拒否する。
	* 外部プログラムの実行は一切しない。HTTP CGI(★ い)や、FTP
          SITE EXECはサポートしない。
	* stdioのようなバグの入りやすいライブラリを使っていない。

---[★ い]-----------------------------------------------------------
shttpd(http://www.superscript.com/shttpd/intro.html) などを使うと
良いだろう。
---------------------------------------------------------------------

●publicfileのインストール

原稿執筆時の publicfile の最新版は publicfile-0.52.tar.gz である。これは 
http://cr.yp.to/publicfile.html から "How to install publicfile" のリン
クをたどると入手できる。また、今月号付録CD-ROMにも収録したので利用して欲
しい。これも他のDJBツールと同様、以下の手順でインストールが完了する。

	# gzip -dc publicfile-0.52.tar.gz
	# cd publicfile-0.52
	# make
	# make setup check

デフォルトでは、/usr/local/publicfile/bin にpublicfileのコマンド群がイン
ストールされる。もし、これを変更したい場合はソースディレクトリの
conf-home ファイルを書き換えてからmakeすれば良い。以下の解説では、デフォ
ルト通り /usr/local/publicfile/bin にインストールしたものと仮定する。

●publicfileの動作設定

publicfileのインストールが終わると、ftpサーバとWebサーバ両方が利用できる
ようになる。djbdnsでtinydns-confを利用したのと類似して、pubilcfileでも公
開用のディレクトリをセットアップするユーティリティがあるのでそれを利用す
る。configureコマンドでは、ftpdとhttpdを起動するための、daemontools 用サー
ビスディレクトリがそれぞれ1つずつと、デフォルトのコンテンツ配置用ディレ
クトリが作成される。configure コマンドは以下の書式で利用する。

/usr/local/publicfile/bin/configure      ...

各引数の意味は以下のようになっている。

			デーモンを走らせるアカウント(このアカウントの
			UID/GID でプロセスが走る)
		ログファイルの所有者となるアカウント(関連プロセ
			スmultilogがこのアカウントのUID/GIDで走る)
			ftpd, httpd で公開するファイルを含むトップディレ
			クトリ(configureコマンドがmkdirしてくれるので未
			作成のディレクトリを指定する)
			サーバとなるホスト名
			同IPアドレス
	...		公開ホスト名が複数あれば何個でも指定できる

例として

	アカウント		public
	ログアカウント		publiclog
	公開ディレクトリ	/archive/public
	ホスト名		ftp.uu.ymzk.org
				www.uu.ymzk.org
	IPアドレス		10.0.0.21

という条件で anonymous ftp サーバとWebサーバを立ち上げるものとしよう。
publicfileによるサーバ構築は次の4段階で行なう。

	1. デーモン起動用アカウントの作成
	2. 公開用ディレクトリの準備
	3. configureコマンドによるサービスディレクトリ作成
	4. サービス起動

以下、順を追って行こう。


1. デーモン起動用アカウントの作成

   まずデーモン走行用のアカウント public を作成する。ここでは、このアカ
   ウントの所属グループを public としてみた。

	(Solaris2, Linux, NetBSD, OpenBSDの場合)
	# groupadd public
	# useradd -s /bin/noshell -d /opt/public/ftpd -g public public
	(FreeBSDの場合)
	# pw groupadd public
	# pw useradd public -g public -s /noshell -d /opt/public/ftpd

   続いてログ用アカウント publiclog を作成する

	(Solaris2, Linux, NetBSD, OpenBSDの場合)
	# useradd -s /bin/noshell -d /opt/public/ftpd/log -g public publiclog
	(FreeBSDの場合)
	# pw useradd publiclog -g public -s /noshell -d /opt/public/ftpd/log

2. 公開用ディレクトリの準備

   今回の例では /archive/public をトップディレクトリとする。ただし、この
   ディレクトリの内容は publicfile のconfigureコマンドが作成してくれるの
   で、管理者は /archive/public ディレクトリを用意する必要はない。という
   よりもむしろ、既に存在するとconfigureコマンドが上書きを回避するために
   なにもせずに終了するので、mkdirすらもしないでおく。

3. configureコマンドによるサービスディレクトリ作成

   サービス用ディレクトリを作成する。

	# /usr/local/publicfile/bin/configure \
	    public publiclog /archive/public ftp.uu.ymzk.org 10.0.0.21 \
	    www.uu.ymzk.org

   これにより、/archive/public ディレクトリが【リスト へ】のような内容で作成
   される。
【リスト へ】------------------------------------------------------------
# ls -lF /archive/public
total 3
drwxr-sr-x  3 root  wheel  512 May 11 00:53 file/
drwx--S--T  3 root  wheel  512 May 11 00:53 ftpd/
drwx--S--T  3 root  wheel  512 May 11 00:53 httpd/

# ls -lF /archive/public/*
/archive/public/file:
total 1
drwxr-sr-x  2 root  wheel  512 May 11 00:53 0/
lrwxr-xr-x  1 root  wheel    1 May 11 00:53 10.0.0.21@ -> 0
lrwxr-xr-x  1 root  wheel    1 May 11 00:53 ftp.uu.ymzk.org@ -> 0
lrwxr-xr-x  1 root  wheel    1 May 11 00:53 www.uu.ymzk.org@ -> 0

/archive/public/ftpd:
total 2
drwxr-sr-x  3 root  wheel  512 May 11 00:53 log/
-rwxr-xr-x  1 root  wheel  176 May 11 00:53 run*

/archive/public/httpd:
total 2
drwxr-sr-x  3 root  wheel  512 May 11 00:53 log/
-rwxr-xr-x  1 root  wheel  152 May 11 00:53 run*
----------------------------------------------------------------------

4. サービス起動

   /archive/public/ftpd, /archive/public/httpd 各ディレクトリには
   daemontoolsでの管理を想定して、すでに run スクリプトができている。一
   度は二つの run スクリプトの内容を確認しておこう。

# head */run
==> ftpd/run <==
#!/bin/sh
exec 2>&1
exec envuidgid public softlimit -o20 -d50000 tcpserver -vUDRHl0 -b20 -c40 -B'220 Features: a p .
' 0 21 /usr/local/publicfile/bin/ftpd /archive/public/file

==> httpd/run <==
#!/bin/sh
exec 2>&1
exec envuidgid public softlimit -o20 -d50000 tcpserver -vUDRHl0 -b50 -c100 0 80 /usr/local/publicfile/bin/httpd /archive/public/file

   これらのスクリプトで気をつけるべき点は二つ。

	A softlimit コマンドで課せられているリソースリミットでデーモンが
          起動できるか
	B コマンドサーチパス(PATH変数)の設定が無くても大丈夫か

   Aについては、実際にコマンドラインから run スクリプトを起動して確認
   しよう。ちなみに筆者の環境(NetBSD 1.5ZC)ではデフォルトのsoftlimit設
   定ではメモリ割り当てエラーで起動できなかった。

	# /archive/public/httpd/run
	  ~~~~~~~~~~~~~~~~~~~~~~~~~
	mmap of bss failed: Cannot allocate memory

   この場合 softlimit の -d (データセグメントリミット)を調整する。

	# vi /archive/public/httpd/run
	(softlimitの部分を変更)

	exec envuidgid public softlimit -o20 -d50000  ……(以下略)
					       ~~~~~
	↓
	exec envuidgid public softlimit -o20 -d100000  ……(以下略)
					       ~~~~~~
   再度 run スクリプトをコマンドラインから起動してhttpdが動くことを確
   認する。

	# /archive/public/httpd/run
	  ~~~~~~~~~~~~~~~~~~~~~~~~~
	tcpserver: status: 0/100

   Bに関しては、ucspi-tcp のコマンド群を /usr/local/bin 以外にインストー
   ルしている場合に注意が必要だろう。runスクリプトにPATH変数の追加設定
   を入れよう。

   以上二点の確認が済めばほぼ間違いなくサービス起動できるだろう。
   /service ディレクトリにシンボリックリンクを張ることで自動的に
   起動される。httpdを起動する場合は、

	# ln -s /archive/public/httpd /service

   とし、ftpdを起動する場合は

	# ln -s /archive/public/ftpd /service

   とする。数秒待って、svstatで確認しよう。

	# svstat /service/httpd
	  ~~~~~~~~~~~~~~~~~~~~~
	/service/httpd: up (pid 15240) 5 seconds

	# svstat /service/ftpd
	  ~~~~~~~~~~~~~~~~~~~~
	/service/ftp: up (pid 15255) 4 seconds

   upの時間が0〜1秒より大きくならず、svstatするたびに pid が変わる場合
   は、即座にサービスを止めて、runスクリプトを見直そう。サービスを止め
   るときは以下のようにする。

	(httpdの場合)
	# cd /service/httpd
	# rm /service/httpd
	# svc -dx . log

●publicfile 用のコンテンツ配置

publicfile configure コマンドによって生成されたディレクトリのうち、
file/ ディレクトリがコンテンツを置くためのディレクトリである。あらかじ
めこのディレクトリには 0/ というディレクトリができている。publicfile
ftpd はこのディレクトリを anonymous ftp login ユーザのログインディレク
トリとする。ここにファイルを置いておけば、利用者にファイルを見せること
ができる。また、ログインユーザと結びついたプロセスはこのディレクトリに
chrootする。

いっぽう、httpdでは複数のコンテンツの使いわけが可能となっている。HTTP 
では Virtual Host の指定ができるので、public httpd でもこれを個別に設
定することができる。/archive/public/file にデフォルトで作成されたIP ア
ドレスと、ホスト名のディレクトリはHTTPで指定されたホスト名に対応するコ
ンテンツを保持するディレクトリとなる。たとえば、

	http://virtual.uu.ymzk.org/

という Virtual Host を作りたい場合は

	/archive/public/file/virtual.uu.ymzk.org/

ディレクトリにコンテンツを置けば良い。とくに異なるコンテンツにする必要
が無い場合は、別のディレクトリにシンボリックリンクを張っておくと良いだ
ろう。

	【例】
	# cd /archive/public/file
	# ln -s 0 virtual.uu.ymzk.org

また、ユーザ個人のWebページを持たせたいときは、各ユーザのディレクトリを
作成し、ユーザのホームディレクトリにシンボリックリンクを作成すると良いだ
ろう。
	【例】
	(rootユーザ)
	# cd /archive/public/file/www.uu.ymzk.org
	# mkdir -p users/taro
	# chown taro users/taro
	(taroユーザ)
	% ln -s /archive/public/file/www.uu.ymzk.org/users/taro ~/webpage


●まとめ

不特定多数の人に極力便利なサービスを提供する、ということが主眼でない場合、
publicfile を利用することでセキュリティ上の不安も皆無の「メンテ要らず」
のサーバが構築できるだろう。


yuuji@example.org
Fingerprint16 = FF F9 FF CC E0 FE 5C F7 19 97 28 24 EC 5D 39 BA
HIROSE Yuuji - ASTROLOGY / BIKE / EPO / GUEST BOOK / YaTeX [Tweet]