数珠つなぎシンボリックリンク

シンボリックリンクでループしたときにエラーが出た,みたいな事を聞いて,「じゃあ,シンボリックリンクを数珠つなぎにしたらどこまでいけるんだろう?」と思ったのでやってみた.

シンボリックリンクの数珠つなぎは以下のようにした.

% cat sym.sh
#!/bin/sh

echo > 0
i=1
while [ $i -le 33 ]; do
 ln -s $((i-1)) $i
 i=$((i+1))
done
% sh sym.sh
% ls -l
total 280
-rw-r--r--  1 yasuhiko  staff   1  2  6 09:18 0
lrwxr-xr-x  1 yasuhiko  staff   1  2  6 09:18 1@ -> 0
...
lrwxr-xr-x  1 yasuhiko  staff   2  2  6 09:18 30@ -> 29
lrwxr-xr-x  1 yasuhiko  staff   2  2  6 09:18 31@ -> 30
lrwxr-xr-x  1 yasuhiko  staff   2  2  6 09:18 32@ -> 31
lrwxr-xr-x  1 yasuhiko  staff   2  2  6 09:18 33@ -> 32

ここで32, 33をcatとしてみると,33段目のシンボリックリンクが解決できないことがわかった.

% cat 32

% cat 33
cat: 33: Too many levels of symbolic links

ここで,ループしている云々よりも32段シンボリックリンクまでしか出来ないんじゃないの?という疑問が浮かんだ.

疑問:シンボリックリンクは32段までしかできない

そうしたら @ucq さんがこんなのを教えてくれた!

なるほど!Macではそうなっているのか!じゃあFreeBSDだとどうなっているんだろう?
そう思って調べてみると,/usr/src/sys/kern/vfs_lookup.c にそれらしいところがあった.namei()はファイルパスからvnode(inode)を探してくれる関数.

 123 int
 124 namei(struct nameidata *ndp)
 125 {
...
 244     for (;;) {
...
 264         error = lookup(ndp);
...
 280         if ((cnp->cn_flags & ISSYMLINK) == 0) {
...
 296             return (0);
 297         }
...
 298         if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
 299             error = ELOOP;
 300             break;
 301         }
...
 323         error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
...
 351     }
...
 363 }

264行目のlookup()でファイルパスからvnodeを取得.シンボリックリンクの場合はリンクを1つ解決.
280行目でシンボリックリンクじゃなければ終了.ここではシンボリックリンクを考えているので続く.
298行目でループ検出.MAXSYMLINKSを超えれば終了.
323行目でシンボリックリンクを解決して,再び264行目のlookup()へ.
という流れぽい

結論:シンボリックリンクを一つ解決するたびにループ検出用変数がインクリメントされて規定値を超えるとエラーになる.