df

この時期、夜の散歩が楽しい。

何故かと言うと、いろいろなクリスマス・デコレーションが見られるからだ。バンビちゃんが 何頭も庭に居たり、アヒルちゃんだか白鳥さんだか知らないけれど、何羽もフェンスに居たりだ。 きっと、お子さんにせがまれて飾っているのかな?

電飾は大体暖色系が多いけど、去年あたりから青色ダイオードが出てきたように思う。これらの LEDは半導体なので半永久的に使えるかと思ったら、だんだんと劣化して、光量が減っていくとか。 で、寿命の定義は、初期光量の半分になった時だそうだ。大体10万時間との事。

最近は、青色ダイオードのおかげでう、LED-TVが出来るようになり、某メーカーは売り出しに躍起。 せいぜい頑張ってください。どう頑張ったって、田園の真ん中に立つ、集虫灯のパチンコ屋看板の 二の舞でしょう。広告がメインでその間に番組を流すなんて、時代遅れになりまっせ。

TVを見て欲しかったら、広告塔は無料じゃなくっちゃ!!!!! 良く聞けよ。関東一円のTV局。

最近、おいらのTVは寿命っぽくて、TVをONした当初は黄色っぽく映るんよ。液晶TVのくせに、 何となくブラウン管の末期的症状に似ているな。液晶の裏側に鎮座する蛍光灯の寿命かしらん。

と、まあ、半導体にも寿命がありまっせと愚痴ってきたけど、クリスマスのイルミネーションは いいよな。出番は、年に一度きり。これなら、寿命は半永久的でっせ。爺婆が孫の為に買って あげたデコレーションセットが、3代とか4代受け継げるぞ。大事にしなされ。

何でも鑑定団で、100年前に使われていた、祭り用の道具です、なんて言われて、思わぬ高値を 付けるかも???

gc

るびまのHotlinksでnariさんが登場してる。 日本で一番有名なgc屋さんではなかろうか。(無駄に)豪華な野次馬に囲まれて楽しそう。

なんで竹内先生が島根に居るんだ? 温泉にでも入りに行ったのか? ささださんに誘われて 研究室のプチ旅行なのかと、いらぬ詮索をしてしまったぞ。まあ、先生が島根に居る理由は大体 想像つくけど。

gcのページを作っちゃうなんてオタッキーだなあ。 読んでると楽しいよ。おいらも以前、amscmのgcのコードを読んだんで親近感があるねぇ。

Mostly-Concurrent Mark & Sweep GC のアルゴリズム 後でゆっくり読んでみよう。

gcとは直接関係ないけど、rubyに穴が見つかって、新しいのが出てるのね。FreeBSDのportsから Ruby 1.9.1-p376 リリースにしたよ。

WindowsXPの調子が悪いその参です。

(苦笑)してますよ。今度はどんなトラブルかと言うと、、、

HDDの容量は無限じゃないんです。だからたまには、マイコンピュータのHDDのアイコンを右クリックして、 だらりと出てきたメニューから一番下のプロパティーを選んで、円グラフを見る訳ですよ。

所が何時の間にか、右クリックしてもメニューが直ぐに出てこなくなり、カーソルはお待ち 下さいアイコンになったままになるんです。で、大分時間が経ってから、メニューがだらりと 出てくるんです。そこをすかさず捕らえて、カーソルを一番下まで持ってこないと、メニュー が消失。また、一からやり直し。これだからGUIって嫌いさ。unixなら、dfって叩くだけで 済んじゃうじゃないですか。

そうそう、duに相当するのもGUIの操作だといらいらさせられますね。いちいち、ファイル数や 容量の総計の計算過程を表示せんでもいいでぇ。馬鹿ファイルシステムは、そうやって時間 稼ぎせんと、さっと表示できんのか脳。紙芝居はPowerPointだけかと思っていたら、DNAに 植え付けられているのね。

df

Windowsではいらいらさせられるdf相当。unixでは一瞬だけど、その仕組みやいかに? ちょっと潜って見てみるか。

まずは、仕様書だな。man df

普段使っているけど、結構知らなかったオプションがあるのね。-cで総計も出ますだってさ。 さすがに -i は知ってたけど。馬鹿GUIは、いろんな単位での表示も出来なくて、GUIの割りには 使う人に不親切だよ。

[sakae@fb8 ~]$ df -ich
Filesystem     Size    Used   Avail Capacity iused ifree %iused  Mounted on
/dev/da0s1a    721M    208M    455M    31%    3.0k  115k    3%   /
devfs          1.0K    1.0K      0B   100%       0     0  100%   /dev
/dev/da0s1d    4.9G    3.3G    1.2G    74%    254k  405k   39%   /usr
total          5.6G    3.5G    1.6G    68%    257k  520k   33%

続いて、関連情報を見ると

関連項目
     lsvfs(1), quota(1), fstatfs(2), getfsstat(2), statfs(2), getmntinfo(3),
     fstab(5), mount(8), quot(8)

manしたおかげで、一つ新しいコマンドを覚えたよ。

[sakae@fb8 ~]$ lsvfs
Filesystem                        Refs Flags
-------------------------------- ----- ---------------
msdosfs                              0
ufs                                  2
procfs                               0 synthetic
devfs                                1 synthetic
cd9660                               0 read-only
nfs                                  0 network

上記が、今ロードされてるモジュールですってさ。話題のzfsはロードしてないので、見えていない。 Refsは、現在マウントされているものの数。 manのチェーンを辿って行ったら、mount_ntfsなんてのが見つかった。心の広いOSだ事!

では、お約束のソースを見るかな。まあ、大体どうなっているかは想像つくわな。fstatfsで 今のfsを引っ張ってきて、それを元にgettsstatあたりで個別のデータを取り出してくる。 後は、いろいろな単位に加工して表示かな。

df.c

[sakae@fb8 /usr/src/bin/df]$ ls
Makefile        df.1            df.c
[sakae@fb8 /usr/src/bin/df]$ wc df.c
     613    2068   15691 df.c

こんな具合になってた。折角なので、自分のエリアに持ってきてから -g付きでコンパイルしてみる。 (ライオンだって、狩ってきた獲物を安全な所へ運んでから、料理するでしょ)

[sakae@fb8 /usr/src/bin/df]$ mkdir ~/work
[sakae@fb8 /usr/src/bin/df]$ cp Makefile df.c ~/work
[sakae@fb8 /usr/src/bin/df]$ cd ~/work
[sakae@fb8 ~/work]$ make
Warning: Object directory not changed from original /usr/home/sakae/work
cc -O2 -pipe  -I/usr/home/sakae/work/../../sbin/mount -std=gnu99 -fstack-protector  -c df.c
df.c:63:20: error: extern.h: No such file or directory
df.c: In function 'main':
df.c:162: warning: implicit declaration of function 'makevfslist'
df.c:162: warning: assignment makes pointer from integer without a cast
df.c:178: warning: assignment makes pointer from integer without a cast
df.c:277: warning: implicit declaration of function 'checkvfsname'
*** Error code 1

Stop in /usr/home/sakae/work.

ははは、エラーだわさ。

[sakae@fb8 ~/work]$ diff  Makefile.org Makefile
4c4
< MOUNT=        ${.CURDIR}/../../sbin/mount
---
> MOUNT=        /usr/src/sbin/mount
9a10
> CFLAGS+= -g -O0
[sakae@fb8 ~/work]$ make
Warning: Object directory not changed from original /usr/home/sakae/work
cc -O2 -pipe  -g -O0 -I/usr/src/sbin/mount -std=gnu99 -fstack-protector  -c df.c
cc -O2 -pipe  -g -O0 -I/usr/src/sbin/mount -std=gnu99 -fstack-protector  -c /usr/src/sbin/mount/vfslist.c
cc -O2 -pipe  -g -O0 -I/usr/src/sbin/mount -std=gnu99 -fstack-protector   -o df df.o vfslist.o -lutil
make: don't know how to make df.1. Stop
[sakae@fb8 ~/work]$ ./df
Filesystem  1K-blocks    Used   Avail Capacity  Mounted on
/dev/da0s1a    738318  213124  466130    31%    /
devfs               1       1       0   100%    /dev
/dev/da0s1d   5093430 3459626 1226330    74%    /usr

どうやら、出来たっぽい。よそのコマンド(mount)の一部を拝借してるのね。上の実行例でも 分かるけど、マウントしてるファイルシステム情報が必要なんだな。そんじゃ、gdbで追って みますかね。

119             while ((ch = getopt(argc, argv, "abcgHhiklmnPt:T")) != -1)
190             mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
199                     for (i = 0; i < mntsize; i++) {
(gdb)
202                             update_maxwidths(&maxwidths, &mntbuf[i]);
(gdb)
199                     for (i = 0; i < mntsize; i++) {
(gdb)
204                     if (cflag)
(gdb)
206                     for (i = 0; i < mntsize; i++)
(gdb)
207                             if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0)
(gdb)
208                                     prtstat(&mntbuf[i], &maxwidths);
(gdb)
Filesystem  1K-blocks    Used   Avail Capacity  Mounted on
/dev/da0s1a    738318  213124  466130    31%    /

なるほどね、getmntinfo と prtstatあたりが肝か。prtstatを見てみる

440                     (void)printf("  Mounted on\n");
(gdb)
Filesystem  1K-blocks    Used   Avail Capacity  Mounted on
442             (void)printf("%-*s", mwp->mntfrom, sfsp->f_mntfromname);
(gdb)
443             if (Tflag)
(gdb)
445             used = sfsp->f_blocks - sfsp->f_bfree;
(gdb)
446             availblks = sfsp->f_bavail + used;
(gdb)
445             used = sfsp->f_blocks - sfsp->f_bfree;
(gdb)
446             availblks = sfsp->f_bavail + used;
(gdb)
447             if (hflag) {
(gdb)
446             availblks = sfsp->f_bavail + used;
(gdb)
447             if (hflag) {
(gdb)
450                     (void)printf(" %*jd %*jd %*jd",
(gdb)
457             (void)printf(" %5.0f%%",
(gdb)
459             if (iflag) {
(gdb)
473                     (void)printf("  ");
(gdb)
474             if (strncmp(sfsp->f_mntfromname, "total", MNAMELEN) != 0)
(gdb)
475                     (void)printf("  %s", sfsp->f_mntonname);
(gdb)
476             (void)printf("\n");
(gdb)
/dev/da0s1a    738318  213124  466130    31%    /

長々とページを稼いでしまったけど、本質は、190行目のgetmntinfoだけね。後はほとんど 整形の為だわさ。gdbで190行目を実行した後のデータを見ると

(gdb) p *mntbuf
$18 = {f_version = 537068824, f_type = 2, f_flags = 20480, f_bsize = 2048, f_io\
size = 16384, f_blocks = 369159, f_bfree = 262597, f_bavail = 233065, f_files =\
 117758, f_ffree = 114785, f_syncwrites = 0, f_asyncwrites = 0, f_syncreads = 0\
, f_asyncreads = 0, f_spare =     {0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0}, f_namemax = 255, f_owner = 0, f_fsid = {val =       {0,
      0}}, f_charspare =     '\0' <repeats 79 times>, f_fstypename =     "ufs",\
 '\0' <repeats 12 times>, f_mntfromname =     "/dev/da0s1"..., f_mntonname =   \
  "/", '\0' <repeats 86 times>}

とか、ちょっと綺麗に表示するぞとか

(gdb) set print pretty on
(gdb) p *(mntbuf+2)
  f_asyncreads = 0,
  f_flags = 2101248,
  f_bsize = 2048,
  f_iosize = 16384,
  f_version = 537068824,
  f_type = 2,
  f_flags = 2101248,
  f_bsize = 2048,
  f_iosize = 16384,
  f_blocks = 2546715,
  f_bfree = 816902,
  f_bavail = 613165,
  f_files = 659454,
  f_ffree = 404957,
  f_syncwrites = 0,
  f_asyncwrites = 0,
  f_syncreads = 0,
  f_asyncreads = 0,
  f_spare =     {0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0},
  f_namemax = 255,
  f_owner = 0,
  f_fsid = {
    val =       {0,
      0}
  },
  f_charspare =     '\0' <repeats 79 times>,
  f_fstypename =     "ufs", '\0' <repeats 12 times>,
  f_mntfromname =     "/dev/da0s1"...,
  f_mntonname =     "/usr", '\0' <repeats 83 times>
}

解説も man statfsしたら出てきた。

     struct statfs {
     uint32_t f_version;             /* 構造体のバージョン番号 */
     uint32_t f_type;                /* ファイルシステムのタイプ */
     uint64_t f_flags;               /* マウントフラグのコピー */
     uint64_t f_bsize;               /* ファイルシステムの断片サイズ */
     uint64_t f_iosize;              /* 最適な転送ブロックサイズ */
     uint64_t f_blocks;              /* ファイルシステム上の合計データブロックサイズ */
     uint64_t f_bfree;               /* ファイルシステム上の利用可能なブロック */
     int64_t  f_bavail;              /* スーパユーザ以外が利用可能なブロック */
     uint64_t f_files;               /* ファイルシステム上の合計ノード数 */
     int64_t  f_ffree;               /* スーパユーザ以外が利用可能なノード数 */
     uint64_t f_syncwrites;          /* マウントしてからの同期書込み数 */
     uint64_t f_asyncwrites;         /* マウントしてからの非同期書込み数 */
     uint64_t f_syncreads;           /* マウントしてからの同期読取り数 */
     uint64_t f_asyncreads;          /* マウントしてからの非同期読取り数 */
     uint64_t f_spare[10];           /* 未使用領域 */
     uint32_t f_namemax;             /* ファイル名の長さの最大 */
     uid_t     f_owner;              /* ファイルシステムをマウントしたユーザ */
     fsid_t    f_fsid;               /* ファイルシステム ID */
     char      f_charspare[80];          /* 後のための余白 */
     char      f_fstypename[MFSNAMELEN]; /* ファイルシステムのタイプ名 */
     char      f_mntfromname[MNAMELEN];  /* マウントされたファイルシステム */
     char      f_mntonname[MNAMELEN];    /* このディレクトリにマウント */
     };

次は、duの秘密かな?