天泣記

2006-01-01 (Sun)

#1

clockcount というライブラリをリリースしてみる

という対象で動くかもしれない

なお、サポートしていないが、S/390 にもあるようである

また、MIPS にもだいたいあるのかもしれない (でも、64bit かどうかわからない)

ちなみに Alpha を扱っていないのは、32bit で気に入らないから

2006-01-02 (Mon)

#1

ぷらっとホームが「検証ルーム」なる設備を持っていることを知る

<URL:http://www.plathome.co.jp/about/sangaku.html>

#2

Alpha の最後のチップは EV7z というやつで、これは 1.3GHz である。

<URL:http://www.itmedia.co.jp/news/articles/0408/17/news015.html>

ここで、1.3GHz でカウンタが増加していくと、32bit (4G) があふれるまでには 3秒かかる。

ということは、それ以上の頻度でカウンタを覗いて、あふれていること (値が減っていること) を検出し、あふれた回数を数えれば、数え始めた時点からは連続的に数えられるわけである。

というわけで試しにそうしてみた。(Ruby のスレッドを使うので、Thread.exclusive=true とかやられたり、あるいはプロセスが suspend されたりすると、数え損ねるかもしれない)

なお、原理的にいえば 64bit のカウンタでもあふれた回数を数えれば連続性を伸ばせるという事情は同じわけであるが、64bit だと 3GHz で増加していっても、あふれるまでに 6万年以上かかるので気にしなくてもよいであろう。

#3

しかし、アセンブリ言語っていうのは、疑似命令の文法はけっこう似ているくせに、なんでコメントの文法がちがうのだろう?

2006-01-03 (Tue)

#1

MIPS64 も、Count Register は 32bit らしい (MIPS64 Architecture For Programmers, Volume III: The MIPS64 Privileged Resource Architecture)

まぁ、試せる環境が無いので実装できないが

#2

そういえば、32bit カウンタがあふれるのを検出するスレッドというのは、fork したときに殺されないほうがいい例のひとつだな。

あふれた回数を保持している変数が fork で複製されるからだが。

#3

SPARC-V8+ 用のコードは SPARC-V9 では動かないことに気が付く。64bit な返値を渡す方法が違うのである

SPARC-V8+ だと %o0 に上位 32bit, %o1 に下位 32bit を入れなければならないが、SPARC-V9 だと %o0 に素直に入れておけばよい

(仮定の話として、SPARC-V8+ で上位と下位が逆だったら両方で動くコードを作れる?)

ということは、どうにかして区別して、生成するのを変化させないといけない。コード自体も変えないといけないし、アセンブラを呼び出すコマンドライン引数も変えないといけない

しかし、32bit か 64bit かというのは、ruby を build するときの CFLAGS (LDFLAGS, DLDFLAGS) に -m64 が入っているかどうかから決まるのだが、コンパイラのオプションを解析するのは避けたい

なんかいい方法はあるか?

アセンブラを $(CC) 経由で動かして、プリプロセッサで __sparcv9 を調べるのがいいか?

アセンブリソースをプリプロセスするには... 拡張子を s じゃなくて S にする? うぅむ。試してみると gcc では動くようだが、これって他のコンパイラドライバでは動くんだろうか。

あと、SPARC-V8 で ruby が build されている時には、同じオプションでは SPARC-V8+ にアセンブルできないな。うぅ。

extconf.rb で調べるしか無いか。

2006-01-04 (Wed)

#1

SPARC V9 には Stack Bias なるものがあって、stack pointer や frame pointer は実際のアドレスから 2047bytes ずれているらしい

<URL:http://docs.sun.com/app/docs/doc/806-0477/6j9r2e2bb?a=view>

なんで?

#2

現在、アセンブリ言語で記述しているのは unsigned long long clockcount(void) という signature な関数であるが、これを void clockcount(unsigned long long *) とすれば、sparc では SPARC-V8+ と SPARC-V9 でコードを共通化できる気がする。

x86 と x86_64 もかな。違うかも?

64bit を引数や返値でうけわたすのは calling convention が変化しがちなところで、ポインタにして直接は扱わないようにすれば、そういうところを避けられる?

では、HP PA-RISC や PowerPC ではどうだろう?

size だけじゃなくて endian の違いもあり得るか。考えてみると、gcc の inline assembly はそういうところを扱わなくていいのが便利だなぁ。

#3

bi-endian について調べる。

とりあえず、PowerPC のドキュメントは分かりやすい。(PowerPC User Instruction Set Architecture, Book I, Version 2.02)

しかし... 実効アドレスをいじって、メモリ上の endian を変更せずにプロセッサから見た場合の endian が変わったかのように見せかけるというのは、なんともトリッキー。

でも、MIPS でもインストラクションの説明を見るとそんなかんじだなぁ。(MIPS64 Architecture For Programmers, Volume II: The MIPS64 Instruction Set)

#4

ふと思ったのだが、32bit アプリケーションを 64bit プロセッサで動かしたとき、レジスタの上位 32bit に変な値が残ってしまうとかいうことは無いのだろうか。

2006-01-05 (Thu)

#1 gonzui 拡充 [CODE blog]

debootstrap の sarge というところに載っているパッケージを gonzui にいれる。

gonzui-import -a として apt でとってきたのを直接入れられるのは便利だ。

#2 リポジトリ [CODE blog]

savannah から glibc と emacs のCVSリポジトリをとってきて、ViewCVS で公開してみる

savannah はリポジトリ rsync でとれるのでよろしい

#3 system [CODE blog]

system 関数の呼び出しを調べてみる

https://www.codeblog.org/gonzui/search?q=funcall%3Asystem&fm=all

いくつか眺めると、つぎのようなコードが見つかった

126: static int
127: http_rman(char *url)
128: {
129:     char *pName;
130:     char *pSection;
131:     char buf[200];
132:
133:     /* parse URL: should be /man?command[?section] */
134:     pSection = strrchr(url, '?');
135:     if (!pSection) {
136:         return -1;
137:     }
138:     pName = pSection-1;
139:     *pSection++ = '\0';
140:
141:     pName = strrchr(url, '?');
142:     if (!pName) {
143:         pName = pSection;
144:         pSection = "";
145:     }
146:     else
147:         pName++;
148:
149:     sprintf(buf, "man %s %s | rman -r \"man?%%s?%%s\" -n %s -f html",
150:             pSection, pName, pName);
151:
152:     return system(buf);
153: }

https://www.codeblog.org/gonzui/markup/xc/extras/rman/contrib/http-rman.c?q=package:xc%20funcall:system#l152

url なる変数から切り出した文字列をコマンドライン引数に直接埋め込んでいて怪しい。バッククォートとか考えてんのかね

その呼出元を見ると、あー、gets とか使ってるんですけど

174:         /* read rest of command (just for the sake of it) */
175:         while (gets(url) && url[0] != '\r')
176:             ;
177:
178:         /* command should be GET <url> [HTTP/1.0] */
179:         if (sscanf(buf, "GET %s", url) == 1) {
180:
181:             status  = http_rman(url);

https://www.codeblog.org/gonzui/markup/xc/extras/rman/contrib/http-rman.c?q=funcall:http_rman#l181

2006-01-06 (Fri)

#1 USB連動電源でリモート電源 ON/OFF [CODE blog]

ソフトウェアから電源のON/OFFを行いたいことがある。(それも安価に)

で、どうやって実現するか

そーいう要求のために作られた箱はたしかにあるが高価である。キットは面倒。というわけでUSB連動電源タップがうまく使えればいいのだが...

#2 USB連動電源タップ [CODE blog]

USB連動電源タップというのは、電源タップからUSBケーブルが出ているもので、USBから来る電源が落ちるとタップのスイッチが切れるというものである。提供元が想定している用途はPCの電源を切ったときに周辺機器の電源を自動的に切るためのものであろう。 (なお、USB的には認識されない)

さて、ここで提供元の想定は気にしないことにして、もし、PCの電源自体は切らずに、ソフトウェアでUSBの電源だけをON/OFFできるとすれば、電源タップのスイッチをソフトウェアで制御できることになる。

問題は PC の中で、USB だけを(理想的には各ポートごとに)ON/OFFできるか、というところである。

というところで個人的にはレイヤが下過ぎて手が出ないのであるが、もともとこの要求を持ってきたひと(g新部さん)の指定で次のように printk を入れて試す。

case USB_PORT_FEAT_POWER:
        if (HCS_PPC (ehci->hcs_params)) {
          printk(KERN_INFO "USB_PORT_FEAT_POWER: has HCS_PPC\n");
                writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
                        &ehci->regs->port_status [wIndex]);
        }
        else {
          printk(KERN_INFO "USB_PORT_FEAT_POWER: no HCS_PPC\n");
        }
        break;

https://www.codeblog.org/gonzui/markup/linux-2.6.14.2/drivers/usb/host/ehci-hub.c?q=USB_PORT_FEAT_POWER#l369

はて? insmod, rmmod したが、dmesg にも /var/log/kern.log にも出て来ない。

#3 tDiary wiki style のプラグイン呼び出しで複数行 [CODE blog]

IRC で尋ねてみると、hikidoc になったのならできるということなので、2.1.3 を試すもできない。

CVS からとってきて試すとできた。

さて、どうするか。

2006-01-07 (Sat)

#1

お、HP TestDrive の FreeBSD/IA64 なマシンが生き返っている

んー。make test まではきれいに行くが、test-all 内でブロックするな

調べてみると、BSD の FD_ISSET のバグだった

<URL:http://www.freebsd.org/cgi/query-pr.cgi?pr=ia64/91421>

うぅむ。web からバグレポートして、自動応答で返ってきたメールには次の URL が書いてあるのだが、それでは見えない... しばらくしてから見えるようになった?

<URL:http://www.freebsd.org/cgi/query-pr.cgi?pr=91421>

なお、NetBSD と OpenBSD にも同じ問題があるように見える

しかし、IA64 でなくても LP64 な BSD ならどこでも問題があるように思えるが、今まで誰も気がつかなかったのだろうか

#2

なんか、すぐに commit されたようである。

<URL:http://www.FreeBSD.org/cgi/cvsweb.cgi/src/sys/sys/select.h?rev=1.20&content-type=text/x-cvsweb-markup>

#3

そーいえば --enable-pthread でテストしていなかったと思いだして、FreeBSD/IA64 上でテストする、と、落ちる。

でも、調べてみたら、--enable-pthread における stack 領域の減少による stack overflow であった。

そーいや、yarv は --enable-pthread 強制なんだよなぁ。stack 領域の減少で使い物にならなくなったりして。

2006-01-08 (Sun)

#1

USB連動電源というものの存在を g新部さんに教えた結果、(ハードウェアはコンシューマデバイスだけで) ソフトウェアから AC 電源の ON/OFF ができるようになった模様

<URL:http://www.gniibe.org/log/2006/01/08#elecom-h2h-g4scr>

さて、なんに使えるか?

個人的には評価ボードは扱っていないので、XFD とかだろうか

コンセントを挿せば動き、抜けば止まる、というデバイスであればなんでもいいわけだが、さて

#2 FD_ISSET [CODE blog]

ふと、BSD の FD_ISSET に問題があることに気がついた

・ http://www.freebsd.org/cgi/query-pr.cgi?pr=91421
・ http://www.FreeBSD.org/cgi/cvsweb.cgi/src/sys/sys/select.h?rev=1.20&content-type=text/x-cvsweb-markup

とりあえず見つけた対象の FreeBSD については報告して直してもらった

NetBSD, OpenBSD も同様な感じである、と最初は思ったが、long じゃなくて __int32_t を使っているから問題ないか

・ http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/src/sys/sys/fd_set.h?rev=1.2&content-type=text/x-cvsweb-markup
・ http://www.openbsd.org/cgi-bin/cvsweb/src/sys/sys/select.h?rev=1.8&content-type=text/x-cvsweb-markup

gonzui で検索してみると、FD_ISSETの用法はだいたい if の条件とかに直接使う感じで int にcastされることはないので、それほど問題にはならなさそうではある

https://www.codeblog.org/gonzui/search?q=FD_ISSET&fm=all

とはいえ、int な変数に代入しているとかもないわけではない

https://www.codeblog.org/gonzui/markup/linux-2.6.14.2/fs/fcntl.c?q=path:linux-2.6.14.2/fs/fcntl.c%20funcall:FD_ISSET#l45

linux kernel の中での FD_ISSET の定義はいろいろなようである

https://www.codeblog.org/gonzui/markup/linux-2.6.14.2/include/linux/time.h?q=fundef:FD_ISSET#l122

として __FD_ISSET で定義され、

https://www.codeblog.org/gonzui/search?q=package:linux-2.6.14.2%20fundef:__FD_ISSET

というように __FD_ISSET はアーキテクチャごとに定義されているようである。各定義は != 0 がついているのもあればついていないのもあるが、ついていないのがそのアーキテクチャではいらないことをわかったうえでそうしているのか、考えずにそうなっているのかはよくわからない

#3 UnixArchive [CODE blog]

そういえば、UnixArchive を gonzui に入れたいと思っている

個人的には一般公開直後にダウンロードしてきて手元に保持しているのだが、検索が面倒なのである。また、FD_ISSET のような問題の起源がどこにあるのかを確認するのに必要である

というわけで、ひさしぶりに、 http://minnie.tuhs.org/ からたどって中身をちょっと見てみる

おや、なんか増えてる?以前ダウンロードしたときには net1.tar.gz とかなかったと思うんだけど (あるいはダウンロードに失敗していた?)

#4 FD_ISSET [CODE blog]

NetBSD が __int32_t を使うようになったのは OpenBSD の fork より前のようだ

http://www.levenez.com/unix/history.html をみながら、FreeBSD から矢印が出ているのを少し調べてみる

・ OpenDarwin は int32_t になっているhttp://cvs.opendarwin.org/cgi-bin/cvsweb.cgi/src/xnu/bsd/sys/types.h?rev=1.1.1.3&content-type=text/x-cvsweb-markup
・ DragonFly BSD は unsigned long のままhttp://www.dragonflybsd.org/cgi-bin/cvsweb.cgi/src/sys/sys/types.h?rev=1.11&content-type=text/x-cvsweb-markup
#5 FD_ISSET 問題の起源 [CODE blog]

この問題の起源を考えてみる

まず、FD_ISSET を導入したのは誰だろう?

・ 4.2BSD の types.h には、fd_set はあるが、FD_ISSET はない。select(2) のマニュアルにも載っていない (かわりに、<< で指定する方法が書いてある)
・ 4.3BSD の types.h には、FD_ISSET があり、long (fd_mask型) を返す。ただし、マニュアルには返値の型の記載はない
・ SUSv2 には FD_ISSET は int を返すとある

というわけで、実装を提供したのは 4.3BSD である。しかし、その時点では仕様は曖昧であり、おそらく POSIX などで後から仕様を定義したときに、実装とは微妙にずれたものにしてしまったのであろう。

さて、ここで、sizeof(int) と sizeof(long) が同じであれば実用上の問題は起きないわけである。Unix ではずいぶんと長い間この条件が成り立っていたわけであるが、4.3BSDがリリースされた対象のマシンではどうだったのだろう? 16bit int という可能性はあるだろうか?

2006-01-09 (Mon)

#1 777 は不幸の番号 [CODE blog]

gonzui-import が失敗するものがあるので調べていたところ、テンポラリに作ったディレクトリを再帰的に 777 に chmod するコードがあった

とりあえず除去した後に尋ねてみると、削除できないものがあったからであるという

・ http://lists.sourceforge.jp/mailman/archives/gonzui-devel/2006-January/000405.html
・ http://lists.sourceforge.jp/mailman/archives/gonzui-devel/2005-April/000276.html

せめて 700 であればかなりましだったのに

#2 umask [CODE blog]

Unix的伝統では、open や mkdir でファイルを作成するときには、666 や 777 を引数に指定し、umask で修正して使う、ということになっている (と思う)

しかし、考えてみれば 666, 777 を指定しておいて、安全なパーミッションになるかどうかは環境とユーザ次第、というのは責任をユーザに押しつけている感がしなくもない

#3 DragonFly BSD 1.4 [CODE blog]

DragonFly BSD 1.4 のリリースノートを読む

http://www.dragonflybsd.org/main/release1_4.cgi

・ closefrom システムコールの導入
・ shutdown() がパイプをサポート

というのが気になった

#4 closefrom [CODE blog]

たしかに、closefrom はユーザレベルでは書きにくい

ちゃんとやるんなら、RLIMIT_NOFILE を調べないといけないし、と考えたところで、RLIMIT_NOFILE を調べてもだめなんじゃないかと思いついた

つまり、open して大きな fd を得てから、setrlimit で小さくしたときには、limit より大きな fd が生きていることが有り得るのではないか、という思いつきである

% ruby -ve ' fs = (3..99).map { open("/dev/null") } Process.setrlimit(Process::RLIMIT_NOFILE, 20) p Process.getrlimit(Process::RLIMIT_NOFILE) p fs.last.fileno p fs.last.read' ruby 1.9.0 (2006-01-03) [i686-linux] [20, 20] 100 ""

やはり動くか

#5 daemon がすべての fd を close すべき理由 [CODE blog]

って、なんだっけ?

そういう慣習であることは覚えているが、そういえば理由を覚えていない

変なものを open していると、unmount できないというのはありそう

セキュリティ的な理由はあるだろうか?

2006-01-11 (Wed)

#1 gonzui 安定化 [CODE blog]

gonzui をいじくりまわしてある程度安定化したので、DB を再構築した上でたまっていたrequestを片付ける

2006-01-12 (Thu)

#1 gtk+ [CODE blog]

gonzui で、「gtk+-2.8.7 内の検索結果」というリンクをたどるとおかしいと大和さんに指摘を受けたので調べてみると、リンクが .../search?q=package%3Agtk+-2.8.7+gtk_main というようになっていた。

gtk+ の + がそのままになっているので + が空白に変換されてしまっているらしい。

の話は URI のエスケープ仕様 (RFC3986) と HTML Form のエスケープ仕様 (HTML 4.01) の異なるところで、HTML Form での送信をエミュレートするときには URL の ? 以降 (の各要素) は HTML Form のほうでエスケープしないといけないのだが、ここでは URI のほうを使っていると推測できる。

実際、リンクをたどった後、URL を書き換えて gtk+ を gtk%2B に書き換えてアクセスすると、ちゃんと予期された内容が出てくる。

ソースを見ると、まぁそのとおりで、WEBrick::HTTPUtils.escape_form を使うべきところで WEBrick::HTTPUtils.escape を使っていたので変えたら直った模様。

#2 Referer: https [CODE blog]

https なページから http なページにリンクをたどったとき、ブラウザは Referer を送るべきでないという規則がある。

Clients SHOULD NOT include a Referer header field in a (non-secure)
HTTP request if the referring page was transferred with a secure
protocol.

RFC 2616 15.1.3

ふと思いついて、ある http なサーバのログを見てみたところ、https な Referer がいくつか見つかった。対応する User-Agent は次の通り。

・ Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13
・ Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1
・ FAST Enterprise Crawler/6.4 (helpdesk at fast.no)

Safari は送るってことかな。SHOULD NOT だから、あえてそうするというのであればいけないというわけではないんだけど。

2006-01-13 (Fri)

#1 USB グッズ [CODE blog]

昨日、大和さんにいわれて気がついたわけであるが、べつに USB 連動電源タップを使わなくても、USB扇風機などの USB Bus Power な機器は制御できるわけである。

というわけでどんなものがあるか調べてみる。

まず、有名なのはイーレッツ (というか、線上のメリークリスマス) である。

http://www.e-lets.co.jp/product/aig-xmas5/index.htm

でも、製品紹介にある他の USB グッズは充電器ぐらいで見た目に面白くない。

http://www.e-lets.co.jp/product/

ほかのメーカはどうかということで探してみる。

・ サンコーレアモノショップ http://www.thanko.jp/products/usb.html
・ ロアス http://www.loas.co.jp/novelty/usb/
・ サンワサプライ http://www.sanwa.co.jp/seihin_joho/usbtoy/index.html
・ ソリッドアライアンス (i-Duck わすれんぼう) http://www.solidalliance.com/products/products.html
・ ゲート http://www.gate.jp/top/makers/maker.php?ID=M041

デモとして見た目に面白そうなのは、光るものと扇風機あたりだろうか

#2 スーパーコムサテライト [CODE blog]

コムサテライト3号店というところでは、USB駆動の改造デバイスを売っているらしい。

・ http://www.watch.impress.co.jp/akiba/hotline/20030607/etc_soumen.html
・ http://www.watch.impress.co.jp/akiba/hotline/20050702/etc_somen.html

現在売っているのは USBクリスタルというものだろうか。

http://www.comsate.co.jp/supercom/

なんとなく行って現物を見てみるが、明るいところで観賞するには光量が足りなくて、デモには向かない感じであった。

#3 若松オリジナル XPort ACコントロールKit [CODE blog]

ついでに他の階を回ると XPort ACコントロールKit というものがあった。

http://www.wakamatsu.co.jp/psplaza/cgi-bin/goodslist.cgi?mode=view_goods&sort=&sub_id=0565&goods_id=0006

#4 USB Fan, Light [CODE blog]

買ってみる。ふたつあわせて1000円。

2006-01-14 (Sat)

#1 sun [CODE blog]

ふと、sun というシンボルがいつ定義されるのか調べてみる。

Solaris 8 の cpp(1) には次のようにある。

...
   Hardware:
         interdata,  pdp11,  u370,  u3b,  u3b2,  u3b5,   u3b15,
         u3b20d, vax, ns32000, iAPX286, i386, sparc, and sun
...
   The symbols  sun, sparc and unix are  defined  for  all  Sun
   systems.
...

マニュアル的には、ハードウェアを意味するシンボルのようである。

とすると 2つの疑問がわく。

・ Sun のハードウェア上で稼働する Sun でない OS では定義されるか
・ Sun でないハードウェア上で稼働する Sun の OS では定義されるか

前者の例は Linux/SPARC とかであり、後者は Solaris x86 である。

ここで、わざわざ Sun のハードウェア上で Sun 以外の OS を動かす商用ベンダがいるとも思えないので、前者で使われているコンパイラは主に gcc であろう。

gcc で探してみると、gcc/config/sol2.h で定義されている模様である。

57: #define TARGET_OS_CPP_BUILTINS()                        \
58:     do {                                                \
59:         builtin_define_std ("unix");                   \
60:         builtin_define_std ("sun");                    \

https://www.codeblog.org/gonzui/markup/gcc-4.0.2/gcc/config/sol2.h#l60

TARGET_OS_CPP_BUILTINS の定義なので、OS によって決まるようである。つまり、Linux/SPARC とかでは定義されないのであろう。

Solaris x86 に関してはソースを参照できないが、探してみると、 Sun Studio 11 の cc(1) ではハードウェアを意味するとは書いていない。むしろ常に定義される感じである。とすると、Solaris x86 でも定義されるように思える。

とすると、結論としては、sun は SunOS を意味するということであろう。

2006-01-15 (Sun)

#1

これって何だろう?

<URL:http://gadgets.zive.cz/?q=node/929>

USB なチョキ。

<URL:http://wkcao.en.ec21.com/GC01073869/CA01073881/USB_Massage.html>

マッサージ器らしい。わかってしまえば面白くない。

#2 Mini Power Minder [CODE blog]

日本以外にもUSB連動電源タップはある模様

http://www.cablestogo.com/product.asp?cat%5Fid=1004&sku=34006

2006-01-16 (Mon)

#1

Linux カーネルをいじる必要なく、ユーザスペースで USB の power control ができる模様

<URL:https://www.codeblog.org/blog/gniibe/?date=20060114#p02>

かなりお手軽感が増している (ここまで来ると Hub を選ぶという点がなんとも残念である)

とりあえず USB Fan, Light, Aquarium を ON/OFF してみた

#2

Paul Eggert を見てきた

#3 USB Fan の速度制御 [CODE blog]

ON/OFF の制御が可能なら、時間的に制御してやれば連続的な制御も可能かもしれない。

# while :
do
./hub-ctrl -b 4 -d 3 -P 4 -p 1 # ON
sleep 0.01
./hub-ctrl -b 4 -d 3 -P 4 -p 0 # OFF
sleep 0.1
done

こころもち遅くなっている気がする。

インバータ?

#4 USB Light の光量制御 [CODE blog]

時間的に... やってみると、ちらちらしてよろしくない。

#5 Paul Eggert [CODE blog]

Paul Eggert を生で見たので、gonzui で検索してみよう。

https://www.codeblog.org/gonzui/search?q=%22Paul+Eggert%22&fm=all

configure などの autoconf まわりでひっかかるのは個別の話ではないにしても、 xc, gcc, glibc, apache, linux, base-files, bash, coreutils, diffutils, findutils, gzip, perl, mawk (debian), sed, tar, bsdmainutils, cpio, gettext, groff, texinfo, nvi, emacs, gnutls, gnupg に残っている名前は個々の貢献に思える。

wget は glibc 経由、postgresql は tzdata 経由だろうか。

なんとも手広い。

2006-01-18 (Wed)

#1

Canon のプリンタ (LBP-2810) のトナーを交換し、メッセージに憤りを覚える。

まず、トナーがきれて、印刷不能になった時のメッセージは 「12G C トナーコウカン」というものであった。(メッセージの細部は違っていたかも)

まぁ、C が Cyan の略であるところまでは許すとしよう。わかりにくいが。しかもトナーのカタログの方には C じゃなくてシアンとして出ているし。

しかし、トナーを注文して品物が届き、C トナーを交換してみると、次に「M トナーコウカン」と出てきやがった。

ここで、トナーは C, M, Y, K が別売りである。

したがって、メッセージにしたがって C トナーだけを注文していたとしたら、プリンタは使えるようにならなかったのである。

しかし、幸いにして、C, M, Y, K の一式を注文しておいたので、M トナーも交換すると、(予想通り) 次に「Y トナーコウカン」と出て来る。

で、Y トナーも交換すると、プリンタが使えるようになった。

不幸にして K トナーが余ってしまったが、「K トナーチェック」とメッセージが出ているので、すぐに必要になることであろう。おそらく。

なお、交換の順番は C, M, Y だったが、プリンタ内部のトナーカートリッジの位置は上から K, M, Y, C であり、順序に一貫性がないことに気がついた。

#2

しかし、考えてみると、この問題はなかなか面白いかも知れない。

逐次的にひとつづつ検査して、最初に失敗したところで全体を失敗させると、こういう挙動になるわけである。

期待される挙動は C, M, Y の 3つのトナーを交換するようメッセージを表示することであるが、これを実現するには、失敗が起きても可能な範囲で続きを実行しないといけない。ただし、失敗したところに依存する作業は行ってはいけない。

そういう動作を行う前例としては、make -k やコンパイラのエラーメッセージがある。make -k は失敗してもそれに依存しない所は動作するし、コンパイラは最初の失敗であきらめたりはしない (ものがある)。

でも、そういう動作を自分で書くのはなかなか厄介である。失敗したところに依存しているかどうかをちゃんと判断するのは面倒臭い。

しかし、C, M, Y, K のトナーの検査という例に限って考えれば、4つの検査は独立なため、それほど難しくない。

もし、そういう比較的簡単な例が多いのであれば、そういうのを支援することに意味があるかも知れない。

#3 イルミネーションUSBケーブル [CODE blog]

http://www.watch.impress.co.jp/akiba/hotline/20010421/etc_usbled.html

光るUSBケーブルというものも以前はあったようだが、いまはもうないのか。

2006-01-19 (Thu)

#1 tDiary 2.1.3.20060102 [CODE blog]

testt

2006-01-20 (Fri)

#1 graphviz plugin [CODE blog]

tDiary の graphviz plugin をためしにいじりまわしてみる。

2006-01-21 (Sat)

#1 Various arbitrary Unix stuff [CODE blog]

http://www.in-ulm.de/~mascheck/various/

いろいろと調べられていて素晴らしいが、とくに

・ "#! /" の 4byte で認識するシステムがあったというのはガセ
・ ${1+"$@"} が必要になる状況
・ directory の setuid bit に意味があるシステムは存在した

というのは以前疑問には思ったものの調べがつかなかった話なので、はっきりと調べられているのを読んでかなり感動。

#2 graphviz [CODE blog]

graphviz を gonzui にいれて、system, popen, fork, exec family を探してみる。

tDiary の plugin をいくらいじっても、graphviz 自身に任意のコマンドを実行できる機能があるとまずいからである。

探してみた結果は fork がひとつ見つかった。

https://www.codeblog.org/gonzui/search?q=package%3Agraphviz-2.2.1+funcall%3Afork&fm=c

ただ、これは sfio の中で、この関数は graphviz 本体からはたどり着けなさそうである。

従って、graphviz に渡すデータはユーザが任意に指定できてもいけなくはないと思う。まぁ、仕様としては。

#3 graphviz test [CODE blog]

じゃんけん

6037b747cd99b1bb00f5b9f179689cdaac0b1fe28ae03d5f61520aeb46109e6d.png

ソースは次の通り

{{graphviz_neato('
 digraph じゃんけん {
   ぐー->ちょき;
   ちょき->ぱー;
   ぱー->ぐー;
 }
 ')}}
#4 graphviz [CODE blog]

しかし、graphviz はどうも怪しげな感じである。

テストしている最中に

% nkf -Ue a.dot
digraph test {
  aaa -> aaa;
  aaa->ぱー;
  ぱー->ぐ;
}
% /usr/bin/dot < a.dot
*** glibc detected *** malloc(): memory corruption: 0x08093970 ***

などといわれることもあった。 (テストした環境は i386 だけど)

だから、実装としては、安心して他人に使わせられる感じはしない。

2006-01-22 (Sun)

#1 USB接続OAタップ [CODE blog]

む、商品が出るらしい。

http://www.watch.impress.co.jp/akiba/hotline/20060121/etc_ptu2f3.html

2006-01-23 (Mon)

#1

FreeBSD Problem Report misc/92110 : setcontext restore the carry flag

2006-01-24 (Tue)

#1

NetBSD PR lib/32609 : seekdir blocks if pthread is linked

#2
% google-count eth{0123456789}
1830000 eth0
1370000 eth1
270000  eth2
59400   eth3
24300   eth4
16200   eth5
11100   eth6
11200   eth7
744     eth8
870     eth9
#3
% google-count wd0{abcdefghijklmnopqrstuvwxyz}
106000  wd0a
32000   wd0b
909     wd0c
18000   wd0d
26000   wd0e
12900   wd0f
12900   wd0g
979     wd0h
510     wd0i
601     wd0j
343     wd0k
402     wd0l
468     wd0m
240     wd0n
1020    wd0o
546     wd0p
796     wd0q
1020    wd0r
1310    wd0s
776     wd0t
1110    wd0u
924     wd0v
932     wd0w
254     wd0x
1100    wd0y
1080    wd0z

2006-01-25 (Wed)

#1

おー、OpenBSD rthread かぁ。

#2

とある Debian 環境で apt-get upgrade したら

Errors were encountered while processing:
 kernel-image-2.4.27-2-686

といわれた。

調べてみようかと思ったが、面倒臭くなったので apt-get remove kernel-image-2.4.27-2-686 とした。

% dpkg -l|grep kernel-image
rc  kernel-image-2 2.4.27-10sarge Linux kernel image for version 2.4.27 on PPr
%

残骸が残っているか。dpkg --purge kernel-image-2.4.27-2-686 として除去。

% dpkg -l|grep kernel-image                  
zsh: done       dpkg -l | 
zsh: exit 1     grep kernel-image

ついでに、apt-get --purge remove grub として grub も削除。

あれ、/boot/grub 以下は消えないのか。

% find /boot -ls
305218    4 drwxr-xr-x   3 root     root         4096 Jan 25 14:42 /boot
 96892    4 drwxr-xr-x   2 root     root         4096 Jan 25 15:19 /boot/grub
 96896    4 -rw-r--r--   1 root     root           15 Aug  5 01:43 /boot/grub/device.map
 96893    4 -rw-r--r--   1 root     root          512 Aug  5 01:43 /boot/grub/stage1
 96895  112 -rw-r--r--   1 root     root       108168 Aug  5 01:43 /boot/grub/stage2
 96897    8 -rw-r--r--   1 root     root         7776 Aug  5 01:43 /boot/grub/e2fs_stage1_5
 96898    8 -rw-r--r--   1 root     root         7504 Aug  5 01:43 /boot/grub/fat_stage1_5
 96899   12 -rw-r--r--   1 root     root         8320 Aug  5 01:43 /boot/grub/jfs_stage1_5
 96900    8 -rw-r--r--   1 root     root         7008 Aug  5 01:43 /boot/grub/minix_stage1_5
 96901   12 -rw-r--r--   1 root     root         9216 Aug  5 01:43 /boot/grub/reiserfs_stage1_5
 96902   12 -rw-r--r--   1 root     root         9288 Aug  5 01:43 /boot/grub/xfs_stage1_5
 96904    4 -rw-r--r--   1 root     root         2710 Jan 25 15:19 /boot/grub/menu.lst
 97219    4 -rw-r--r--   1 root     root         2710 Jan 25 15:19 /boot/grub/menu.lst~

そんで、reboot する。とくに問題はない。

やっぱこの環境では kernel はいらないんだよなぁ。

#3 code plugin & PATH_MAX [CODE blog]

xc/config/imake/imake.c:1115-1124

1115: #ifdef CROSSCOMPILE
1116:   if (CrossCompiling) {
1117:       char cmd[PATH_MAX];
1118:       strcpy (cmd, CrossCompileDir);
1119:       strcat (cmd,"/");
1120:       strcat (cmd,ld);
1121:       ldprog = popen (cmd, "r");
1122:   } else
1123: #endif
1124:       ldprog = popen (ld, "r");

code plugin を試す。

なお、PATH_MAX は GNU Hurd では無制限で定義されていないらしいので、こういうコードを書くと動かないようである。

http://www.gnu.org/software/hurd/faq.ja.html#q6-2

#4 PATH_MAX [CODE blog]

xc/config/imake/imake.c:1399-1407

1399:   char buf[PATH_MAX];
1400:   char cmd[PATH_MAX];
1401:   char* ptr;
1402:
1403:   strcpy(cmd,name);
1404:
1405:   buf[0] = '\0';
1406:   strcat (cmd, " --print-libgcc-file-name");
1407:   if ((gccproc = popen (cmd, "r")) != NULL) {

なんというか、PATH_MAX の意味をわかっていない感じである。なんとなく十分に大きな数という認識だろうか。

#5 shell escape [CODE blog]

xc/programs/Xserver/hw/xfree86/xf86cfg/cards.c:558-575

558:     cmd = malloc(32 + (strlen(pattern) * 2) + strlen(Cards));
559:
560:     strcpy(cmd, "egrep -i '^NAME\\ .*");
561:     len = strlen(cmd);
562:     ptr = pattern;
563:     while (*ptr) {
564:         if (!isalnum(*ptr)) {
565:             cmd[len++] = '\\';
566:         }
567:         cmd[len++] = *ptr++;
568:     }
569:     cmd[len] = '\0';
570:     strcat(cmd, ".*$' ");
571:     strcat(cmd, Cards);
572:     strcat(cmd, " | sort");
573:     /*sprintf(cmd, "egrep -i '^NAME\\ .*%s.*$' %s | sort", pattern, Cards);*/
574:
575:     if ((fp = popen(cmd, "r")) == NULL) {

シェルにあたえる引数をエスケープするのに、isalnum が偽になるバイトの前に \ をつけている。これは正しいだろうか?

それはそれとして、とりあえず、char が signed だと負の値を isalnum に渡してしまうのはよろしくない。

#6 code plugin 文字化け [CODE blog]
{{code "xc/programs/Xserver/hw/xfree86/xf86cfg/cards.c", "558-575"}}

と書いたのだが、「\」が「促」に化けてしまうようだ。

#7 xrx [CODE blog]

xc/programs/xrx/helper/GetUrl.c:53-60

53: GetUrl(char *url, char **reply_ret, int *len_ret)
54: {
55:     char buf[BUFSIZ], *reply, *ptr;
56:     FILE *fp;
57:     int readbytes, size;
58:
59:     sprintf(buf, "www -source \"%s\"", url);
60:     fp = popen(buf, "r");

ここも怪しい。ただ、url の起源をたどっていくと、内部で生成しているので、危なくない可能性もある。

ここはソースを読むのと、xrx について調べるのと両方やるのが効率がいいところかもしれない。

xc/programs/xrx/testplugin/testplugin.c:650-662

650: NPError
651: NPN_GetURL(NPP instance, const char *url, const char *window)
652: {
653:     AppData *data = (AppData *)instance->ndata;
654:     char buf[BUFSIZ];
655:     FILE *fp;
656:
657:     if (url == NULL)
658:         return NPERR_INVALID_URL;
659:
660:     /* perform request using "www" */
661:     sprintf(buf, "www -source \"%s\"", url);
662:     fp = popen(buf, "r");

ここも同様。

2006-01-26 (Thu)

#1 FreeBSD PR misc/92110 : setcontext restore the carry flag [CODE blog]

http://www.freebsd.org/cgi/query-pr.cgi?pr=92110

#2 NetBSD PR lib/32609 : seekdir blocks if pthread is linked [CODE blog]

http://www.NetBSD.org/cgi-bin/query-pr-single.pl?number=32609

#3 ffs [CODE blog]

ふと、ffs の用途を考えつき、他のひとは ffs を使っているのかどうか疑問になったので検索してみる。

https://www.codeblog.org/gonzui/search?q=funcall%3Affs&fm=all

X でけっこう使っているようだ。

#4 j0 [CODE blog]

ついでに、j0 も検索してみる。

https://www.codeblog.org/gonzui/search?q=funcall%3Aj0&fm=all

こちらはあまり使われていない。

まぁ、数学関数を使うようなアプリケーションを入れていないからそうなるのも当然か。

#5 shell escape/quote [CODE blog]

system や popen でコマンドに文字列を渡す場合、shell が解釈してしまわないように細工をしてやらなければならない。

まぁ、そんな細工をしなくてもいいようにそもそも shell を使わないというのが最良なこともままあるが、それではあまりに面倒なこともたしかにあるので、どう細工すべきか考えるのも重要ではある。

https://www.codeblog.org/blog/akr/?date=20060125#p03 のケースでは \ を使っていたが、残念ながらあれには穴がある。

SUSv3 を調べると、shell の escape/qoute には次の記法がある。

・ single quote: '' の内部に書いたすべての文字はその文字のままコマンドに渡される。なお、内部に ' を入れることはできない。
・ double quote: "" の内部は、$, `, \ を除いてそのままコマンドに渡される。\ は直後の文字が $, `, ", \, <newline> のときだけ quote 外部の \ と同じ意味になる。
・ escape: (quote の外部の) \ は直後の1文字をそのままコマンドに渡す。ただし、newline は例外で、\<newline> は継続行とみなされ、その2文字が除去される。

というわけで、\ だけでやろうとした先の例では、newline が消えてしまう。

#6 shell escape/quote (2) [CODE blog]

ではどうすればいいかというと、いくつか考えられる。

・ 基本的には \ でやって、newline のところだけ '' または "" を使う
・ "" を使い、内部の $, `, \ に \ を前置する
・ '' を使い、' はいったん ' を閉じて、\' を使う

Ruby で書くと次のような感じである。

def shell_escape_1(str)
  str.gsub(/(\n+)|./) { $1 ? "'#{"\n"*$1.length}'" : "\\#{$&}" }
end

def shell_escape_2(str)
  "\"#{str.gsub(/[$`\\"]/, '\\\\\\&')}\""
end

def shell_escape_3(str)
  str.gsub(/('+)|[^']+/) { $1 ? "\\'" * $1.length : "'#{$&}'" }
end

そういえば、tDiary の graphviz plugin にも shell_escape_2 に類似したコードがあったが、! にも \ を前置するようになっていた。考えてみるとこれはうまくない。

sh-3.1$ echo "\!" |od -c
0000000   \   !  \n
0000003

double quote の内部で、$, `, ", \, <newline> 以外に \ をつけると、\ が残ってしまう。まぁ、わたしが書き換えたバージョンでは、 graphviz を起動するところには shell を使っておらず、エラーメッセージにコマンドラインを含めるところで使っているだけなので、あまりおおきな問題ではない (ということにしよう)。

#7 興味のあるツール [CODE blog]

gcov, lcov, valgrind, callgrind, kcachegrind

2006-01-27 (Fri)

#1 乱数 [CODE blog]

乱数については、以前調べたことがある。

結局、/dev/urandom があればそこから取り出して種にするというのがそこそこまともだという結論に達したのだが、世の中には /dev/urandom ではだめだというひともいるらしい。

・ http://www.securityfocus.com/bid/6855
・ http://icat.nist.gov/icat.cfm?cvename=CAN-2001-0950

/dev/random を使っちゃうと、むしろブロックして危ないと思うのだが、/dev/urandom で本当にまずいケースはあるだろうか。

http://www.securityfocus.com/bid/6855 で指摘されている util-linux のソースは、次のようになっている。

util-linux-2.12r/misc-utils/mcookie.c:37-48,76,132-150

37: #define BUFFERSIZE 4096
38:
39: struct rngs {
40:    const char *path;
41:    int minlength, maxlength;
42: } rngs[] = {
43:    { "/dev/random",              16,  16 }, /* 16 bytes = 128 bits suffice */
44:    { "/proc/interrupts",          0,   0 },
45:    { "/proc/slabinfo",            0,   0 },
46:    { "/proc/stat",                0,   0 },
47:    { "/dev/urandom",             32,  64 },
48: };

...

76:    unsigned char     buf[BUFFERSIZE];

...

132:    for (i = 0; i < RNGS; i++) {
133:       if ((fd = open( rngs[i].path, O_RDONLY|O_NONBLOCK )) >= 0) {
134:          int count = sizeof(buf);
135:
136:          if (rngs[i].maxlength && count > rngs[i].maxlength)
137:             count = rngs[i].maxlength;
138:          r = read( fd, buf, count );
139:          if (r > 0)
140:             MD5Update( &ctx, buf, r );
141:          else
142:             r = 0;
143:          close( fd );
144:          if (Verbose)
145:             fprintf( stderr, _("Got %d bytes from %s\n"), r, rngs[i].path );
146:          if (rngs[i].minlength && r >= rngs[i].minlength)
147:             break;
148:       } else if (Verbose)
149:          fprintf( stderr, _("Could not open %s\n"), rngs[i].path );
150:    }

つまり、/dev/random, /proc/interrupts, /proc/slabinfo, /proc/stat, /dev/urandom を順に O_NONBLOCK で読んでいる。

(そこで Vulnerable とされている Debian 3.0 の util-linux 2.11n を ftp://aist.ring.gr.jp/pub/linux/debian/debian/pool/main/u/util-linux/util-linux_2.11n.orig.tar.gz からとってきて確かめてもコードは同様に見える。)

たしかに、このコードでは /dev/random のエントロピーが枯渇して即座に読めなければ /dev/urandom から読む。でも、それってそんなにいけないことなのだろうか?

あと、そもそもエントロピーが枯渇しているときに /dev/urandom を読むのであれば、/dev/random を読む意味はあるのだろうか?

#2 ruby の乱数 [CODE blog]

以前調べたのは ruby で使うためで、その結果、現在は次のようになっている。

ruby-1.8.3/random.c:256-306

256: random_seed()
257: {
258:     static int n = 0;
259:     struct timeval tv;
260:     int fd;
261:     struct stat statbuf;
262:
263:     int seed_len;
264:     BDIGIT *digits;
265:     unsigned long *seed;
266:     NEWOBJ(big, struct RBignum);
267:     OBJSETUP(big, rb_cBignum, T_BIGNUM);
268:
269:     seed_len = 4 * sizeof(long);
270:     big->sign = 1;
271:     big->len = seed_len / SIZEOF_BDIGITS + 1;
272:     digits = big->digits = ALLOC_N(BDIGIT, big->len);
273:     seed = (unsigned long *)big->digits;
274:
275:     memset(digits, 0, big->len * SIZEOF_BDIGITS);
276:
277: #ifdef S_ISCHR
278:     if ((fd = open("/dev/urandom", O_RDONLY
279: #ifdef O_NONBLOCK
280:             |O_NONBLOCK
281: #endif
282: #ifdef O_NOCTTY
283:             |O_NOCTTY
284: #endif
285: #ifdef O_NOFOLLOW
286:             |O_NOFOLLOW
287: #endif
288:             )) >= 0) {
289:         if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
290:             read(fd, seed, seed_len);
291:         }
292:         close(fd);
293:     }
294: #endif
295:
296:     gettimeofday(&tv, 0);
297:     seed[0] ^= tv.tv_usec;
298:     seed[1] ^= tv.tv_sec;
299:     seed[2] ^= getpid() ^ (n++ << 16);
300:     seed[3] ^= (unsigned long)&seed;
301:
302:     /* set leading-zero-guard if need. */
303:     digits[big->len-1] = digits[big->len-2] <= 1 ? 1 : 0;
304:
305:     return rb_big_norm((VALUE)big);
306: }

/dev/urandom を 4 * sizeof(long) だけ読んで種を生成している。つまり、long の長さによるが、128 ないし 256bit 読む。 (/dev/urandom がなかったときの保険というかごまかしと言うか以前のコードの名残として、時刻などいくつかの情報を xor している)

なお、ruby は Mersenne Twister を内部に抱えていて、こういう長い種もとくに問題なく扱えるし、システムによって生成される乱数が異なることもない。まぁ、ruby のバージョンが変われば変わる可能性はあるが。

こういうコードになったのは ruby-1.8.3 からで、/dev/urandom を使っていなかった他、いくつか問題があった。なので、1.8.3 でいろいろと変えたのだが、乱数だけあって気がつくひとはあまりいない。ただ、何回か、種を設定しても生成される乱数が異なることに気がついたひとはいたようである。あと、srand が以前の種を返すので、

% ruby-1.8.2 -e 'srand; p srand'
1138591551
% ruby-1.8.3 -e 'srand; p srand'
255108505494104843374021615775162945381

というようにあからさまに長くなっていることを気にするひとがいるか思ったが、いまのところ見かけた覚えがない。

#3 perl の乱数 [CODE blog]

perl も /dev/urandom を使っている。 (というか、ruby で使おうと思ったのは perl で使っていることに気がついたからである)

perl-5.8.7/util.c:4446-4525

4446: U32
4447: Perl_seed(pTHX)
4448: {
4449:     /*
4450:      * This is really just a quick hack which grabs various garbage
4451:      * values.  It really should be a real hash algorithm which
4452:      * spreads the effect of every input bit onto every output bit,
4453:      * if someone who knows about such things would bother to write it.
4454:      * Might be a good idea to add that function to CORE as well.
4455:      * No numbers below come from careful analysis or anything here,
4456:      * except they are primes and SEED_C1 > 1E6 to get a full-width
4457:      * value from (tv_sec * SEED_C1 + tv_usec).  The multipliers should
4458:      * probably be bigger too.
4459:      */
4460: #if RANDBITS > 16
4461: #  define SEED_C1       1000003
4462: #define   SEED_C4       73819
4463: #else
4464: #  define SEED_C1       25747
4465: #define   SEED_C4       20639
4466: #endif
4467: #define   SEED_C2       3
4468: #define   SEED_C3       269
4469: #define   SEED_C5       26107
4470:
4471: #ifndef PERL_NO_DEV_RANDOM
4472:     int fd;
4473: #endif
4474:     U32 u;
4475: #ifdef VMS
4476: #  include <starlet.h>
4477:     /* when[] = (low 32 bits, high 32 bits) of time since epoch
4478:      * in 100-ns units, typically incremented ever 10 ms.        */
4479:     unsigned int when[2];
4480: #else
4481: #  ifdef HAS_GETTIMEOFDAY
4482:     struct timeval when;
4483: #  else
4484:     Time_t when;
4485: #  endif
4486: #endif
4487:
4488: /* This test is an escape hatch, this symbol isn't set by Configure. */
4489: #ifndef PERL_NO_DEV_RANDOM
4490: #ifndef PERL_RANDOM_DEVICE
4491:    /* /dev/random isn't used by default because reads from it will block
4492:     * if there isn't enough entropy available.  You can compile with
4493:     * PERL_RANDOM_DEVICE to it if you'd prefer Perl to block until there
4494:     * is enough real entropy to fill the seed. */
4495: #  define PERL_RANDOM_DEVICE "/dev/urandom"
4496: #endif
4497:     fd = PerlLIO_open(PERL_RANDOM_DEVICE, 0);
4498:     if (fd != -1) {
4499:         if (PerlLIO_read(fd, &u, sizeof u) != sizeof u)
4500:             u = 0;
4501:         PerlLIO_close(fd);
4502:         if (u)
4503:             return u;
4504:     }
4505: #endif
4506:
4507: #ifdef VMS
4508:     _ckvmssts(sys$gettim(when));
4509:     u = (U32)SEED_C1 * when[0] + (U32)SEED_C2 * when[1];
4510: #else
4511: #  ifdef HAS_GETTIMEOFDAY
4512:     PerlProc_gettimeofday(&when,NULL);
4513:     u = (U32)SEED_C1 * when.tv_sec + (U32)SEED_C2 * when.tv_usec;
4514: #  else
4515:     (void)time(&when);
4516:     u = (U32)SEED_C1 * when;
4517: #  endif
4518: #endif
4519:     u += SEED_C3 * (U32)PerlProc_getpid();
4520:     u += SEED_C4 * (U32)PTR2UV(PL_stack_sp);
4521: #ifndef PLAN9           /* XXX Plan9 assembler chokes on this; fix needed  */
4522:     u += SEED_C5 * (U32)PTR2UV(&when);
4523: #endif
4524:     return u;
4525: }

/dev/urandom 以外には時刻などを使う。

ただ、この Perl_seed という関数の返り値は U32 なので、(おそらく) 32bit しかない。32bit というのは現在の計算機の brute force attack に対抗するには危うい。

あと、perl の乱数アルゴリズムはシステムが提供している drand48, random, rand のどれかを使う。長い種を扱わないのはこのへんに起因するのかもしれない。

perl-5.8.7/pod/perl56delta.pod:390-396

390: =head2 Better pseudo-random number generator
391:
392: In 5.005_0x and earlier, perl's rand() function used the C library
393: rand(3) function.  As of 5.005_52, Configure tests for drand48(),
394: random(), and rand() (in that order) and picks the first one it finds.
395:
396: These changes should result in better random numbers from rand().
#4 bash の乱数 [CODE blog]

そういえば、bash には $RANDOM という疑似変数がある。

bash-3.1/doc/bashref.texi:4694-4697

4694: @item RANDOM
4695: Each time this parameter is referenced, a random integer
4696: between 0 and 32767 is generated.  Assigning a value to this
4697: variable seeds the random number generator.

せっかくなのでたどってみよう。

とりあえず RANDOM で検索すると次の行が見つかった。

bash-3.1/variables.c:1451

1451:   INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);

きっと get_random というのが乱数を生成する関数で、 assign_random はおそらく種をセットするのだろう。

bash-3.1/variables.c:1137-1161,1175-1191,1200-1201

1137: /* The random number seed.  You can change this by setting RANDOM. */
1138: static unsigned long rseed = 1;
1139: static int last_random_value;
1140: static int seeded_subshell = 0;
1141:
1142: /* A linear congruential random number generator based on the example
1143:    one in the ANSI C standard.  This one isn't very good, but a more
1144:    complicated one is overkill. */
1145:
1146: /* Returns a pseudo-random number between 0 and 32767. */
1147: static int
1148: brand ()
1149: {
1150:   rseed = rseed * 1103515245 + 12345;
1151:   return ((unsigned int)((rseed >> 16) & 32767));       /* was % 32768 */
1152: }
1153:
1154: /* Set the random number generator seed to SEED. */
1155: static void
1156: sbrand (seed)
1157:      unsigned long seed;
1158: {
1159:   rseed = seed;
1160:   last_random_value = 0;
1161: }

...

1175: int
1176: get_random_number ()
1177: {
1178:   int rv;
1179:
1180:   /* Reset for command and process substitution. */
1181:   if (subshell_environment && seeded_subshell == 0)
1182:     {
1183:       sbrand (rseed + getpid() + NOW);
1184:       seeded_subshell = 1;
1185:     }
1186:
1187:   do
1188:     rv = brand ();
1189:   while (rv == last_random_value);
1190:   return rv;
1191: }

...

1200:   rv = get_random_number ();
1201:   last_random_value = rv;

アルゴリズムは線形合同法で、種は pid と時刻という感じだろうか。

コメントにもあるようにそんなによくないというのは自覚しているようではある。しかし、last_random_value とかいうので、同じ値が連続して出てこないようにしているのはいかがなものかと思う。どちらかというと、見識があってこれで十分と判断したというよりは、素人っぽさを感じる。

#5 python の乱数 [CODE blog]

Python には os.urandom というのがある。 (なお、Windows の場合は C で定義されるようである)

Python-2.4.2/Lib/os.py:710-725

710: if not _exists("urandom"):
711:     def urandom(n):
712:         """urandom(n) -> str
713:
714:         Return a string of n random bytes suitable for cryptographic use.
715:
716:         """
717:         try:
718:             _urandomfd = open("/dev/urandom", O_RDONLY)
719:         except:
720:             raise NotImplementedError("/dev/urandom (or equivalent) not found")
721:         bytes = ""
722:         while len(bytes) < n:
723:             bytes += read(_urandomfd, n - len(bytes))
724:         close(_urandomfd)
725:         return bytes

疑似乱数は Mersenne Twister が random.py で定義される。

Python-2.4.2/Lib/random.py:29,46,108-112

29: General notes on the underlying Mersenne Twister core generator:

...

46: from os import urandom as _urandom

...

108:             try:
109:                 a = long(_hexlify(_urandom(16)), 16)
110:             except NotImplementedError:
111:                 import time
112:                 a = long(time.time() * 256) # use fractional seconds

種は、os.urandom を使って16バイト (128bit) 読んで作る。読めなければ時刻。

#6 php の乱数 [CODE blog]

php-5.1.0/ext/standard/rand.c:58-82

58: /* {{{ php_rand
59:  */
60: PHPAPI long php_rand(TSRMLS_D)
61: {
62:         long ret;
63:
64:         if (!BG(rand_is_seeded)) {
65:                 php_srand(GENERATE_SEED() TSRMLS_CC);
66:         }
67:
68: #ifdef ZTS
69:         ret = php_rand_r(&BG(rand_seed));
70: #else
71: # if defined(HAVE_RANDOM)
72:         ret = random();
73: # elif defined(HAVE_LRAND48)
74:         ret = lrand48();
75: # else
76:         ret = rand();
77: # endif
78: #endif
79:
80:         return ret;
81: }
82: /* }}} */

疑似乱数には random, lrand48, rand のどれかを使っている。

php-5.1.0/ext/standard/php_rand.h:49-53

49: #ifdef PHP_WIN32
50: #define GENERATE_SEED() ((long) (time(0) * GetCurrentProcessId() * 1000000 * php_combined_lcg(TSRMLS_C)))
51: #else
52: #define GENERATE_SEED() ((long) (time(0) * getpid() * 1000000 * php_combined_lcg(TSRMLS_C)))
53: #endif

種は時刻と pid と、えーと、この lcg ってのはそれ自身が疑似乱数なのか。うぅむ。

あ、php_rand_r というのが使われる可能性もある?

php-5.1.0/main/reentrancy.c:278,318-333

278: #ifndef HAVE_RAND_R

...

318: static int
319: do_rand(unsigned long *ctx)
320: {
321:         return ((*ctx = *ctx * 1103515245 + 12345) % ((u_long)PHP_RAND_MAX + 1));
322: }
323:
324:
325: PHPAPI int
326: php_rand_r(unsigned int *ctx)
327: {
328:         u_long val = (u_long) *ctx;
329:         *ctx = do_rand(&val);
330:         return (int) *ctx;
331: }
332:
333: #endif

うぅむ。これはあまりよろしくない。でも、HAVE_RAND_R というところからみると、rand_r があれば使われないか。でも、rand_r って rand と同程度で、それもそんなに良くない気がするなぁ。

#7 graphviz [CODE blog]

どうも graphviz は Debian のが古い (古すぎる) のが問題らしい。 graphviz-2.7.20060126.0540.tar.gz をとってきて試しに install してみたら問題が起きない。

Debian BTS にも新しいのが欲しいというリクエストが出ているが、反応がないようだ。

http://bugs.debian.org/cgi-bin/pkgreport.cgi?which=pkg&data=graphviz&archive=no&version=&dist=unstable

2006-01-28 (Sat)

#1 $RANDOM [CODE blog]

調べた中でいちばんしょぼいのは bash の $RANDOM である。

では、$RANDOM を使っているシェルスクリプトはあるだろうか?もしあったら危ないこともあるかもしれない。

まぁ、SUSv3 にも定義されていなくてポータブルじゃないからあまりないだろう、と思ったところが大違い。大量にヒット。

https://www.codeblog.org/gonzui/search?q=RANDOM&fm=sh

うぅむ。autoconf 関連のスクリプトとかに入っているのか。

たとえば、config.guess に入っている。ここに入っていると大量にヒットしてしまうのもしょうがない。

gcc-3.4.4/config.guess:107-110

107:  { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
108:  { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
109:  { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
110:  { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;

まぁ、mktemp があれば使わないし、注意深く考えてある感じはする。

2006-01-29 (Sun)

#1
const int a = 1;
const int b = a;

というコードは gcc では error になるが、g++ ではそうならないことを知る。

2006-01-30 (Mon)

#1 php の virtual_popen [CODE blog]

popen を探して php の virtual_popen にいきあたる。

php-5.1.0/TSRM/tsrm_virtual_cwd.c:984-1044

984: #else /* Unix */
985:
986: CWD_API FILE *virtual_popen(const char *command, const char *type TSRMLS_DC)
987: {
988:         int command_length;
989:         int dir_length, extra = 0;
990:         char *command_line;
991:         char *ptr, *dir;
992:         FILE *retval;
993:
994:         command_length = strlen(command);
995:
996:         dir_length = CWDG(cwd).cwd_length;
997:         dir = CWDG(cwd).cwd;
998:         while (dir_length > 0) {
999:                 if (*dir == '\'') extra+=3;
1000:                 dir++;
1001:                 dir_length--;
1002:         }
1003:         dir_length = CWDG(cwd).cwd_length;
1004:         dir = CWDG(cwd).cwd;
1005:
1006:         ptr = command_line = (char *) malloc(command_length + sizeof("cd '' ; ") + dir_length + extra+1+1);
1007:         if (!command_line) {
1008:                 return NULL;
1009:         }
1010:         memcpy(ptr, "cd ", sizeof("cd ")-1);
1011:         ptr += sizeof("cd ")-1;
1012:
1013:         if (CWDG(cwd).cwd_length == 0) {
1014:                 *ptr++ = DEFAULT_SLASH;
1015:         } else {
1016:                 *ptr++ = '\'';
1017:                 while (dir_length > 0) {
1018:                         switch (*dir) {
1019:                         case '\'':
1020:                                 *ptr++ = '\'';
1021:                                 *ptr++ = '\\';
1022:                                 *ptr++ = '\'';
1023:                                 /* fall-through */
1024:                         default:
1025:                                 *ptr++ = *dir;
1026:                         }
1027:                         dir++;
1028:                         dir_length--;
1029:                 }
1030:                 *ptr++ = '\'';
1031:         }
1032:
1033:         *ptr++ = ' ';
1034:         *ptr++ = ';';
1035:         *ptr++ = ' ';
1036:
1037:         memcpy(ptr, command, command_length+1);
1038:         retval = popen(command_line, type);
1039:
1040:         free(command_line);
1041:         return retval;
1042: }
1043:
1044: #endif

読んでみると、カレントディレクトリを移動した上で指定したコマンドを実行(popen)するもののようだ。そのために、popen に渡す引数に cd '...' というのを前置している。

quote は '...' で、' 自体の処理もちゃんとしているのはよろしい。

ただ、なんでこんなことをせねばならんのかという嘆きたくはなる。

popen の中では fork して exec しているわけで、child process で exec するまえに chdir を呼ぶというのが本来やりたい処理である。もしそうできれば、quote は不要である。

だが、popen を使う限りにおいて、そうはできない。

では、(ここの部分は Unix 用だし) popen を使わずに fork/exec を直接使えばいいのかというと、おそらくそれはそう単純にはいかない。インターフェース上 virtual_popen の返値は pclose にわたされると想像されるが、pclose に渡せるものを作れるのは popen だけである。名前からしてあからさまに対になっていてそんな感じがするし、機能から考えても、pclose は child process を wait するから、pid を FILE構造体に入れなきゃいけないけど、fdopen ではそれはできない。

やはりなんというか popen という API はできがわるい。

#2 php_escape_shell_cmd [CODE blog]

さらに、php_escape_shell_cmd にいきあたる。

php-5.1.0/ext/standard/exec.c:255-324

255: /* {{{ php_escape_shell_cmd
256:    Escape all chars that could possibly be used to
257:    break out of a shell command
258:
259:    This function emalloc's a string and returns the pointer.
260:    Remember to efree it when done with it.
261:
262:    *NOT* safe for binary strings
263: */
264: char *php_escape_shell_cmd(char *str) {
265:         register int x, y, l;
266:         char *cmd;
267:         char *p = NULL;
268:
269:         l = strlen(str);
270:         cmd = safe_emalloc(2, l, 1);
271:
272:         for (x = 0, y = 0; x < l; x++) {
273:                 switch (str[x]) {
274:                         case '"':
275:                         case '\'':
276: #ifndef PHP_WIN32
277:                                 if (!p && (p = memchr(str + x + 1, str[x], l - x - 1))) {
278:                                         /* noop */
279:                                 } else if (p && *p == str[x]) {
280:                                         p = NULL;
281:                                 } else {
282:                                         cmd[y++] = '\\';
283:                                 }
284:                                 cmd[y++] = str[x];
285:                                 break;
286: #endif
287:                         case '#': /* This is character-set independent */
288:                         case '&':
289:                         case ';':
290:                         case '`':
291:                         case '|':
292:                         case '*':
293:                         case '?':
294:                         case '~':
295:                         case '<':
296:                         case '>':
297:                         case '^':
298:                         case '(':
299:                         case ')':
300:                         case '[':
301:                         case ']':
302:                         case '{':
303:                         case '}':
304:                         case '$':
305:                         case '\\':
306:                         case '\x0A': /* excluding these two */
307:                         case '\xFF':
308: #ifdef PHP_WIN32
309:                         /* since Windows does not allow us to escape these chars, just remove them */
310:                         case '%':
311:                                 cmd[y++] = ' ';
312:                                 break;
313: #endif
314:                                 cmd[y++] = '\\';
315:                                 /* fall-through */
316:                         default:
317:                                 cmd[y++] = str[x];
318:
319:                 }
320:         }
321:         cmd[y] = '\0';
322:         return cmd;
323: }
324: /* }}} */

むー。文字列を escape している感じだが、もともと存在する quote を解釈する?しかも single quote と double quote の処理が同じ?

これは怪しい。


[latest]


田中哲