tfs.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
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; iqid = *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; id, 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; ifid->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 }