URI:
       tfs.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tfs.c (8901B)
       ---
            1 #include "std.h"
            2 #include "dat.h"
            3 
            4 enum
            5 {
            6         Qroot,
            7         Qfactotum,
            8         Qrpc,
            9         Qkeylist,
           10         Qprotolist,
           11         Qconfirm,
           12         Qlog,
           13         Qctl,
           14         Qneedkey,
           15         Qconv
           16 };
           17 
           18 static int qtop;
           19 
           20 Qid
           21 mkqid(int type, int path)
           22 {
           23         Qid q;
           24 
           25         q.type = type;
           26         q.path = path;
           27         q.vers = 0;
           28         return q;
           29 }
           30 
           31 static struct
           32 {
           33         char *name;
           34         int qidpath;
           35         ulong perm;
           36 } dirtab[] = {
           37         /* positions of confirm and needkey known below */
           38         "confirm",                Qconfirm,                0600|DMEXCL,
           39         "needkey",        Qneedkey,        0600|DMEXCL,
           40         "ctl",                        Qctl,                        0600,
           41         "rpc",                Qrpc,                0666,
           42         "proto",                Qprotolist,        0444,
           43         "log",                Qlog,                0600|DMEXCL,
           44         "conv",                Qconv,                0400
           45 };
           46 
           47 static void
           48 fillstat(Dir *dir, char *name, int type, int path, ulong perm)
           49 {
           50         dir->name = estrdup(name);
           51         dir->uid = estrdup(owner);
           52         dir->gid = estrdup(owner);
           53         dir->mode = perm;
           54         dir->length = 0;
           55         dir->qid = mkqid(type, path);
           56         dir->atime = time(0);
           57         dir->mtime = time(0);
           58         dir->muid = estrdup("");
           59 }
           60 
           61 static int
           62 rootdirgen(int n, Dir *dir, void *v)
           63 {
           64         USED(v);
           65 
           66         if(n > 0)
           67                 return -1;
           68 
           69         fillstat(dir, factname, QTDIR, Qfactotum, DMDIR|0555);
           70         return 0;
           71 }
           72 
           73 static int
           74 fsdirgen(int n, Dir *dir, void *v)
           75 {
           76         USED(v);
           77 
           78         if(n >= nelem(dirtab))
           79                 return -1;
           80         fillstat(dir, dirtab[n].name, 0, dirtab[n].qidpath, dirtab[n].perm);
           81         return 0;
           82 }
           83 
           84 static char*
           85 fswalk1(Fid *fid, char *name, Qid *qid)
           86 {
           87         int i;
           88 
           89         switch((int)fid->qid.path){
           90         default:
           91                 return "fswalk1: cannot happen";
           92         case Qroot:
           93                 if(strcmp(name, factname) == 0){
           94                         *qid = mkqid(QTDIR, Qfactotum);
           95                         fid->qid = *qid;
           96                         return nil;
           97                 }
           98                 if(strcmp(name, "..") == 0){
           99                         *qid = fid->qid;
          100                         return nil;
          101                 }
          102                 return "not found";
          103         case Qfactotum:
          104                 for(i=0; i<nelem(dirtab); i++)
          105                         if(strcmp(name, dirtab[i].name) == 0){
          106                                 *qid = mkqid(0, dirtab[i].qidpath);
          107                                 fid->qid = *qid;
          108                                 return nil;
          109                         }
          110                 if(strcmp(name, "..") == 0){
          111                         *qid = mkqid(QTDIR, qtop);
          112                         fid->qid = *qid;
          113                         return nil;
          114                 }
          115                 return "not found";
          116         }
          117 }
          118 
          119 static void
          120 fsstat(Req *r)
          121 {
          122         int i, path;
          123 
          124         path = r->fid->qid.path;
          125         switch(path){
          126         case Qroot:
          127                 fillstat(&r->d, "/", QTDIR, Qroot, 0555|DMDIR);
          128                 break;
          129         case Qfactotum:
          130                 fillstat(&r->d, "factotum", QTDIR, Qfactotum, 0555|DMDIR);
          131                 break;
          132         default:
          133                 for(i=0; i<nelem(dirtab); i++)
          134                         if(dirtab[i].qidpath == path){
          135                                 fillstat(&r->d, dirtab[i].name, 0, dirtab[i].qidpath, dirtab[i].perm);
          136                                 goto Break2;
          137                         }
          138                 respond(r, "file not found");
          139                 break;
          140         }
          141     Break2:
          142         respond(r, nil);
          143 }
          144 
          145 static int
          146 readlist(int off, int (*gen)(int, char*, uint), Req *r)
          147 {
          148         char *a, *ea;
          149         int n;
          150 
          151         a = r->ofcall.data;
          152         ea = a+r->ifcall.count;
          153         for(;;){
          154                 n = (*gen)(off, a, ea-a);
          155                 if(n == 0){
          156                         r->ofcall.count = a - (char*)r->ofcall.data;
          157                         return off;
          158                 }
          159                 a += n;
          160                 off++;
          161         }
          162         /* not reached */
          163 }
          164 
          165 static int
          166 keylist(int i, char *a, uint nn)
          167 {
          168         int n;
          169         char buf[4096];
          170         Key *k;
          171 
          172         if(i >= ring.nkey)
          173                 return 0;
          174 
          175         k = ring.key[i];
          176         k->attr = sortattr(k->attr);
          177         n = snprint(buf, sizeof buf, "key %A %N\n", k->attr, k->privattr);
          178         if(n >= sizeof(buf)-5)
          179                 strcpy(buf+sizeof(buf)-5, "...\n");
          180         n = strlen(buf);
          181         if(n > nn)
          182                 return 0;
          183         memmove(a, buf, n);
          184         return n;
          185 }
          186 
          187 static int
          188 protolist(int i, char *a, uint n)
          189 {
          190         if(prototab[i] == nil)
          191                 return 0;
          192         if(strlen(prototab[i]->name)+1 > n)
          193                 return 0;
          194         n = strlen(prototab[i]->name)+1;
          195         memmove(a, prototab[i]->name, n-1);
          196         a[n-1] = '\n';
          197         return n;
          198 }
          199 
          200 /* BUG this is O(n^2) to fill in the list */
          201 static int
          202 convlist(int i, char *a, uint nn)
          203 {
          204         Conv *c;
          205         char buf[512];
          206         int n;
          207 
          208         for(c=conv; c && i-- > 0; c=c->next)
          209                 ;
          210 
          211         if(c == nil)
          212                 return 0;
          213 
          214         if(c->state)
          215                 n = snprint(buf, sizeof buf, "conv state=%q %A\n", c->state, c->attr);
          216         else
          217                 n = snprint(buf, sizeof buf, "conv state=closed err=%q\n", c->err);
          218 
          219         if(n >= sizeof(buf)-5)
          220                 strcpy(buf+sizeof(buf)-5, "...\n");
          221         n = strlen(buf);
          222         if(n > nn)
          223                 return 0;
          224         memmove(a, buf, n);
          225         return n;
          226 }
          227 
          228 static void
          229 fskickreply(Conv *c)
          230 {
          231         Req *r;
          232 
          233         if(c->hangup){
          234                 if((r = c->req) != nil){
          235                         c->req = nil;
          236                         respond(r, "hangup");
          237                 }
          238                 return;
          239         }
          240 
          241         if(!c->req || !c->nreply)
          242                 return;
          243 
          244         r = c->req;
          245         r->ofcall.count = c->nreply;
          246         r->ofcall.data = c->reply;
          247         if(r->ofcall.count > r->ifcall.count)
          248                 r->ofcall.count = r->ifcall.count;
          249         c->req = nil;
          250         respond(r, nil);
          251         c->nreply = 0;
          252 }
          253 
          254 /*
          255  * Some of the file system work happens in the fs proc, but
          256  * fsopen, fsread, fswrite, fsdestroyfid, and fsflush happen in
          257  * the main proc so that they can access the various shared
          258  * data structures without worrying about locking.
          259  */
          260 static int inuse[nelem(dirtab)];
          261 int *confirminuse = &inuse[0];
          262 int *needkeyinuse = &inuse[1];
          263 static void
          264 fsopen(Req *r)
          265 {
          266         int i, *inusep, perm;
          267         static int need[4] = { 4, 2, 6, 1 };
          268         Conv *c;
          269 
          270         inusep = nil;
          271         perm = 5;        /* directory */
          272         for(i=0; i<nelem(dirtab); i++)
          273                 if(dirtab[i].qidpath == r->fid->qid.path){
          274                         if(dirtab[i].perm & DMEXCL)
          275                                 inusep = &inuse[i];
          276                         if(strcmp(r->fid->uid, owner) == 0)
          277                                 perm = dirtab[i].perm>>6;
          278                         else
          279                                 perm = dirtab[i].perm;
          280                         break;
          281                 }
          282 
          283         if((r->ifcall.mode&~(OMASK|OTRUNC))
          284         || (need[r->ifcall.mode&3] & ~perm)){
          285                 respond(r, "permission denied");
          286                 return;
          287         }
          288 
          289         if(inusep){
          290                 if(*inusep){
          291                         respond(r, "file in use");
          292                         return;
          293                 }
          294                 *inusep = 1;
          295         }
          296 
          297         if(r->fid->qid.path == Qrpc){
          298                 if((c = convalloc(r->fid->uid)) == nil){
          299                         char e[ERRMAX];
          300 
          301                         rerrstr(e, sizeof e);
          302                         respond(r, e);
          303                         return;
          304                 }
          305                 c->kickreply = fskickreply;
          306                 r->fid->aux = c;
          307         }
          308 
          309         respond(r, nil);
          310 }
          311 
          312 static void
          313 fsread(Req *r)
          314 {
          315         Conv *c;
          316 
          317         switch((int)r->fid->qid.path){
          318         default:
          319                 respond(r, "fsread: cannot happen");
          320                 break;
          321         case Qroot:
          322                 dirread9p(r, rootdirgen, nil);
          323                 respond(r, nil);
          324                 break;
          325         case Qfactotum:
          326                 dirread9p(r, fsdirgen, nil);
          327                 respond(r, nil);
          328                 break;
          329         case Qrpc:
          330                 c = r->fid->aux;
          331                 if(c->rpc.op == RpcUnknown){
          332                         respond(r, "no rpc pending");
          333                         break;
          334                 }
          335                 if(c->req){
          336                         respond(r, "read already pending");
          337                         break;
          338                 }
          339                 c->req = r;
          340                 if(c->nreply)
          341                         (*c->kickreply)(c);
          342                 else
          343                         rpcexec(c);
          344                 break;
          345         case Qconfirm:
          346                 confirmread(r);
          347                 break;
          348         case Qlog:
          349                 logread(r);
          350                 break;
          351         case Qctl:
          352                 r->fid->aux = (void*)(uintptr)readlist((uintptr)r->fid->aux, keylist, r);
          353                 respond(r, nil);
          354                 break;
          355         case Qneedkey:
          356                 needkeyread(r);
          357                 break;
          358         case Qprotolist:
          359                 r->fid->aux = (void*)(uintptr)readlist((uintptr)r->fid->aux, protolist, r);
          360                 respond(r, nil);
          361                 break;
          362         case Qconv:
          363                 r->fid->aux = (void*)(uintptr)readlist((uintptr)r->fid->aux, convlist, r);
          364                 respond(r, nil);
          365                 break;
          366         }
          367 }
          368 
          369 static void
          370 fswrite(Req *r)
          371 {
          372         int ret;
          373         char err[ERRMAX], *s;
          374         int (*strfn)(char*);
          375         char *name;
          376 
          377         switch((int)r->fid->qid.path){
          378         default:
          379                 respond(r, "fswrite: cannot happen");
          380                 break;
          381         case Qrpc:
          382                 if(rpcwrite(r->fid->aux, r->ifcall.data, r->ifcall.count) < 0){
          383                         rerrstr(err, sizeof err);
          384                         respond(r, err);
          385                 }else{
          386                         r->ofcall.count = r->ifcall.count;
          387                         respond(r, nil);
          388                 }
          389                 break;
          390         case Qneedkey:
          391                 name = "needkey";
          392                 strfn = needkeywrite;
          393                 goto string;
          394         case Qctl:
          395                 name = "ctl";
          396                 strfn = ctlwrite;
          397                 goto string;
          398         case Qconfirm:
          399                 name = "confirm";
          400                 strfn = confirmwrite;
          401         string:
          402                 s = emalloc(r->ifcall.count+1);
          403                 memmove(s, r->ifcall.data, r->ifcall.count);
          404                 s[r->ifcall.count] = '\0';
          405                 ret = (*strfn)(s);
          406                 free(s);
          407                 if(ret < 0){
          408                         rerrstr(err, sizeof err);
          409                         respond(r, err);
          410                         flog("write %s: %s", name, err);
          411                 }else{
          412                         r->ofcall.count = r->ifcall.count;
          413                         respond(r, nil);
          414                 }
          415                 break;
          416         }
          417 }
          418 
          419 static void
          420 fsflush(Req *r)
          421 {
          422         confirmflush(r->oldreq);
          423         logflush(r->oldreq);
          424         respond(r, nil);
          425 }
          426 
          427 static void
          428 fsdestroyfid(Fid *fid)
          429 {
          430         if(fid->qid.path == Qrpc && fid->aux){
          431                 convhangup(fid->aux);
          432                 convclose(fid->aux);
          433         }
          434 }
          435 
          436 static Channel *creq;
          437 static Channel *cfid, *cfidr;
          438 
          439 static void
          440 fsreqthread(void *v)
          441 {
          442         Req *r;
          443 
          444         USED(v);
          445 
          446         while((r = recvp(creq)) != nil){
          447                 switch(r->ifcall.type){
          448                 default:
          449                         respond(r, "bug in fsreqthread");
          450                         break;
          451                 case Topen:
          452                         fsopen(r);
          453                         break;
          454                 case Tread:
          455                         fsread(r);
          456                         break;
          457                 case Twrite:
          458                         fswrite(r);
          459                         break;
          460                 case Tflush:
          461                         fsflush(r);
          462                         break;
          463                 }
          464         }
          465 }
          466 
          467 static void
          468 fsclunkthread(void *v)
          469 {
          470         Fid *f;
          471 
          472         USED(v);
          473 
          474         while((f = recvp(cfid)) != nil){
          475                 fsdestroyfid(f);
          476                 sendp(cfidr, 0);
          477         }
          478 }
          479 
          480 static void
          481 fsproc(void *v)
          482 {
          483         USED(v);
          484 
          485         threadcreate(fsreqthread, nil, STACK);
          486         threadcreate(fsclunkthread, nil, STACK);
          487         threadexits(nil);
          488 }
          489 
          490 static void
          491 fsattach(Req *r)
          492 {
          493         r->fid->qid = mkqid(QTDIR, qtop);
          494         r->ofcall.qid = r->fid->qid;
          495         respond(r, nil);
          496 }
          497 
          498 static void
          499 fssend(Req *r)
          500 {
          501         sendp(creq, r);
          502 }
          503 
          504 static void
          505 fssendclunk(Fid *f)
          506 {
          507         sendp(cfid, f);
          508         recvp(cfidr);
          509 }
          510 
          511 void
          512 fsstart(Srv *s)
          513 {
          514         USED(s);
          515 
          516         if(extrafactotumdir)
          517                 qtop = Qroot;
          518         else
          519                 qtop = Qfactotum;
          520         creq = chancreate(sizeof(Req*), 0);
          521         cfid = chancreate(sizeof(Fid*), 0);
          522         cfidr = chancreate(sizeof(Fid*), 0);
          523         proccreate(fsproc, nil, STACK);
          524 }
          525 
          526 Srv fs;
          527 
          528 void
          529 fsinit0(void)
          530 {
          531         fs.attach = fsattach;
          532         fs.walk1 = fswalk1;
          533         fs.open = fssend;
          534         fs.read = fssend;
          535         fs.write = fssend;
          536         fs.stat = fsstat;
          537         fs.flush = fssend;
          538         fs.destroyfid = fssendclunk;
          539         fs.start = fsstart;
          540 }