read/writeの中身
続いて,read/writeの中身を埋めていこう.コードを解説する前に,一つおさらい.「プロセスグループ」にも書いたように,各ファイルにはQidというファイルサーバローカルで,ユニークな識別子が付けられている.以下のコードでは,このQidを利用して,ctlファイルとdataファイルの処理を区別している.Qidはゼロオリジンで,createfileごとにインクリメントされる.つまり,この例ではctlファイルのQidが0,dataファイルのQidが1となる*1.
コード例として,ctlファイルに環境変数名を設定したら,dataファイルにその値がセットされるものを考えてみる.変更箇所であるmyread,mywrite関数を次に示す.readstr(2)で文字列をアプリに返している.readstr自体はrespondを呼ばないので,ちゃんと明示的にrespondを呼ぶ必要がある.
enum { Qctl, Qdata, }; void myread(Req *r) { int qid = (int)r->fid->qid.path; char data[1024], *e; switch (qid) { case Qctl: sprint(data, "env=%s\n", ename); readstr(r, data); break; case Qdata: e = getenv(ename); if (e) { sprint(data, "%s=%s\n", ename, e); readstr(r, data); } break; } respond(r, nil); } void mywrite(Req *r) { int qid = (int)r->fid->qid.path; char data[1024]; switch (qid) { case Qctl: memmove(data, r->ifcall.data, r->ifcall.count); data[r->ifcall.count] = '\0'; strcpy(ename, data); } respond(r, nil); }
次のような実行結果になる.なお,lsに-qオプションを付けると,Qidが表示される.
% mysrv % mount /srv/mysrv /n/mysrv % ls -q /n/mysrv (00000000000000000 0 00) /n/mysrv/ctl (00000000000000001 0 00) /n/mysrv/data % cat /n/mysrv/ctl home % cat /n/mysrv/data home=/usr/oraccha % echo -n user > /n/mysrv/ctl % cat /n/mysrv/data user=oraccha
もっと具体的なコードとしてramfsが挙げられるかなと思ったけど,ramfsはpostmountsrvを使わず,自前でrforkして,イベントループを作っているみたい.なんでだろう? nntpfsやwebfs,wikifsはpostmountsrvを使っている.
*1:正確にはQidではなく,Qid.pathの値だけど,煩雑なのでこう書いた.pathと書くとパス名のように誤解するかもしれないが,64ビットの整数値である.