namec〜名前からチャネルを取得する

今まで何度か出てきたが,追求を避けてきたnamec関数を見ていこう.と言ってもnamecは350行ほどの大きな関数なので,まずはenvデバイスを例にカーネルバイスの場合からはじめよう.
カーネルバイスのファイル名は#から始まる.envデバイスの場合は#eだ.そして,devtab経由でattach関数を呼び出し,チャネルを取得している.attach関数はbindmount関数にも出現していた.attachすることでファイルツリーが連結され,プロセスからアクセスできるようになる.

port/chan.c
 1288: Chan*
 1289: namec(char *aname, int amode, int omode, ulong perm)
 1290: {

 1308:         name = aname;

 1316:         switch(name[0]){

 1322:         case '#':

 1350:                 t = devno(r, 1);

 1353:                 c = devtab[t]->attach(up->genbuf+n);
 1354:                 break;

 1632:         return c;
 1633: }

envデバイスのattach関数であるenvattachは,汎用attach関数であるdevattachを呼んでいる.

port/devenv.c
   63: static Chan*
   64: envattach(char *spec)
   65: {
   66:         Chan *c;
   75: 
   76:         c = devattach('e', spec);

   78:         return c;
   79: }

devattachでは,チャネルを生成し,qidとpathを設定している.qidはファイルサーバ(今回はenvデバイス)におけるファイルの識別子で,pathはパス名である.

port/dev.c
  125: Chan*
  126: devattach(int tc, char *spec)
  127: {
  128:         Chan *c;
  129:         char *buf;
  130: 
  131:         c = newchan();
  132:         mkqid(&c->qid, 0, 0, QTDIR);
  133:         c->type = devno(tc, 0);
  134:         if(spec == nil)
  135:                 spec = "";
  136:         buf = smalloc(4+strlen(spec)+1);
  137:         sprint(buf, "#%C%s", tc, spec);
  138:         c->path = newpath(buf);
  139:         free(buf);
  140:         return c;
  141: }

基本的なopen-close-read-writeは、このnamecとdevtab[]の組み合わせで実行される.次のイディオムは頻出するので覚えておくとよい.

  c = namec(name, ...);
  devtab[c->type]->read(c, ...);