どさにっきクラウド 〜2009年3月下旬〜

by やまや
<< = >>

2009年3月21日(土)

無題

_ 房総半島一周500km。けっこうな距離なので車中泊の準備をしてったんだけど、日帰りで走りきってしまった:-)。思いのほか見るべきところが少なかったというのが大きいんだが。

tail -f | grep | grep

_ このへん

リアルタイムでログを見る時、tailをよく使うと思います。
tail -f /var/log/httpd/access_log
phpを含み、jpgとpngを含まないログを表示
tail -f /var/log/httpd/access_log | fgrep php | fgrep -v jpg | fgrep -v png
残念でした。後者は「リアルタイム」では見られません。

_ これはリアルタイムで見える。

tail -f filename
これも期待どおり。
tail -f filename | grep hoge
でも、これはダメ。
tail -f filename | grep hoge | grep fuga
grep 2つがダメなので、3つ並べてもやっぱりダメ。

_ なぜか。grep は標準出力が通常の端末かそうでないかをチェックして、ファイルへのリダイレクトやパイプならば出力をバッファリングするから。条件に合う行がファイルに追記されても、grep が内部で持ってるバッファがいっぱいになるまで標準出力への書き出しはおこなわれない。なので、リアルタイムな出力にはならず、しばらくだんまりしたあと一気にガガガッと出力されて、またしばらくだんまり、というのを繰り返すことになる。

_ わかりやすい例。

( echo hoge; sleep 3 ) | grep hoge
これは grep の標準出力が端末なのでバッファリングされず、hoge がすぐ出力されて、その後3秒してからプロンプトが返ってくる。
( echo hoge; sleep 3 ) | grep hoge | cat
これは grep の標準出力がパイプなのでバッファリングされて、3秒たって入力をすべて読み込んだ後にバッファに残っていた hoge が出力される。

_ 少なくとも GNU grep はこのように動作する。今手元にないので確認できないけど、Solaris の grep もたしかそうだったと思う。PCRE のおまけについてくる pcregrep は標準出力が端末の場合でもバッファリングするので、grep が2段ではなく1段でもリアルタイムな出力は得られない。

_ つーわけで、tail -f のうしろに grep を多段につなげても望んだ動作にはならんので、どーしても必要ならば無理矢理ひとつの正規表現にまとめて grep 一発で済ますか、grep のかわりになにかのスクリプト言語を使って毎行フラッシュする grep 相当のワンライナーを書きましょう。


2009年3月23日(月)

無題

_ いつもより10分早くうちを出たときにかぎって、強風で電車がちっとも前に進まずいつもより到着が30分遅れるワナ。

v6 DNS

_ 某所の DNS サーバに AAAA レコードをプレゼントしてみた。

_ IPv6 なんてちっとも普及してないし、実際すでに AAAA を持ってる Web サーバへのアクセスもかぎりなくゼロに近いので、DNS の方もせいぜい数分に1回クエリがある程度かなというのが当初の予想。が、とんでもねぇ。そりゃ v4 に比べたらはるかに少ないけど、v6 でけっこうな数の問い合わせがくる。末端ユーザへの普及はまだまだだけど、サーバ系では地味に増えはじめてるってことなのか。

_ 問い合わせが圧倒的に多いのは FreeBIT の DNS サーバ。逆に言えば、ISP クラスでも v6 トランスポートなキャッシュ DNS を用意してるのは freebit ぐらいしかないということで、なんだかんだいってもやっぱり v6 は僅少。それでも10分ほど観測してただけで数十の v6 アドレスがログに残る程度には使われているようだ。きっと誰かがやると思ってた 〜::dead:beaf な v6 アドレスもしっかり発見したし。

_ しかし 使いきれないほどにアドレスがある ipv6 でも、つい v4 のときのように小さい番号から詰めてアドレスを割り振ってしまうのはどうしようもないな。そんな貧乏根性は捨ててもいいはずなのに。


2009年3月26日(木)

お行儀の悪いデーモン

_ Unix Programming Frequently Asked Questions 日本語訳より 1.7 プログラムをデーモンとして動かすにはどうすればいいですか?

6. ファイルディスクリプタ0、1、2をclose()します。これによって親プロセスから引き継いだ標準入力、出力、エラー出力を解放します。
デーモンがこれをサボるとどうなるか。

_ とくに ssh でリモートログインした先のホストでそういうデーモンを起動するときに困る。いや、起動はふつーにできるんだ、なんの問題もなく。でも、デーモン起動後も stdin/out/err が端末に結びついたままなので、ログアウトしようとしてシェルを終了した後も、入出力の口を残すために ssh の接続が切断されないままずっと残り続ける。たいていのデーモンはそんな口があったところでまったく使わないので、ログアウトで端末が無応答になり固まったかのように見えることになる。

_ つーわけで、mailman を使ってる人は起動スクリプトの

/path/to/mailmanctl -s -q start
になってるところを
/path/to/mailmanctl -s -q start <&- >&- 2>&-
のように標準入出力を端末から切り離した状態で起動するように書き換えておきましょう。ssh 経由で起動した後でも正常にログアウトできるようになります。

_ (3/27 補足) >&- で切り離すのはよろしくないとのことで。詳しくは こっちを参照。


2009年3月27日(金)

</dev/null >/dev/null 2>&1

_ きのうの件でお手紙いただきました。ありがとうございます。要約:

_ ためしてみた。

#include <stdio.h>
#include <fcntl.h>
main(){
    int fd;
    fd = open("hoge", O_WRONLY, 0);
    printf("fd=%d\n", fd);
}
コンパイルして実行。
$ ./a.out
fd=-1
コケた。O_CREAT がないからか。
$ touch hoge
$ ./a.out
fd=3
stdin/out/err で 0-2 を使ってるから、その次の3番が割り当てられる、と。

_ stdout を閉じて実行。

$ ./a.out >&-
stdout を閉じてるので printf() の出力はどこに行くんだろうと思ったら、
$ cat hoge
fd=1
最初にオープンしたファイルの記述子が1番になってて、そっちに書かれてた。

_ そんなわけで、<&- >&- 2>&- で実行すると、ふつーにオープンしたファイルが閉じたことで空いたディスクリプタに割り当てられてしまうので、その後で標準出力や標準エラー出力(のつもりのディスクリプタ)になんか書くと、別のファイルに書き込んじゃってぶっこわしちゃうよ、と。

_ それを避けるためには、閉じるんじゃなくて開けたまま </dev/null >/dev/null 2>&1 のようにリダイレクトしておけ、と。 きのう引用したとこ

7. stdin、stdout、stderr用に新しいディスクリプタをオープンします。使うつもりがなくても、オープンしておくことは良い考えです。
「良い考え」ってのはそういうことだったのね。

_ つーことで、mailman の2番目に正しい起動のしかたはこう。

/path/to/mailmanctl -s -q start </dev/null >/dev/null 2>&1
いちばん正しいのは、もちろんこんなことしなくてもいいように mailman 自体を修正すること。


2009年3月30日(月)

postfix で TLS

_ オレオレじゃないホンモノの SSL 証明書をインストールした postfix のサーバ。そこらの MUA でつないでみても、openssl s_client でつないでみても証明書の警告は出ないし、問題ないだろう、と思っていたら、おかしなクライアントがあった。そいつの名は…… postfix。なんでだよオイ。

_ smtp_tls_security_level = may (相手が TLS 非対応 or オレオレ証明でも気にしない) な postfix で STARTTLS を喋らせると、正しい証明書を持ってる相手につないでるのに送信側のログにはなぜか Untrusted TLS connection と記録されている。えー、なんでー、と試行錯誤しつつ、smtp_tls_security_level = verify (証明書が正しく検証できないところには送らない) と逆により厳しい設定で送らせてみたら何の問題もなくちゃんと Verified TLS connection になる。なんでー。

_ ソースを追ってみると、SSL_get_peer_certificate() でコケてるようなんだけど、ここでコケてんのになんでその後の SSL_get_verify_result() が通るのよ??? わけわかんねぇ。ログレベルを上げてみると、smtp_tls_security_level = verify のときはクライアントに SSL_connect:SSLv3 read server certificate A なログが残るが、may のときは出ない。ソースを読んでも、SSL_get_peer_certificate() の部分は smtp_tls_security_level の設定によって挙動が変わるようなコードには見えないんだけどなんでよ。クライアント側の設定がどっちでも、サーバ側には SSL_accept:SSLv3 write certificate A なログが残ってるんでちゃんと証明書をクライアント側に送ってるはずで、それを拾えていないクライアントがおかしいと思うんだけど、その挙動がまったく理解できん。

_ ここまでの挙動を見てみるとどうもサーバは無実っぽいようにも見えるんだが、困ったことに同じ postfix なクライアントで別のホンモノ SSL 証明書を持ってる sendmail なサーバに STARTTLS してみると、こっちはちゃんと smtp_tls_security_level = may でも Trusted TLS connection になっちゃうので、クライアントが 100% 悪いと断言しきれない。ねー、どこかおかしいの??? さっぱりわからん。だれかおしえて。


<< = >>
やまや